LCOV - code coverage report
Current view: top level - src/utils/common - StringUtils.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 77.4 % 319 247
Test Date: 2026-04-16 16:39:47 Functions: 76.2 % 42 32

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2001-2026 German Aerospace Center (DLR) and others.
       4              : // This program and the accompanying materials are made available under the
       5              : // terms of the Eclipse Public License 2.0 which is available at
       6              : // https://www.eclipse.org/legal/epl-2.0/
       7              : // This Source Code may also be made available under the following Secondary
       8              : // Licenses when the conditions for such availability set forth in the Eclipse
       9              : // Public License 2.0 are satisfied: GNU General Public License, version 2
      10              : // or later which is available at
      11              : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
      12              : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
      13              : /****************************************************************************/
      14              : /// @file    StringUtils.cpp
      15              : /// @author  Daniel Krajzewicz
      16              : /// @author  Laura Bieker
      17              : /// @author  Michael Behrisch
      18              : /// @author  Robert Hilbrich
      19              : /// @date    unknown
      20              : ///
      21              : // Some static methods for string processing
      22              : /****************************************************************************/
      23              : #include <config.h>
      24              : 
      25              : #include <string>
      26              : #include <iostream>
      27              : #include <cstdio>
      28              : #include <cstring>
      29              : #include <regex>
      30              : #ifdef WIN32
      31              : #define NOMINMAX
      32              : #include <windows.h>
      33              : #undef NOMINMAX
      34              : #else
      35              : #include <unistd.h>
      36              : #endif
      37              : #include <xercesc/util/TransService.hpp>
      38              : #include <xercesc/util/TranscodingException.hpp>
      39              : #include <utils/common/UtilExceptions.h>
      40              : #include <utils/common/ToString.h>
      41              : #include <utils/common/StringTokenizer.h>
      42              : #include "StringUtils.h"
      43              : 
      44              : #define KM_PER_MILE 1.609344
      45              : 
      46              : 
      47              : // ===========================================================================
      48              : // static member definitions
      49              : // ===========================================================================
      50              : std::string StringUtils::emptyString;
      51              : XERCES_CPP_NAMESPACE::XMLLCPTranscoder* StringUtils::myLCPTranscoder = nullptr;
      52              : 
      53              : 
      54              : // ===========================================================================
      55              : // method definitions
      56              : // ===========================================================================
      57              : std::string
      58      1578752 : StringUtils::prune(const std::string& str) {
      59              :     const std::string::size_type endpos = str.find_last_not_of(" \t\n\r");
      60      1578752 :     if (std::string::npos != endpos) {
      61      1575615 :         const int startpos = (int)str.find_first_not_of(" \t\n\r");
      62      1575615 :         return str.substr(startpos, endpos - startpos + 1);
      63              :     }
      64         3137 :     return "";
      65              : }
      66              : 
      67              : 
      68              : std::string
      69        59025 : StringUtils::pruneZeros(const std::string& str, int max) {
      70              :     const std::string::size_type endpos = str.find_last_not_of("0");
      71        59025 :     if (endpos != std::string::npos && str.back() == '0') {
      72        39919 :         std::string res = str.substr(0, MAX2((int)str.size() - max, (int)endpos + 1));
      73        39919 :         return res;
      74              :     }
      75              :     return str;
      76              : }
      77              : 
      78              : std::string
      79      8147667 : StringUtils::to_lower_case(const std::string& str) {
      80              :     std::string s = str;
      81              :     std::transform(s.begin(), s.end(), s.begin(), [](char c) {
      82     56339478 :         return (char)::tolower(c);
      83              :     });
      84      8147667 :     return s;
      85              : }
      86              : 
      87              : 
      88              : std::string
      89            0 : StringUtils::to_upper_case(const std::string& str) {
      90              :     std::string s = str;
      91              :     std::transform(s.begin(), s.end(), s.begin(), [](char c) {
      92            0 :         return (char)::toupper(c);
      93              :     });
      94            0 :     return s;
      95              : }
      96              : 
      97              : 
      98              : std::string
      99         1956 : StringUtils::latin1_to_utf8(std::string str) {
     100              :     // inspired by http://stackoverflow.com/questions/4059775/convert-iso-8859-1-strings-to-utf-8-in-c-c
     101              :     std::string result;
     102         8781 :     for (const auto& c : str) {
     103         6825 :         const unsigned char uc = (unsigned char)c;
     104         6825 :         if (uc < 128) {
     105              :             result += uc;
     106              :         } else {
     107          100 :             result += (char)(0xc2 + (uc > 0xbf));
     108          100 :             result += (char)((uc & 0x3f) + 0x80);
     109              :         }
     110              :     }
     111         1956 :     return result;
     112              : }
     113              : 
     114              : 
     115              : std::string
     116      1270718 : StringUtils::convertUmlaute(std::string str) {
     117      3812154 :     str = replace(str, "\xE4", "ae");
     118      3812154 :     str = replace(str, "\xC4", "Ae");
     119      3812154 :     str = replace(str, "\xF6", "oe");
     120      3812154 :     str = replace(str, "\xD6", "Oe");
     121      3812154 :     str = replace(str, "\xFC", "ue");
     122      3812154 :     str = replace(str, "\xDC", "Ue");
     123      3812154 :     str = replace(str, "\xDF", "ss");
     124      3812154 :     str = replace(str, "\xC9", "E");
     125      3812154 :     str = replace(str, "\xE9", "e");
     126      3812154 :     str = replace(str, "\xC8", "E");
     127      3812154 :     str = replace(str, "\xE8", "e");
     128      1270718 :     return str;
     129              : }
     130              : 
     131              : 
     132              : std::string
     133     71965161 : StringUtils::replace(std::string str, const std::string& what, const std::string& by) {
     134              :     std::string::size_type idx = str.find(what);
     135     71965161 :     const int what_len = (int)what.length();
     136     71965161 :     if (what_len > 0) {
     137     71965160 :         const int by_len = (int)by.length();
     138     71969032 :         while (idx != std::string::npos) {
     139         3872 :             str = str.replace(idx, what_len, by);
     140         3872 :             idx = str.find(what, idx + by_len);
     141              :         }
     142              :     }
     143     71965161 :     return str;
     144              : }
     145              : 
     146              : 
     147              : std::string
     148      1304550 : StringUtils::substituteEnvironment(const std::string& str, const std::chrono::time_point<std::chrono::system_clock>* const timeRef) {
     149              :     std::string s = str;
     150      1304550 :     if (timeRef != nullptr) {
     151              :         const std::string::size_type localTimeIndex = str.find("${LOCALTIME}");
     152              :         const std::string::size_type utcIndex = str.find("${UTC}");
     153              :         const bool isUTC = utcIndex != std::string::npos;
     154      1304544 :         if (localTimeIndex != std::string::npos || isUTC) {
     155            6 :             const time_t rawtime = std::chrono::system_clock::to_time_t(*timeRef);
     156              :             char buffer [80];
     157            6 :             struct tm* timeinfo = isUTC ? gmtime(&rawtime) : localtime(&rawtime);
     158            6 :             strftime(buffer, 80, "%Y-%m-%d-%H-%M-%S.", timeinfo);
     159              :             auto seconds = std::chrono::time_point_cast<std::chrono::seconds>(*timeRef);
     160              :             auto microseconds = std::chrono::duration_cast<std::chrono::microseconds>(*timeRef - seconds);
     161            6 :             const std::string micro = buffer + toString(microseconds.count());
     162            6 :             if (isUTC) {
     163              :                 s.replace(utcIndex, 6, micro);
     164              :             } else {
     165              :                 s.replace(localTimeIndex, 12, micro);
     166              :             }
     167              :         }
     168              :     }
     169              :     const std::string::size_type pidIndex = str.find("${PID}");
     170      1304550 :     if (pidIndex != std::string::npos) {
     171              : #ifdef WIN32
     172              :         s.replace(pidIndex, 6, toString(::GetCurrentProcessId()));
     173              : #else
     174            6 :         s.replace(pidIndex, 6, toString(::getpid()));
     175              : #endif
     176              :     }
     177      1304550 :     if (std::getenv("SUMO_LOGO") == nullptr) {
     178      3913650 :         s = replace(s, "${SUMO_LOGO}", "${SUMO_HOME}/data/logo/sumo-128x138.png");
     179              :     }
     180              :     const std::string::size_type tildeIndex = str.find("~");
     181      1304550 :     if (tildeIndex == 0) {
     182            3 :         s.replace(0, 1, "${HOME}");
     183              :     }
     184      3913650 :     s = replace(s, ",~", ",${HOME}");
     185              : #ifdef WIN32
     186              :     if (std::getenv("HOME") == nullptr) {
     187              :         s = replace(s, "${HOME}", "${USERPROFILE}");
     188              :     }
     189              : #endif
     190              : 
     191              :     // Expression for an environment variables, e.g. ${NAME}
     192              :     // Note: - R"(...)" is a raw string literal syntax to simplify a regex declaration
     193              :     //       - .+? looks for the shortest match (non-greedy)
     194              :     //       - (.+?) defines a "subgroup" which is already stripped of the $ and {, }
     195      1304550 :     std::regex envVarExpr(R"(\$\{(.+?)\})");
     196              : 
     197              :     // Are there any variables in this string?
     198              :     std::smatch match;
     199              :     std::string strIter = s;
     200              : 
     201              :     // Loop over the entire value string and look for variable names
     202      1304616 :     while (std::regex_search(strIter, match, envVarExpr)) {
     203              :         std::string varName = match[1];
     204              : 
     205              :         // Find the variable in the environment and its value
     206              :         std::string varValue;
     207           66 :         if (std::getenv(varName.c_str()) != nullptr) {
     208           65 :             varValue = std::getenv(varName.c_str());
     209              :         }
     210              : 
     211              :         // Replace the variable placeholder with its value in the original string
     212          264 :         s = std::regex_replace(s, std::regex("\\$\\{" + varName + "\\}"), varValue);
     213              : 
     214              :         // Continue the loop with the remainder of the string
     215          132 :         strIter = match.suffix();
     216              :     }
     217      1304550 :     return s;
     218      1304550 : }
     219              : 
     220              : 
     221              : std::string
     222        87059 : StringUtils::isoTimeString(const std::chrono::time_point<std::chrono::system_clock>* const timeRef) {
     223        87059 :     const std::chrono::system_clock::time_point now = timeRef == nullptr ? std::chrono::system_clock::now() : *timeRef;
     224              :     const auto now_seconds = std::chrono::time_point_cast<std::chrono::seconds>(now);
     225        87059 :     const std::time_t now_c = std::chrono::system_clock::to_time_t(now);
     226              :     const auto microseconds = std::chrono::duration_cast<std::chrono::microseconds>(now - now_seconds).count();
     227        87059 :     std::tm local_tm = *std::localtime(&now_c);
     228              : 
     229              :     // Get the time zone offset
     230        87059 :     std::time_t utc_time = std::time(nullptr);
     231        87059 :     std::tm utc_tm = *std::gmtime(&utc_time);
     232        87059 :     const double offset = std::difftime(std::mktime(&local_tm), std::mktime(&utc_tm)) / 3600.0;
     233        87059 :     const int hours_offset = static_cast<int>(offset);
     234        87059 :     const int minutes_offset = static_cast<int>((offset - hours_offset) * 60);
     235              : 
     236              :     // Format the time
     237        87059 :     std::ostringstream oss;
     238              :     char buf[32];
     239        87059 :     std::strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S", &local_tm);
     240              :     oss << buf << "."
     241              :         << std::setw(6) << std::setfill('0') << std::abs(microseconds)
     242              :         << (hours_offset >= 0 ? "+" : "-")
     243        87059 :         << std::setw(2) << std::setfill('0') << std::abs(hours_offset) << ":"
     244       174118 :         << std::setw(2) << std::setfill('0') << std::abs(minutes_offset);
     245        87059 :     return oss.str();
     246        87059 : }
     247              : 
     248              : 
     249              : bool
     250      6621038 : StringUtils::startsWith(const std::string& str, const std::string prefix) {
     251      6621038 :     return str.compare(0, prefix.length(), prefix) == 0;
     252              : }
     253              : 
     254              : 
     255              : bool
     256       224327 : StringUtils::endsWith(const std::string& str, const std::string suffix) {
     257       224327 :     if (str.length() >= suffix.length()) {
     258       224304 :         return str.compare(str.length() - suffix.length(), suffix.length(), suffix) == 0;
     259              :     } else {
     260              :         return false;
     261              :     }
     262              : }
     263              : 
     264              : 
     265              : std::string
     266            0 : StringUtils::padFront(const std::string& str, int length, char padding) {
     267            0 :     return std::string(MAX2(0, length - (int)str.size()), padding) + str;
     268              : }
     269              : 
     270              : 
     271              : std::string
     272      1511320 : StringUtils::escapeXML(const std::string& orig, const bool maskDoubleHyphen) {
     273      4533960 :     std::string result = replace(orig, "&", "&amp;");
     274      4533960 :     result = replace(result, ">", "&gt;");
     275      4533960 :     result = replace(result, "<", "&lt;");
     276      4533960 :     result = replace(result, "\"", "&quot;");
     277      1511320 :     if (maskDoubleHyphen) {
     278      2285205 :         result = replace(result, "--", "&#45;&#45;");
     279              :     }
     280     48362240 :     for (char invalid = '\1'; invalid < ' '; invalid++) {
     281    234254600 :         result = replace(result, std::string(1, invalid).c_str(), "");
     282              :     }
     283      4533960 :     return replace(result, "'", "&apos;");
     284              : }
     285              : 
     286              : 
     287              : std::string
     288            0 : StringUtils::escapeShell(const std::string& orig) {
     289            0 :     std::string result = replace(orig, "\"", "\\\"");
     290            0 :     return result;
     291              : }
     292              : 
     293              : 
     294              : std::string
     295         5121 : StringUtils::urlEncode(const std::string& toEncode, const std::string encodeWhich) {
     296         5121 :     std::ostringstream out;
     297              : 
     298       131266 :     for (int i = 0; i < (int)toEncode.length(); ++i) {
     299       126145 :         const char t = toEncode.at(i);
     300              : 
     301       126145 :         if ((encodeWhich != "" && encodeWhich.find(t) == std::string::npos) ||
     302            1 :                 (encodeWhich == "" &&
     303            0 :                  ((t >= 45 && t <= 57) ||       // hyphen, period, slash, 0-9
     304            0 :                   (t >= 65 && t <= 90) ||        // A-Z
     305              :                   t == 95 ||                     // underscore
     306              :                   (t >= 97 && t <= 122) ||       // a-z
     307              :                   t == 126))                     // tilde
     308              :            ) {
     309       126144 :             out << toEncode.at(i);
     310              :         } else {
     311            2 :             out << charToHex(toEncode.at(i));
     312              :         }
     313              :     }
     314              : 
     315         5121 :     return out.str();
     316         5121 : }
     317              : 
     318              : 
     319              : std::string
     320        92445 : StringUtils::urlDecode(const std::string& toDecode) {
     321        92445 :     std::ostringstream out;
     322              : 
     323      1658666 :     for (int i = 0; i < (int)toDecode.length(); ++i) {
     324      1566223 :         if (toDecode.at(i) == '%') {
     325            2 :             std::string str(toDecode.substr(i + 1, 2));
     326            2 :             out << hexToChar(str);
     327            0 :             i += 2;
     328              :         } else {
     329      1566221 :             out << toDecode.at(i);
     330              :         }
     331              :     }
     332              : 
     333        92443 :     return out.str();
     334        92445 : }
     335              : 
     336              : std::string
     337            1 : StringUtils::charToHex(unsigned char c) {
     338              :     short i = c;
     339              : 
     340            1 :     std::stringstream s;
     341              : 
     342            1 :     s << "%" << std::setw(2) << std::setfill('0') << std::hex << i;
     343              : 
     344            1 :     return s.str();
     345            1 : }
     346              : 
     347              : 
     348              : unsigned char
     349            2 : StringUtils::hexToChar(const std::string& str) {
     350            2 :     short c = 0;
     351            2 :     if (!str.empty()) {
     352            2 :         std::istringstream in(str);
     353            2 :         in >> std::hex >> c;
     354            2 :         if (in.fail()) {
     355            4 :             throw NumberFormatException(str + " could not be interpreted as hex");
     356              :         }
     357            2 :     }
     358            0 :     return static_cast<unsigned char>(c);
     359              : }
     360              : 
     361              : 
     362              : int
     363     18609674 : StringUtils::toInt(const std::string& sData) {
     364     18609674 :     long long int result = toLong(sData);
     365     18592205 :     if (result > std::numeric_limits<int>::max() || result < std::numeric_limits<int>::min()) {
     366            3 :         throw NumberFormatException(toString(result) + " int overflow");
     367              :     }
     368     18592204 :     return (int)result;
     369              : }
     370              : 
     371              : 
     372              : bool
     373            8 : StringUtils::isInt(const std::string& sData) {
     374              :     // first check if can be converted to long int
     375            8 :     if (isLong(sData)) {
     376            0 :         const long long int result = toLong(sData);
     377              :         // now check if the result is in the range of an int
     378            0 :         return ((result <= std::numeric_limits<int>::max()) && (result >= std::numeric_limits<int>::min()));
     379              :     }
     380              :     return false;
     381              : }
     382              : 
     383              : 
     384              : int
     385            0 : StringUtils::toIntSecure(const std::string& sData, int def) {
     386            0 :     if (sData.length() == 0) {
     387              :         return def;
     388              :     }
     389            0 :     return toInt(sData);
     390              : }
     391              : 
     392              : 
     393              : long long int
     394     20089428 : StringUtils::toLong(const std::string& sData) {
     395              :     const char* const data = sData.c_str();
     396     20089428 :     if (data == 0 || data[0] == 0) {
     397           64 :         throw EmptyData();
     398              :     }
     399              :     char* end;
     400     20089364 :     errno = 0;
     401              : #ifdef _MSC_VER
     402              :     long long int ret = _strtoi64(data, &end, 10);
     403              : #else
     404     20089364 :     long long int ret = strtoll(data, &end, 10);
     405              : #endif
     406     20089364 :     if (errno == ERANGE) {
     407            0 :         errno = 0;
     408            0 :         throw NumberFormatException("(long long integer range) " + sData);
     409              :     }
     410     20089364 :     if ((int)(end - data) != (int)strlen(data)) {
     411        57046 :         throw NumberFormatException("(long long integer format) " + sData);
     412              :     }
     413     20060841 :     return ret;
     414              : }
     415              : 
     416              : 
     417              : bool
     418            8 : StringUtils::isLong(const std::string& sData) {
     419              :     const char* const data = sData.c_str();
     420            8 :     if (data == 0 || data[0] == 0) {
     421              :         return false;
     422              :     }
     423              :     char* end;
     424              :     // reset errno before parsing, to keep errors
     425            8 :     errno = 0;
     426              :     // continue depending of current plattform
     427              : #ifdef _MSC_VER
     428              :     _strtoi64(data, &end, 10);
     429              : #else
     430            8 :     strtoll(data, &end, 10);
     431              : #endif
     432              :     // check out of range
     433            8 :     if (errno == ERANGE) {
     434              :         return false;
     435              :     }
     436              :     // check length of converted data
     437            8 :     if ((int)(end - data) != (int)strlen(data)) {
     438              :         return false;
     439              :     }
     440              :     return true;
     441              : }
     442              : 
     443              : 
     444              : int
     445          962 : StringUtils::hexToInt(const std::string& sData) {
     446          962 :     if (sData.length() == 0) {
     447            0 :         throw EmptyData();
     448              :     }
     449          962 :     size_t idx = 0;
     450              :     int result;
     451              :     try {
     452          962 :         if (sData[0] == '#') { // for html color codes
     453          878 :             result = std::stoi(sData.substr(1), &idx, 16);
     454          878 :             idx++;
     455              :         } else {
     456              :             result = std::stoi(sData, &idx, 16);
     457              :         }
     458            0 :     } catch (...) {
     459            0 :         throw NumberFormatException("(hex integer format) " + sData);
     460            0 :     }
     461          962 :     if (idx != sData.length()) {
     462            0 :         throw NumberFormatException("(hex integer format) " + sData);
     463              :     }
     464          962 :     return result;
     465              : }
     466              : 
     467              : 
     468              : bool
     469            0 : StringUtils::isHex(std::string sData) {
     470            0 :     if (sData.length() == 0) {
     471              :         return false;
     472              :     }
     473              :     // remove the first character (for HTML color codes)
     474            0 :     if (sData[0] == '#') {
     475            0 :         sData = sData.substr(1);
     476              :     }
     477              :     const char* sDataPtr = sData.c_str();
     478              :     char* returnPtr;
     479              :     // reset errno
     480            0 :     errno = 0;
     481              :     // call string to long (size 16) from standard library
     482            0 :     strtol(sDataPtr, &returnPtr, 16);
     483              :     // check out of range
     484            0 :     if (errno == ERANGE) {
     485              :         return false;
     486              :     }
     487              :     // check if there was an error converting sDataPtr to double,
     488            0 :     if (sDataPtr == returnPtr) {
     489              :         return false;
     490              :     }
     491              :     // compare size of start and end points
     492            0 :     if (static_cast<size_t>(returnPtr - sDataPtr) != sData.size()) {
     493              :         return false;
     494              :     }
     495              :     return true;
     496              : }
     497              : 
     498              : 
     499              : double
     500     75238536 : StringUtils::toDouble(const std::string& sData) {
     501     75238536 :     if (sData.size() == 0) {
     502          191 :         throw EmptyData();
     503              :     }
     504              :     try {
     505     75238345 :         size_t idx = 0;
     506              :         const double result = std::stod(sData, &idx);
     507     75236769 :         if (idx != sData.size()) {
     508           34 :             throw NumberFormatException("(double format) " + sData);
     509              :         } else {
     510     75236752 :             return result;
     511              :         }
     512         1593 :     } catch (...) {
     513              :         // invalid_argument or out_of_range
     514         3186 :         throw NumberFormatException("(double) " + sData);
     515         1593 :     }
     516              : }
     517              : 
     518              : 
     519              : bool
     520            0 : StringUtils::isDouble(const std::string& sData) {
     521            0 :     if (sData.size() == 0) {
     522              :         return false;
     523              :     }
     524              :     const char* sDataPtr = sData.c_str();
     525              :     char* returnPtr;
     526              :     // reset errno
     527            0 :     errno = 0;
     528              :     // call string to double from standard library
     529            0 :     strtod(sDataPtr, &returnPtr);
     530              :     // check out of range
     531            0 :     if (errno == ERANGE) {
     532              :         return false;
     533              :     }
     534              :     // check if there was an error converting sDataPtr to double,
     535            0 :     if (sDataPtr == returnPtr) {
     536              :         return false;
     537              :     }
     538              :     // compare size of start and end points
     539            0 :     if (static_cast<size_t>(returnPtr - sDataPtr) != sData.size()) {
     540              :         return false;
     541              :     }
     542              :     return true;
     543              : }
     544              : 
     545              : 
     546              : double
     547          348 : StringUtils::toDoubleSecure(const std::string& sData, const double def) {
     548          348 :     if (sData.length() == 0) {
     549              :         return def;
     550              :     }
     551          348 :     return toDouble(sData);
     552              : }
     553              : 
     554              : 
     555              : bool
     556      3293251 : StringUtils::toBool(const std::string& sData) {
     557      3293251 :     if (sData.length() == 0) {
     558            1 :         throw EmptyData();
     559              :     }
     560      3293250 :     const std::string s = to_lower_case(sData);
     561      3293250 :     if (s == "1" || s == "yes" || s == "true" || s == "on" || s == "x" || s == "t") {
     562              :         return true;
     563              :     }
     564      2677156 :     if (s == "0" || s == "no" || s == "false" || s == "off" || s == "-" || s == "f") {
     565              :         return false;
     566              :     }
     567          147 :     throw BoolFormatException(s);
     568              : }
     569              : 
     570              : 
     571              : bool
     572        75610 : StringUtils::isBool(const std::string& sData) {
     573        75610 :     if (sData.length() == 0) {
     574              :         return false;
     575              :     }
     576        17622 :     const std::string s = to_lower_case(sData);
     577              :     // check true values
     578        17622 :     if (s == "1" || s == "yes" || s == "true" || s == "on" || s == "x" || s == "t") {
     579              :         return true;
     580              :     }
     581              :     // check false values
     582         1058 :     if (s == "0" || s == "no" || s == "false" || s == "off" || s == "-" || s == "f") {
     583              :         return true;
     584              :     }
     585              :     // no valid true or false values
     586              :     return false;
     587              : }
     588              : 
     589              : 
     590              : MMVersion
     591        46839 : StringUtils::toVersion(const std::string& sData) {
     592       140517 :     std::vector<std::string> parts = StringTokenizer(sData, ".").getVector();
     593        93678 :     return MMVersion(toInt(parts.front()), toDouble(parts.back()));
     594        46839 : }
     595              : 
     596              : 
     597              : double
     598         2205 : StringUtils::parseDist(const std::string& sData) {
     599         2205 :     if (sData.size() == 0) {
     600            1 :         throw EmptyData();
     601              :     }
     602              :     try {
     603         2204 :         size_t idx = 0;
     604              :         const double result = std::stod(sData, &idx);
     605         2203 :         if (idx != sData.size()) {
     606            4 :             const std::string unit = prune(sData.substr(idx));
     607            4 :             if (unit == "m" || unit == "metre" || unit == "meter" || unit == "metres" || unit == "meters") {
     608              :                 return result;
     609              :             }
     610            2 :             if (unit == "km" || unit == "kilometre" || unit == "kilometer" || unit == "kilometres" || unit == "kilometers") {
     611            1 :                 return result * 1000.;
     612              :             }
     613            1 :             if (unit == "mi" || unit == "mile" || unit == "miles") {
     614            0 :                 return result * 1000. * KM_PER_MILE;
     615              :             }
     616            1 :             if (unit == "nmi") {
     617            0 :                 return result * 1852.;
     618              :             }
     619            1 :             if (unit == "ft" || unit == "foot" || unit == "feet") {
     620            0 :                 return result * 12. * 0.0254;
     621              :             }
     622            1 :             if (unit == "\"" || unit == "in" || unit == "inch" || unit == "inches") {
     623            0 :                 return result * 0.0254;
     624              :             }
     625            1 :             if (unit[0] == '\'') {
     626            0 :                 double inches = 12 * result;
     627            0 :                 if (unit.length() > 1) {
     628            0 :                     inches += std::stod(unit.substr(1), &idx);
     629            1 :                     if (unit.substr(idx) == "\"") {
     630            0 :                         return inches * 0.0254;
     631              :                     }
     632              :                 }
     633              :             }
     634            2 :             throw NumberFormatException("(distance format) " + sData);
     635              :         } else {
     636              :             return result;
     637              :         }
     638            2 :     } catch (...) {
     639              :         // invalid_argument or out_of_range
     640            4 :         throw NumberFormatException("(double) " + sData);
     641            2 :     }
     642              : }
     643              : 
     644              : 
     645              : double
     646         8125 : StringUtils::parseSpeed(const std::string& sData, const bool defaultKmph) {
     647         8125 :     if (sData.size() == 0) {
     648            1 :         throw EmptyData();
     649              :     }
     650              :     try {
     651         8124 :         size_t idx = 0;
     652              :         const double result = std::stod(sData, &idx);
     653         8120 :         if (idx != sData.size()) {
     654         1245 :             const std::string unit = prune(sData.substr(idx));
     655         1245 :             if (unit == "km/h" || unit == "kph" || unit == "kmh" || unit == "kmph") {
     656            3 :                 return result / 3.6;
     657              :             }
     658         1242 :             if (unit == "m/s") {
     659              :                 return result;
     660              :             }
     661         1240 :             if (unit == "mph") {
     662         1239 :                 return result * KM_PER_MILE / 3.6;
     663              :             }
     664            1 :             if (unit == "knots") {
     665            0 :                 return result * 1.852 / 3.6;
     666              :             }
     667            2 :             throw NumberFormatException("(speed format) " + sData);
     668              :         } else {
     669         6875 :             return defaultKmph ? result / 3.6 : result;
     670              :         }
     671            5 :     } catch (...) {
     672              :         // invalid_argument or out_of_range
     673           10 :         throw NumberFormatException("(double) " + sData);
     674            5 :     }
     675              : }
     676              : 
     677              : 
     678              : std::string
     679    101638327 : StringUtils::transcode(const XMLCh* const data, int length) {
     680    101638327 :     if (data == 0) {
     681            0 :         throw EmptyData();
     682              :     }
     683    101638327 :     if (length == 0) {
     684       355038 :         return "";
     685              :     }
     686              : #if _XERCES_VERSION < 30100
     687              :     char* t = XERCES_CPP_NAMESPACE::XMLString::transcode(data);
     688              :     std::string result(t);
     689              :     XERCES_CPP_NAMESPACE::XMLString::release(&t);
     690              :     return result;
     691              : #else
     692              :     try {
     693    101283289 :         XERCES_CPP_NAMESPACE::TranscodeToStr utf8(data, "UTF-8");
     694    101283289 :         return reinterpret_cast<const char*>(utf8.str());
     695    101283289 :     } catch (XERCES_CPP_NAMESPACE::TranscodingException&) {
     696            0 :         return "?";
     697            0 :     }
     698              : #endif
     699              : }
     700              : 
     701              : 
     702              : std::string
     703       838373 : StringUtils::transcodeFromLocal(const std::string& localString) {
     704              : #if _XERCES_VERSION > 30100
     705              :     try {
     706       838373 :         if (myLCPTranscoder == nullptr) {
     707        52847 :             myLCPTranscoder = XERCES_CPP_NAMESPACE::XMLPlatformUtils::fgTransService->makeNewLCPTranscoder(XERCES_CPP_NAMESPACE::XMLPlatformUtils::fgMemoryManager);
     708              :         }
     709       838373 :         if (myLCPTranscoder != nullptr) {
     710       838373 :             return transcode(myLCPTranscoder->transcode(localString.c_str()));
     711              :         }
     712            0 :     } catch (XERCES_CPP_NAMESPACE::TranscodingException&) {}
     713              : #endif
     714              :     return localString;
     715              : }
     716              : 
     717              : 
     718              : std::string
     719       917628 : StringUtils::transcodeToLocal(const std::string& utf8String) {
     720              : #if _XERCES_VERSION > 30100
     721              :     try {
     722       917628 :         if (myLCPTranscoder == nullptr) {
     723         1139 :             myLCPTranscoder = XERCES_CPP_NAMESPACE::XMLPlatformUtils::fgTransService->makeNewLCPTranscoder(XERCES_CPP_NAMESPACE::XMLPlatformUtils::fgMemoryManager);
     724              :         }
     725       917628 :         if (myLCPTranscoder != nullptr) {
     726       917628 :             XERCES_CPP_NAMESPACE::TranscodeFromStr utf8(reinterpret_cast<const XMLByte*>(utf8String.c_str()), utf8String.size(), "UTF-8");
     727       917628 :             return myLCPTranscoder->transcode(utf8.str());
     728       917628 :         }
     729            0 :     } catch (XERCES_CPP_NAMESPACE::TranscodingException&) {}
     730              : #endif
     731              :     return utf8String;
     732              : }
     733              : 
     734              : 
     735              : std::string
     736            0 : StringUtils::trim_left(const std::string s, const std::string& t) {
     737              :     std::string result = s;
     738            0 :     result.erase(0, s.find_first_not_of(t));
     739            0 :     return result;
     740              : }
     741              : 
     742              : std::string
     743            0 : StringUtils::trim_right(const std::string s, const std::string& t) {
     744              :     std::string result = s;
     745            0 :     result.erase(s.find_last_not_of(t) + 1);
     746            0 :     return result;
     747              : }
     748              : 
     749              : std::string
     750            0 : StringUtils::trim(const std::string s, const std::string& t) {
     751            0 :     return trim_right(trim_left(s, t), t);
     752              : }
     753              : 
     754              : 
     755              : std::string
     756            0 : StringUtils::wrapText(const std::string s, int width) {
     757            0 :     std::vector<std::string> parts = StringTokenizer(s).getVector();
     758              :     std::string result;
     759              :     std::string line;
     760              :     bool firstLine = true;
     761              :     bool firstWord = true;
     762            0 :     for (std::string p : parts) {
     763            0 :         if ((int)(line.size() + p.size()) < width || firstWord) {
     764            0 :             if (firstWord) {
     765              :                 firstWord = false;
     766              :             } else {
     767              :                 line += " ";
     768              :             }
     769              :             line += p;
     770              :         } else {
     771            0 :             if (firstLine) {
     772              :                 firstLine = false;
     773              :             } else {
     774              :                 result += "\n";
     775              :             }
     776              :             result += line;
     777              :             line.clear();
     778              :             line += p;
     779              :         }
     780              :     }
     781            0 :     if (line.size() > 0) {
     782            0 :         if (firstLine) {
     783              :             firstLine = false;
     784              :         } else {
     785              :             result += "\n";
     786              :         }
     787              :         result += line;
     788              :     }
     789            0 :     return result;
     790            0 : }
     791              : 
     792              : 
     793              : void
     794        54343 : StringUtils::resetTranscoder() {
     795        54343 :     myLCPTranscoder = nullptr;
     796        54343 : }
     797              : 
     798              : 
     799              : std::string
     800          961 : StringUtils::adjustDecimalValue(double value, int precision) {
     801              :     // obtain value in string format with 20 decimals precision
     802          961 :     auto valueStr = toString(value, precision);
     803              :     // now clear all zeros
     804        16885 :     while (valueStr.size() > 1) {
     805        16885 :         if (valueStr.back() == '0') {
     806              :             valueStr.pop_back();
     807          961 :         } else if (valueStr.back() == '.') {
     808              :             valueStr.pop_back();
     809              :             return valueStr;
     810              :         } else {
     811              :             return valueStr;
     812              :         }
     813              :     }
     814              :     return valueStr;
     815              : }
     816              : 
     817              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1