/* * Copyright 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "common/strings.h" #include #include #include #include #include #include #include namespace { struct IsSpace : std::unary_function { bool operator()(std::string::value_type v) { return isspace(static_cast(v)); } }; struct IsHexDigit : std::unary_function { bool operator()(std::string::value_type v) { return isxdigit(static_cast(v)); } }; } // namespace namespace bluetooth { namespace common { std::string ToHexString(const std::vector& value) { return ToHexString(value.begin(), value.end()); } bool IsValidHexString(const std::string& str) { return std::find_if_not(str.begin(), str.end(), IsHexDigit{}) == str.end(); } std::optional> FromHexString(const std::string& str) { if (str.size() % 2 != 0) { LOG_INFO("str size is not divisible by 2, size is %zu", str.size()); return std::nullopt; } if (std::find_if_not(str.begin(), str.end(), IsHexDigit{}) != str.end()) { LOG_INFO("value contains none hex digit"); return std::nullopt; } std::vector value; value.reserve(str.size() / 2); for (size_t i = 0; i < str.size(); i += 2) { uint8_t v = 0; auto ret = std::from_chars(str.c_str() + i, str.c_str() + i + 2, v, 16); if (std::make_error_code(ret.ec)) { LOG_INFO("failed to parse hex char at index %zu", i); return std::nullopt; } value.push_back(v); } return value; } std::string StringTrim(std::string str) { str.erase(str.begin(), std::find_if_not(str.begin(), str.end(), IsSpace{})); str.erase(std::find_if_not(str.rbegin(), str.rend(), IsSpace{}).base(), str.end()); return str; } std::vector StringSplit(const std::string& str, const std::string& delim, size_t max_token) { ASSERT_LOG(!delim.empty(), "delim cannot be empty"); std::vector tokens; // Use std::string::find and std::string::substr to avoid copying str into a stringstream std::string::size_type starting_index = 0; auto index_of_delim = str.find(delim); while ((max_token == 0 || tokens.size() < (max_token - 1)) && index_of_delim != std::string::npos) { tokens.push_back(str.substr(starting_index, index_of_delim - starting_index)); starting_index = index_of_delim + delim.size(); index_of_delim = str.find(delim, starting_index); } // Append last item to the vector if there are anything left if (starting_index < (str.size() + 1)) { tokens.push_back(str.substr(starting_index)); } return tokens; } std::string StringJoin(const std::vector& strings, const std::string& delim) { std::stringstream ss; for (auto it = strings.begin(); it != strings.end(); it++) { ss << *it; if (std::next(it) != strings.end()) { ss << delim; } } return ss.str(); } std::optional Int64FromString(const std::string& str) { char* ptr = nullptr; errno = 0; int64_t value = std::strtoll(str.c_str(), &ptr, 10); if (errno != 0) { LOG_INFO("cannot parse string '%s' with error '%s'", str.c_str(), strerror(errno)); return std::nullopt; } if (ptr == str.c_str()) { LOG_INFO("string '%s' is empty or has wrong format", str.c_str()); return std::nullopt; } if (ptr != (str.c_str() + str.size())) { LOG_INFO("cannot parse whole string '%s'", str.c_str()); return std::nullopt; } return value; } std::string ToString(int64_t value) { return std::to_string(value); } std::optional Uint64FromString(const std::string& str) { if (str.find('-') != std::string::npos) { LOG_INFO("string '%s' contains minus sign, this function is for unsigned", str.c_str()); return std::nullopt; } char* ptr = nullptr; errno = 0; uint64_t value = std::strtoull(str.c_str(), &ptr, 10); if (errno != 0) { LOG_INFO("cannot parse string '%s' with error '%s'", str.c_str(), strerror(errno)); return std::nullopt; } if (ptr == str.c_str()) { LOG_INFO("string '%s' is empty or has wrong format", str.c_str()); return std::nullopt; } if (ptr != (str.c_str() + str.size())) { LOG_INFO("cannot parse whole string '%s'", str.c_str()); return std::nullopt; } return value; } std::string ToString(uint64_t value) { return std::to_string(value); } std::optional BoolFromString(const std::string& str) { if (str == "true") { return true; } else if (str == "false") { return false; } else { LOG_INFO("string '%s' is neither true nor false", str.c_str()); return std::nullopt; } } std::string ToString(bool value) { return value ? "true" : "false"; } } // namespace common } // namespace bluetooth