LCOV - code coverage report
Current view: top level - src/utils/common - StringUtils.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 75.9 % 319 242
Test Date: 2025-12-06 15:35:27 Functions: 75.6 % 41 31

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

Generated by: LCOV version 2.0-1