• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "common/strings.h"
18 
19 #include <algorithm>
20 #include <charconv>
21 #include <cstdlib>
22 #include <functional>
23 #include <iomanip>
24 #include <iterator>
25 #include <sstream>
26 #include <system_error>
27 
28 namespace {
29 
30 struct IsSpace {
operator ()__anon2e3a88c30111::IsSpace31   bool operator()(std::string::value_type v) {
32     return isspace(static_cast<int>(v));
33   }
34 };
35 
36 struct IsHexDigit {
operator ()__anon2e3a88c30111::IsHexDigit37   bool operator()(std::string::value_type v) {
38     return isxdigit(static_cast<int>(v));
39   }
40 };
41 
42 }  // namespace
43 
44 namespace bluetooth {
45 namespace common {
46 
ToHexString(const std::vector<uint8_t> & value)47 std::string ToHexString(const std::vector<uint8_t>& value) {
48   return ToHexString(value.begin(), value.end());
49 }
50 
IsValidHexString(const std::string & str)51 bool IsValidHexString(const std::string& str) {
52   return std::find_if_not(str.begin(), str.end(), IsHexDigit{}) == str.end();
53 }
54 
FromHexString(const std::string & str)55 std::optional<std::vector<uint8_t>> FromHexString(const std::string& str) {
56   if (str.size() % 2 != 0) {
57     LOG_INFO("str size is not divisible by 2, size is %zu", str.size());
58     return std::nullopt;
59   }
60   if (std::find_if_not(str.begin(), str.end(), IsHexDigit{}) != str.end()) {
61     LOG_INFO("value contains none hex digit");
62     return std::nullopt;
63   }
64   std::vector<uint8_t> value;
65   value.reserve(str.size() / 2);
66   for (size_t i = 0; i < str.size(); i += 2) {
67     uint8_t v = 0;
68     auto ret = std::from_chars(str.c_str() + i, str.c_str() + i + 2, v, 16);
69     if (std::make_error_code(ret.ec)) {
70       LOG_INFO("failed to parse hex char at index %zu", i);
71       return std::nullopt;
72     }
73     value.push_back(v);
74   }
75   return value;
76 }
77 
StringTrim(std::string str)78 std::string StringTrim(std::string str) {
79   str.erase(str.begin(), std::find_if_not(str.begin(), str.end(), IsSpace{}));
80   str.erase(std::find_if_not(str.rbegin(), str.rend(), IsSpace{}).base(), str.end());
81   return str;
82 }
83 
StringSplit(const std::string & str,const std::string & delim,size_t max_token)84 std::vector<std::string> StringSplit(const std::string& str, const std::string& delim, size_t max_token) {
85   ASSERT_LOG(!delim.empty(), "delim cannot be empty");
86   std::vector<std::string> tokens;
87   // Use std::string::find and std::string::substr to avoid copying str into a stringstream
88   std::string::size_type starting_index = 0;
89   auto index_of_delim = str.find(delim);
90   while ((max_token == 0 || tokens.size() < (max_token - 1)) && index_of_delim != std::string::npos) {
91     tokens.push_back(str.substr(starting_index, index_of_delim - starting_index));
92     starting_index = index_of_delim + delim.size();
93     index_of_delim = str.find(delim, starting_index);
94   }
95   // Append last item to the vector if there are anything left
96   if (starting_index < (str.size() + 1)) {
97     tokens.push_back(str.substr(starting_index));
98   }
99   return tokens;
100 }
101 
StringJoin(const std::vector<std::string> & strings,const std::string & delim)102 std::string StringJoin(const std::vector<std::string>& strings, const std::string& delim) {
103   std::stringstream ss;
104   for (auto it = strings.begin(); it != strings.end(); it++) {
105     ss << *it;
106     if (std::next(it) != strings.end()) {
107       ss << delim;
108     }
109   }
110   return ss.str();
111 }
112 
Int64FromString(const std::string & str)113 std::optional<int64_t> Int64FromString(const std::string& str) {
114   char* ptr = nullptr;
115   errno = 0;
116   int64_t value = std::strtoll(str.c_str(), &ptr, 10);
117   if (errno != 0) {
118     LOG_INFO("cannot parse string '%s' with error '%s'", str.c_str(), strerror(errno));
119     return std::nullopt;
120   }
121   if (ptr == str.c_str()) {
122     LOG_INFO("string '%s' is empty or has wrong format", str.c_str());
123     return std::nullopt;
124   }
125   if (ptr != (str.c_str() + str.size())) {
126     LOG_INFO("cannot parse whole string '%s'", str.c_str());
127     return std::nullopt;
128   }
129   return value;
130 }
131 
ToString(int64_t value)132 std::string ToString(int64_t value) {
133   return std::to_string(value);
134 }
135 
Uint64FromString(const std::string & str)136 std::optional<uint64_t> Uint64FromString(const std::string& str) {
137   if (str.find('-') != std::string::npos) {
138     LOG_INFO("string '%s' contains minus sign, this function is for unsigned", str.c_str());
139     return std::nullopt;
140   }
141   char* ptr = nullptr;
142   errno = 0;
143   uint64_t value = std::strtoull(str.c_str(), &ptr, 10);
144   if (errno != 0) {
145     LOG_INFO("cannot parse string '%s' with error '%s'", str.c_str(), strerror(errno));
146     return std::nullopt;
147   }
148   if (ptr == str.c_str()) {
149     LOG_INFO("string '%s' is empty or has wrong format", str.c_str());
150     return std::nullopt;
151   }
152   if (ptr != (str.c_str() + str.size())) {
153     LOG_INFO("cannot parse whole string '%s'", str.c_str());
154     return std::nullopt;
155   }
156   return value;
157 }
158 
ToString(uint64_t value)159 std::string ToString(uint64_t value) {
160   return std::to_string(value);
161 }
162 
BoolFromString(const std::string & str)163 std::optional<bool> BoolFromString(const std::string& str) {
164   if (str == "true") {
165     return true;
166   } else if (str == "false") {
167     return false;
168   } else {
169     LOG_INFO("string '%s' is neither true nor false", str.c_str());
170     return std::nullopt;
171   }
172 }
173 
ToString(bool value)174 std::string ToString(bool value) {
175   return value ? "true" : "false";
176 }
177 
178 }  // namespace common
179 }  // namespace bluetooth
180