LCOV - code coverage report
Current view: top level - port - cplstring.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 147 156 94.2 %
Date: 2024-04-29 01:40:10 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             :  * 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_port.h"
      31             : #include "cpl_string.h"
      32             : 
      33             : #include <cctype>
      34             : #include <cstdarg>
      35             : #include <cstddef>
      36             : #include <cstring>
      37             : #include <string>
      38             : 
      39             : #include "cpl_config.h"
      40             : #include "cpl_conv.h"
      41             : 
      42             : #if !defined(va_copy) && defined(__va_copy)
      43             : #define va_copy __va_copy
      44             : #endif
      45             : 
      46             : /*
      47             :  * The CPLString class is derived from std::string, so the vast majority
      48             :  * of the implementation comes from that.  This module is just the extensions
      49             :  * we add.
      50             :  */
      51             : 
      52             : /************************************************************************/
      53             : /*                               Printf()                               */
      54             : /************************************************************************/
      55             : 
      56             : /** Assign the content of the string using sprintf() */
      57      377327 : CPLString &CPLString::Printf(CPL_FORMAT_STRING(const char *pszFormat), ...)
      58             : 
      59             : {
      60             :     va_list args;
      61             : 
      62      377327 :     va_start(args, pszFormat);
      63      377327 :     vPrintf(pszFormat, args);
      64      377291 :     va_end(args);
      65             : 
      66      377291 :     return *this;
      67             : }
      68             : 
      69             : /************************************************************************/
      70             : /*                              vPrintf()                               */
      71             : /************************************************************************/
      72             : 
      73             : /** Assign the content of the string using vsprintf() */
      74      499650 : CPLString &CPLString::vPrintf(CPL_FORMAT_STRING(const char *pszFormat),
      75             :                               va_list args)
      76             : 
      77             : {
      78             :     /* -------------------------------------------------------------------- */
      79             :     /*      This implementation for platforms without vsnprintf() will      */
      80             :     /*      just plain fail if the formatted contents are too large.        */
      81             :     /* -------------------------------------------------------------------- */
      82             : 
      83             : #if !defined(HAVE_VSNPRINTF)
      84             :     char *pszBuffer = static_cast<char *>(CPLMalloc(30000));
      85             :     if (CPLvsnprintf(pszBuffer, 30000, pszFormat, args) > 29998)
      86             :     {
      87             :         CPLError(CE_Fatal, CPLE_AppDefined,
      88             :                  "CPLString::vPrintf() ... buffer overrun.");
      89             :     }
      90             :     *this = pszBuffer;
      91             :     CPLFree(pszBuffer);
      92             : 
      93             : /* -------------------------------------------------------------------- */
      94             : /*      This should grow a big enough buffer to hold any formatted      */
      95             : /*      result.                                                         */
      96             : /* -------------------------------------------------------------------- */
      97             : #else
      98             :     va_list wrk_args;
      99             : 
     100             : #ifdef va_copy
     101      499650 :     va_copy(wrk_args, args);
     102             : #else
     103             :     wrk_args = args;
     104             : #endif
     105             : 
     106      499650 :     char szModestBuffer[500] = {};
     107      499650 :     szModestBuffer[0] = '\0';
     108      499650 :     int nPR = CPLvsnprintf(szModestBuffer, sizeof(szModestBuffer), pszFormat,
     109             :                            wrk_args);
     110      499623 :     if (nPR == -1 || nPR >= static_cast<int>(sizeof(szModestBuffer)) - 1)
     111             :     {
     112        1269 :         int nWorkBufferSize = 2000;
     113        1269 :         char *pszWorkBuffer = static_cast<char *>(CPLMalloc(nWorkBufferSize));
     114             : 
     115             : #ifdef va_copy
     116        1285 :         va_end(wrk_args);
     117        1285 :         va_copy(wrk_args, args);
     118             : #else
     119             :         wrk_args = args;
     120             : #endif
     121        1472 :         while ((nPR = CPLvsnprintf(pszWorkBuffer, nWorkBufferSize, pszFormat,
     122        1472 :                                    wrk_args)) >= nWorkBufferSize - 1 ||
     123             :                nPR == -1)
     124             :         {
     125         187 :             nWorkBufferSize *= 4;
     126             :             pszWorkBuffer =
     127         187 :                 static_cast<char *>(CPLRealloc(pszWorkBuffer, nWorkBufferSize));
     128             : #ifdef va_copy
     129         187 :             va_end(wrk_args);
     130         187 :             va_copy(wrk_args, args);
     131             : #else
     132             :             wrk_args = args;
     133             : #endif
     134             :         }
     135        1285 :         *this = pszWorkBuffer;
     136        1285 :         CPLFree(pszWorkBuffer);
     137             :     }
     138             :     else
     139             :     {
     140      498354 :         *this = szModestBuffer;
     141             :     }
     142             : #ifdef va_copy
     143      499633 :     va_end(wrk_args);
     144             : #endif
     145             : 
     146             : #endif /* !defined(HAVE_VSNPRINTF) */
     147             : 
     148      499633 :     return *this;
     149             : }
     150             : 
     151             : /************************************************************************/
     152             : /*                              FormatC()                               */
     153             : /************************************************************************/
     154             : 
     155             : /**
     156             :  * Format double in C locale.
     157             :  *
     158             :  * The passed value is formatted using the C locale (period as decimal
     159             :  * separator) and appended to the target CPLString.
     160             :  *
     161             :  * @param dfValue the value to format.
     162             :  * @param pszFormat the sprintf() style format to use or omit for default.
     163             :  * Note that this format string should only include one substitution argument
     164             :  * and it must be for a double (%f or %g).
     165             :  *
     166             :  * @return a reference to the CPLString.
     167             :  */
     168             : 
     169        4026 : CPLString &CPLString::FormatC(double dfValue, const char *pszFormat)
     170             : 
     171             : {
     172        4026 :     if (pszFormat == nullptr)
     173        3412 :         pszFormat = "%g";
     174             : 
     175             :     // presumably long enough for any number.
     176        4026 :     const size_t buf_size = 512;
     177        4026 :     char szWork[buf_size] = {};
     178             : 
     179        4026 :     CPLsnprintf(szWork, buf_size, pszFormat, dfValue);
     180             : 
     181        4026 :     *this += szWork;
     182             : 
     183        4026 :     return *this;
     184             : }
     185             : 
     186             : /************************************************************************/
     187             : /*                                Trim()                                */
     188             : /************************************************************************/
     189             : 
     190             : /**
     191             :  * Trim white space.
     192             :  *
     193             :  * Trims white space off the let and right of the string.  White space
     194             :  * is any of a space, a tab, a newline ('\\n') or a carriage control ('\\r').
     195             :  *
     196             :  * @return a reference to the CPLString.
     197             :  */
     198             : 
     199      244870 : CPLString &CPLString::Trim()
     200             : 
     201             : {
     202      244870 :     constexpr char szWhitespace[] = " \t\r\n";
     203             : 
     204      244870 :     const size_t iLeft = find_first_not_of(szWhitespace);
     205      244870 :     const size_t iRight = find_last_not_of(szWhitespace);
     206             : 
     207      244870 :     if (iLeft == std::string::npos)
     208             :     {
     209       12642 :         erase();
     210       12642 :         return *this;
     211             :     }
     212             : 
     213      232228 :     assign(substr(iLeft, iRight - iLeft + 1));
     214             : 
     215      232228 :     return *this;
     216             : }
     217             : 
     218             : /************************************************************************/
     219             : /*                               Recode()                               */
     220             : /************************************************************************/
     221             : 
     222             : /** Recode the string */
     223        3229 : CPLString &CPLString::Recode(const char *pszSrcEncoding,
     224             :                              const char *pszDstEncoding)
     225             : 
     226             : {
     227        3229 :     if (pszSrcEncoding == nullptr)
     228           0 :         pszSrcEncoding = CPL_ENC_UTF8;
     229        3229 :     if (pszDstEncoding == nullptr)
     230           0 :         pszDstEncoding = CPL_ENC_UTF8;
     231             : 
     232        3229 :     if (strcmp(pszSrcEncoding, pszDstEncoding) == 0)
     233           0 :         return *this;
     234             : 
     235        3229 :     char *pszRecoded = CPLRecode(c_str(), pszSrcEncoding, pszDstEncoding);
     236             : 
     237        3229 :     if (pszRecoded == nullptr)
     238           0 :         return *this;
     239             : 
     240        3229 :     assign(pszRecoded);
     241        3229 :     CPLFree(pszRecoded);
     242             : 
     243        3229 :     return *this;
     244             : }
     245             : 
     246             : /************************************************************************/
     247             : /*                               ifind()                                */
     248             : /************************************************************************/
     249             : 
     250             : /**
     251             :  * Case insensitive find() alternative.
     252             :  *
     253             :  * @param str substring to find.
     254             :  * @param pos offset in the string at which the search starts.
     255             :  * @return the position of substring in the string or std::string::npos if not
     256             :  * found.
     257             :  * @since GDAL 1.9.0
     258             :  */
     259             : 
     260        7483 : size_t CPLString::ifind(const std::string &str, size_t pos) const
     261             : 
     262             : {
     263        7483 :     return ifind(str.c_str(), pos);
     264             : }
     265             : 
     266             : /**
     267             :  * Case insensitive find() alternative.
     268             :  *
     269             :  * @param s substring to find.
     270             :  * @param nPos offset in the string at which the search starts.
     271             :  * @return the position of the substring in the string or std::string::npos if
     272             :  * not found.
     273             :  * @since GDAL 1.9.0
     274             :  */
     275             : 
     276      202682 : size_t CPLString::ifind(const char *s, size_t nPos) const
     277             : 
     278             : {
     279      202682 :     const char *pszHaystack = c_str();
     280             :     const char chFirst =
     281      202667 :         static_cast<char>(CPLTolower(static_cast<unsigned char>(s[0])));
     282      202674 :     const size_t nTargetLen = strlen(s);
     283             : 
     284      202674 :     if (nPos > size())
     285           0 :         nPos = size();
     286             : 
     287      202671 :     pszHaystack += nPos;
     288             : 
     289     7293080 :     while (*pszHaystack != '\0')
     290             :     {
     291     7099570 :         if (chFirst == CPLTolower(static_cast<unsigned char>(*pszHaystack)))
     292             :         {
     293      313963 :             if (EQUALN(pszHaystack, s, nTargetLen))
     294        9157 :                 return nPos;
     295             :         }
     296             : 
     297     7090410 :         nPos++;
     298     7090410 :         pszHaystack++;
     299             :     }
     300             : 
     301      193509 :     return std::string::npos;
     302             : }
     303             : 
     304             : /************************************************************************/
     305             : /*                              toupper()                               */
     306             : /************************************************************************/
     307             : 
     308             : /**
     309             :  * Convert to upper case in place.
     310             :  */
     311             : 
     312     2557470 : CPLString &CPLString::toupper()
     313             : 
     314             : {
     315    22982200 :     for (size_t i = 0; i < size(); i++)
     316    20424700 :         (*this)[i] = static_cast<char>(CPLToupper((*this)[i]));
     317             : 
     318     2557470 :     return *this;
     319             : }
     320             : 
     321             : /************************************************************************/
     322             : /*                              tolower()                               */
     323             : /************************************************************************/
     324             : 
     325             : /**
     326             :  * Convert to lower case in place.
     327             :  */
     328             : 
     329       80800 : CPLString &CPLString::tolower()
     330             : 
     331             : {
     332     1419060 :     for (size_t i = 0; i < size(); i++)
     333     1338260 :         (*this)[i] = static_cast<char>(CPLTolower((*this)[i]));
     334             : 
     335       80800 :     return *this;
     336             : }
     337             : 
     338             : /************************************************************************/
     339             : /*                             replaceAll()                             */
     340             : /************************************************************************/
     341             : 
     342             : /**
     343             :  * Replace all occurrences of osBefore with osAfter.
     344             :  */
     345      790557 : CPLString &CPLString::replaceAll(const std::string &osBefore,
     346             :                                  const std::string &osAfter)
     347             : {
     348      790557 :     const size_t nBeforeSize = osBefore.size();
     349      790553 :     const size_t nAfterSize = osAfter.size();
     350      790549 :     if (nBeforeSize)
     351             :     {
     352      790545 :         size_t nStartPos = 0;
     353      794541 :         while ((nStartPos = find(osBefore, nStartPos)) != std::string::npos)
     354             :         {
     355        4006 :             replace(nStartPos, nBeforeSize, osAfter);
     356        3996 :             nStartPos += nAfterSize;
     357             :         }
     358             :     }
     359      790543 :     return *this;
     360             : }
     361             : 
     362             : /**
     363             :  * Replace all occurrences of chBefore with osAfter.
     364             :  */
     365        4536 : CPLString &CPLString::replaceAll(char chBefore, const std::string &osAfter)
     366             : {
     367        4536 :     return replaceAll(std::string(&chBefore, 1), osAfter);
     368             : }
     369             : 
     370             : /**
     371             :  * Replace all occurrences of osBefore with chAfter.
     372             :  */
     373      775836 : CPLString &CPLString::replaceAll(const std::string &osBefore, char chAfter)
     374             : {
     375      775836 :     return replaceAll(osBefore, std::string(&chAfter, 1));
     376             : }
     377             : 
     378             : /**
     379             :  * Replace all occurrences of chBefore with chAfter.
     380             :  */
     381        3411 : CPLString &CPLString::replaceAll(char chBefore, char chAfter)
     382             : {
     383        3411 :     return replaceAll(std::string(&chBefore, 1), std::string(&chAfter, 1));
     384             : }
     385             : 
     386             : /************************************************************************/
     387             : /*                             endsWith()                              */
     388             : /************************************************************************/
     389             : 
     390             : /**
     391             :  * Returns whether the string ends with another string
     392             :  * @param osStr other string.
     393             :  * @return true if the string ends with osStr.
     394             :  */
     395       18748 : bool CPLString::endsWith(const std::string &osStr) const
     396             : {
     397       18748 :     if (size() < osStr.size())
     398         107 :         return false;
     399       18641 :     return substr(size() - osStr.size()) == osStr;
     400             : }
     401             : 
     402             : /************************************************************************/
     403             : /*                         CPLURLGetValue()                             */
     404             : /************************************************************************/
     405             : 
     406             : /**
     407             :  * Return the value matching a key from a key=value pair in a URL.
     408             :  *
     409             :  * @param pszURL the URL.
     410             :  * @param pszKey the key to find.
     411             :  * @return the value of empty string if not found.
     412             :  * @since GDAL 1.9.0
     413             :  */
     414        1611 : CPLString CPLURLGetValue(const char *pszURL, const char *pszKey)
     415             : {
     416        3222 :     CPLString osKey(pszKey);
     417        1611 :     osKey += "=";
     418        1611 :     size_t nKeyPos = CPLString(pszURL).ifind(osKey);
     419        1611 :     if (nKeyPos != std::string::npos && nKeyPos > 0 &&
     420         327 :         (pszURL[nKeyPos - 1] == '?' || pszURL[nKeyPos - 1] == '&'))
     421             :     {
     422         654 :         CPLString osValue(pszURL + nKeyPos + osKey.size());
     423         327 :         const char *pszValue = osValue.c_str();
     424         327 :         const char *pszSep = strchr(pszValue, '&');
     425         327 :         if (pszSep)
     426             :         {
     427          94 :             osValue.resize(pszSep - pszValue);
     428             :         }
     429         327 :         return osValue;
     430             :     }
     431        1284 :     return "";
     432             : }
     433             : 
     434             : /************************************************************************/
     435             : /*                          CPLURLAddKVP()                              */
     436             : /************************************************************************/
     437             : 
     438             : /**
     439             :  * Return a new URL with a new key=value pair.
     440             :  *
     441             :  * @param pszURL the URL.
     442             :  * @param pszKey the key to find.
     443             :  * @param pszValue the value of the key (may be NULL to unset an existing KVP).
     444             :  * @return the modified URL.
     445             :  * @since GDAL 1.9.0
     446             :  */
     447        5045 : CPLString CPLURLAddKVP(const char *pszURL, const char *pszKey,
     448             :                        const char *pszValue)
     449             : {
     450        5045 :     const CPLString osURL(strchr(pszURL, '?') == nullptr
     451       14491 :                               ? CPLString(pszURL).append("?")
     452       10090 :                               : pszURL);
     453             : 
     454       10090 :     CPLString osKey(pszKey);
     455        5045 :     osKey += "=";
     456        5045 :     size_t nKeyPos = osURL.ifind(osKey);
     457        5124 :     if (nKeyPos != std::string::npos && nKeyPos > 0 &&
     458          79 :         (osURL[nKeyPos - 1] == '?' || osURL[nKeyPos - 1] == '&'))
     459             :     {
     460         150 :         CPLString osNewURL(osURL);
     461          75 :         osNewURL.resize(nKeyPos);
     462          75 :         if (pszValue)
     463             :         {
     464          44 :             osNewURL += osKey;
     465          44 :             osNewURL += pszValue;
     466             :         }
     467          75 :         const char *pszNext = strchr(osURL.c_str() + nKeyPos, '&');
     468          75 :         if (pszNext)
     469             :         {
     470          72 :             if (osNewURL.back() == '&' || osNewURL.back() == '?')
     471          30 :                 osNewURL += pszNext + 1;
     472             :             else
     473          42 :                 osNewURL += pszNext;
     474             :         }
     475          75 :         return osNewURL;
     476             :     }
     477             :     else
     478             :     {
     479        9940 :         CPLString osNewURL(osURL);
     480        4970 :         if (pszValue)
     481             :         {
     482        3246 :             if (osNewURL.back() != '&' && osNewURL.back() != '?')
     483        2374 :                 osNewURL += '&';
     484        3246 :             osNewURL += osKey;
     485        3246 :             osNewURL += pszValue;
     486             :         }
     487        4970 :         return osNewURL;
     488             :     }
     489             : }
     490             : 
     491             : /************************************************************************/
     492             : /*                            CPLOPrintf()                              */
     493             : /************************************************************************/
     494             : 
     495             : /** Return a CPLString with the content of sprintf() */
     496       13153 : CPLString CPLOPrintf(CPL_FORMAT_STRING(const char *pszFormat), ...)
     497             : 
     498             : {
     499             :     va_list args;
     500       13153 :     va_start(args, pszFormat);
     501             : 
     502       13153 :     CPLString osTarget;
     503       13153 :     osTarget.vPrintf(pszFormat, args);
     504             : 
     505       13153 :     va_end(args);
     506             : 
     507       26306 :     return osTarget;
     508             : }
     509             : 
     510             : /************************************************************************/
     511             : /*                            CPLOvPrintf()                             */
     512             : /************************************************************************/
     513             : 
     514             : /** Return a CPLString with the content of vsprintf() */
     515           0 : CPLString CPLOvPrintf(CPL_FORMAT_STRING(const char *pszFormat), va_list args)
     516             : 
     517             : {
     518           0 :     CPLString osTarget;
     519           0 :     osTarget.vPrintf(pszFormat, args);
     520           0 :     return osTarget;
     521             : }
     522             : 
     523             : /************************************************************************/
     524             : /*                            CPLQuotedSQLIdentifer()                   */
     525             : /************************************************************************/
     526             : 
     527             : /** Return a CPLString of the SQL quoted identifier */
     528           6 : CPLString CPLQuotedSQLIdentifier(const char *pszIdent)
     529             : 
     530             : {
     531           6 :     CPLString osIdent;
     532             : 
     533           6 :     if (pszIdent)
     534             :     {
     535           6 :         char *pszQuotedIdent = CPLEscapeString(pszIdent, -1, CPLES_SQLI);
     536           6 :         osIdent.Printf("\"%s\"", pszQuotedIdent);
     537           6 :         CPLFree(pszQuotedIdent);
     538             :     }
     539             : 
     540           6 :     return osIdent;
     541             : }

Generated by: LCOV version 1.14