tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

string_utils.cpp (9200B)


      1 //
      2 // Copyright 2015 The ANGLE Project Authors. All rights reserved.
      3 // Use of this source code is governed by a BSD-style license that can be
      4 // found in the LICENSE file.
      5 //
      6 // string_utils:
      7 //   String helper functions.
      8 //
      9 
     10 #include "common/string_utils.h"
     11 
     12 #include <stdlib.h>
     13 #include <string.h>
     14 #include <algorithm>
     15 #include <cctype>
     16 #include <fstream>
     17 #include <sstream>
     18 
     19 #include "common/platform.h"
     20 #include "common/system_utils.h"
     21 
     22 namespace
     23 {
     24 
     25 bool EndsWithSuffix(const char *str,
     26                    const size_t strLen,
     27                    const char *suffix,
     28                    const size_t suffixLen)
     29 {
     30    return suffixLen <= strLen && strncmp(str + strLen - suffixLen, suffix, suffixLen) == 0;
     31 }
     32 
     33 }  // anonymous namespace
     34 
     35 namespace angle
     36 {
     37 
     38 const char kWhitespaceASCII[] = " \f\n\r\t\v";
     39 
     40 std::vector<std::string> SplitString(const std::string &input,
     41                                     const std::string &delimiters,
     42                                     WhitespaceHandling whitespace,
     43                                     SplitResult resultType)
     44 {
     45    std::vector<std::string> result;
     46    if (input.empty())
     47    {
     48        return result;
     49    }
     50 
     51    std::string::size_type start = 0;
     52    while (start != std::string::npos)
     53    {
     54        auto end = input.find_first_of(delimiters, start);
     55 
     56        std::string piece;
     57        if (end == std::string::npos)
     58        {
     59            piece = input.substr(start);
     60            start = std::string::npos;
     61        }
     62        else
     63        {
     64            piece = input.substr(start, end - start);
     65            start = end + 1;
     66        }
     67 
     68        if (whitespace == TRIM_WHITESPACE)
     69        {
     70            piece = TrimString(piece, kWhitespaceASCII);
     71        }
     72 
     73        if (resultType == SPLIT_WANT_ALL || !piece.empty())
     74        {
     75            result.push_back(std::move(piece));
     76        }
     77    }
     78 
     79    return result;
     80 }
     81 
     82 void SplitStringAlongWhitespace(const std::string &input, std::vector<std::string> *tokensOut)
     83 {
     84 
     85    std::istringstream stream(input);
     86    std::string line;
     87 
     88    while (std::getline(stream, line))
     89    {
     90        size_t prev = 0, pos;
     91        while ((pos = line.find_first_of(kWhitespaceASCII, prev)) != std::string::npos)
     92        {
     93            if (pos > prev)
     94                tokensOut->push_back(line.substr(prev, pos - prev));
     95            prev = pos + 1;
     96        }
     97        if (prev < line.length())
     98            tokensOut->push_back(line.substr(prev, std::string::npos));
     99    }
    100 }
    101 
    102 std::string TrimString(const std::string &input, const std::string &trimChars)
    103 {
    104    auto begin = input.find_first_not_of(trimChars);
    105    if (begin == std::string::npos)
    106    {
    107        return "";
    108    }
    109 
    110    std::string::size_type end = input.find_last_not_of(trimChars);
    111    if (end == std::string::npos)
    112    {
    113        return input.substr(begin);
    114    }
    115 
    116    return input.substr(begin, end - begin + 1);
    117 }
    118 
    119 std::string GetPrefix(const std::string &input, size_t offset, const char *delimiter)
    120 {
    121    size_t match = input.find(delimiter, offset);
    122    if (match == std::string::npos)
    123    {
    124        return input.substr(offset);
    125    }
    126    return input.substr(offset, match - offset);
    127 }
    128 
    129 std::string GetPrefix(const std::string &input, size_t offset, char delimiter)
    130 {
    131    size_t match = input.find(delimiter, offset);
    132    if (match == std::string::npos)
    133    {
    134        return input.substr(offset);
    135    }
    136    return input.substr(offset, match - offset);
    137 }
    138 
    139 bool HexStringToUInt(const std::string &input, unsigned int *uintOut)
    140 {
    141    unsigned int offset = 0;
    142 
    143    if (input.size() >= 2 && input[0] == '0' && input[1] == 'x')
    144    {
    145        offset = 2u;
    146    }
    147 
    148    // Simple validity check
    149    if (input.find_first_not_of("0123456789ABCDEFabcdef", offset) != std::string::npos)
    150    {
    151        return false;
    152    }
    153 
    154    std::stringstream inStream(input);
    155    inStream >> std::hex >> *uintOut;
    156    return !inStream.fail();
    157 }
    158 
    159 bool ReadFileToString(const std::string &path, std::string *stringOut)
    160 {
    161    std::ifstream inFile(path.c_str());
    162    if (inFile.fail())
    163    {
    164        return false;
    165    }
    166 
    167    inFile.seekg(0, std::ios::end);
    168    stringOut->reserve(static_cast<std::string::size_type>(inFile.tellg()));
    169    inFile.seekg(0, std::ios::beg);
    170 
    171    stringOut->assign(std::istreambuf_iterator<char>(inFile), std::istreambuf_iterator<char>());
    172    return !inFile.fail();
    173 }
    174 
    175 bool BeginsWith(const std::string &str, const std::string &prefix)
    176 {
    177    return strncmp(str.c_str(), prefix.c_str(), prefix.length()) == 0;
    178 }
    179 
    180 bool BeginsWith(const std::string &str, const char *prefix)
    181 {
    182    return strncmp(str.c_str(), prefix, strlen(prefix)) == 0;
    183 }
    184 
    185 bool BeginsWith(const char *str, const char *prefix)
    186 {
    187    return strncmp(str, prefix, strlen(prefix)) == 0;
    188 }
    189 
    190 bool BeginsWith(const std::string &str, const std::string &prefix, const size_t prefixLength)
    191 {
    192    return strncmp(str.c_str(), prefix.c_str(), prefixLength) == 0;
    193 }
    194 
    195 bool EndsWith(const std::string &str, const std::string &suffix)
    196 {
    197    return EndsWithSuffix(str.c_str(), str.length(), suffix.c_str(), suffix.length());
    198 }
    199 
    200 bool EndsWith(const std::string &str, const char *suffix)
    201 {
    202    return EndsWithSuffix(str.c_str(), str.length(), suffix, strlen(suffix));
    203 }
    204 
    205 bool EndsWith(const char *str, const char *suffix)
    206 {
    207    return EndsWithSuffix(str, strlen(str), suffix, strlen(suffix));
    208 }
    209 
    210 bool ContainsToken(const std::string &tokenStr, char delimiter, const std::string &token)
    211 {
    212    if (token.empty())
    213    {
    214        return false;
    215    }
    216    // Compare token with all sub-strings terminated by delimiter or end of string
    217    std::string::size_type start = 0u;
    218    do
    219    {
    220        std::string::size_type end = tokenStr.find(delimiter, start);
    221        if (end == std::string::npos)
    222        {
    223            end = tokenStr.length();
    224        }
    225        const std::string::size_type length = end - start;
    226        if (length == token.length() && tokenStr.compare(start, length, token) == 0)
    227        {
    228            return true;
    229        }
    230        start = end + 1u;
    231    } while (start < tokenStr.size());
    232    return false;
    233 }
    234 
    235 void ToLower(std::string *str)
    236 {
    237    for (char &ch : *str)
    238    {
    239        ch = static_cast<char>(::tolower(ch));
    240    }
    241 }
    242 
    243 void ToUpper(std::string *str)
    244 {
    245    for (char &ch : *str)
    246    {
    247        ch = static_cast<char>(::toupper(ch));
    248    }
    249 }
    250 
    251 bool ReplaceSubstring(std::string *str,
    252                      const std::string &substring,
    253                      const std::string &replacement)
    254 {
    255    size_t replacePos = str->find(substring);
    256    if (replacePos == std::string::npos)
    257    {
    258        return false;
    259    }
    260    str->replace(replacePos, substring.size(), replacement);
    261    return true;
    262 }
    263 
    264 int ReplaceAllSubstrings(std::string *str,
    265                         const std::string &substring,
    266                         const std::string &replacement)
    267 {
    268    int count = 0;
    269    while (ReplaceSubstring(str, substring, replacement))
    270    {
    271        count++;
    272    }
    273    return count;
    274 }
    275 
    276 std::string ToCamelCase(const std::string &str)
    277 {
    278    std::string result;
    279 
    280    bool lastWasUnderscore = false;
    281    for (char c : str)
    282    {
    283        if (c == '_')
    284        {
    285            lastWasUnderscore = true;
    286            continue;
    287        }
    288 
    289        if (lastWasUnderscore)
    290        {
    291            c                 = static_cast<char>(std::toupper(c));
    292            lastWasUnderscore = false;
    293        }
    294        result += c;
    295    }
    296 
    297    return result;
    298 }
    299 
    300 std::vector<std::string> GetStringsFromEnvironmentVarOrAndroidProperty(const char *varName,
    301                                                                       const char *propertyName,
    302                                                                       const char *separator)
    303 {
    304    std::string environment = GetEnvironmentVarOrAndroidProperty(varName, propertyName);
    305    return SplitString(environment, separator, TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
    306 }
    307 
    308 std::vector<std::string> GetCachedStringsFromEnvironmentVarOrAndroidProperty(
    309    const char *varName,
    310    const char *propertyName,
    311    const char *separator)
    312 {
    313    std::string environment = GetEnvironmentVarOrAndroidProperty(varName, propertyName);
    314    return SplitString(environment, separator, TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
    315 }
    316 
    317 // glob can have * as wildcard
    318 bool NamesMatchWithWildcard(const char *glob, const char *name)
    319 {
    320    // Find the first * in glob.
    321    const char *firstWildcard = strchr(glob, '*');
    322 
    323    // If there are no wildcards, match the strings precisely.
    324    if (firstWildcard == nullptr)
    325    {
    326        return strcmp(glob, name) == 0;
    327    }
    328 
    329    // Otherwise, match up to the wildcard first.
    330    size_t preWildcardLen = firstWildcard - glob;
    331    if (strncmp(glob, name, preWildcardLen) != 0)
    332    {
    333        return false;
    334    }
    335 
    336    const char *postWildcardRef = glob + preWildcardLen + 1;
    337 
    338    // As a small optimization, if the wildcard is the last character in glob, accept the match
    339    // already.
    340    if (postWildcardRef[0] == '\0')
    341    {
    342        return true;
    343    }
    344 
    345    // Try to match the wildcard with a number of characters.
    346    for (size_t matchSize = 0; name[matchSize] != '\0'; ++matchSize)
    347    {
    348        if (NamesMatchWithWildcard(postWildcardRef, name + matchSize))
    349        {
    350            return true;
    351        }
    352    }
    353 
    354    return false;
    355 }
    356 
    357 }  // namespace angle