| /* |
| * Copyright (C) 2004-2023 Savoir-faire Linux Inc. |
| * |
| * This program is free software: you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation, either version 3 of the License, or |
| * (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program. If not, see <https://www.gnu.org/licenses/>. |
| */ |
| #include "string_utils.h" |
| |
| #include <fmt/core.h> |
| #include <fmt/ranges.h> |
| |
| #include <sstream> |
| #include <cctype> |
| #include <algorithm> |
| #include <ostream> |
| #include <iomanip> |
| #include <stdexcept> |
| #include <ios> |
| #include <charconv> |
| #include <string_view> |
| #ifdef _WIN32 |
| #include <windows.h> |
| #include <oleauto.h> |
| #endif |
| |
| #include <ciso646> // fix windows compiler bug |
| |
| namespace dhtnet { |
| |
| #ifdef _WIN32 |
| std::wstring |
| to_wstring(const std::string& str, int codePage) |
| { |
| int srcLength = (int) str.length(); |
| int requiredSize = MultiByteToWideChar(codePage, 0, str.c_str(), srcLength, nullptr, 0); |
| if (!requiredSize) { |
| throw std::runtime_error("Unable to convert string to wstring"); |
| } |
| std::wstring result((size_t) requiredSize, 0); |
| if (!MultiByteToWideChar(codePage, 0, str.c_str(), srcLength, &(*result.begin()), requiredSize)) { |
| throw std::runtime_error("Unable to convert string to wstring"); |
| } |
| return result; |
| } |
| |
| std::string |
| to_string(const std::wstring& wstr, int codePage) |
| { |
| int srcLength = (int) wstr.length(); |
| int requiredSize = WideCharToMultiByte(codePage, 0, wstr.c_str(), srcLength, nullptr, 0, 0, 0); |
| if (!requiredSize) { |
| throw std::runtime_error("Unable to convert wstring to string"); |
| } |
| std::string result((size_t) requiredSize, 0); |
| if (!WideCharToMultiByte( |
| codePage, 0, wstr.c_str(), srcLength, &(*result.begin()), requiredSize, 0, 0)) { |
| throw std::runtime_error("Unable to convert wstring to string"); |
| } |
| return result; |
| } |
| #endif |
| |
| std::string |
| to_string(double value) |
| { |
| char buf[64]; |
| int len = snprintf(buf, sizeof(buf), "%-.*G", 16, value); |
| if (len <= 0) |
| throw std::invalid_argument {"Unable to parse double"}; |
| return {buf, (size_t) len}; |
| } |
| |
| std::string |
| to_hex_string(uint64_t id) |
| { |
| return fmt::format("{:016x}", id); |
| } |
| |
| uint64_t |
| from_hex_string(const std::string& str) |
| { |
| uint64_t id; |
| if (auto [p, ec] = std::from_chars(str.data(), str.data()+str.size(), id, 16); ec != std::errc()) { |
| throw std::invalid_argument("Unable to parse id: " + str); |
| } |
| return id; |
| } |
| |
| std::string_view |
| trim(std::string_view s) |
| { |
| auto wsfront = std::find_if_not(s.cbegin(), s.cend(), [](int c) { return std::isspace(c); }); |
| return std::string_view(&*wsfront, std::find_if_not(s.rbegin(), |
| std::string_view::const_reverse_iterator(wsfront), |
| [](int c) { return std::isspace(c); }) |
| .base() - wsfront); |
| } |
| |
| std::vector<unsigned> |
| split_string_to_unsigned(std::string_view str, char delim) |
| { |
| std::vector<unsigned> output; |
| for (auto first = str.data(), second = str.data(), last = first + str.size(); second != last && first != last; first = second + 1) { |
| second = std::find(first, last, delim); |
| if (first != second) { |
| unsigned result; |
| auto [p, ec] = std::from_chars(first, second, result); |
| if (ec == std::errc()) |
| output.emplace_back(result); |
| } |
| } |
| return output; |
| } |
| |
| void |
| string_replace(std::string& str, const std::string& from, const std::string& to) |
| { |
| size_t start_pos = 0; |
| while ((start_pos = str.find(from, start_pos)) != std::string::npos) { |
| str.replace(start_pos, from.length(), to); |
| start_pos += to.length(); // Handles case where 'to' is a substring of 'from' |
| } |
| } |
| |
| } // namespace dhtnet |