1 #pragma once
2
3 #include "constants.hpp"
4 #include "error_codes.hpp"
5 #include "logger.hpp"
6
7 #include <algorithm>
8 #include <chrono>
9 #include <cstdio>
10 #include <cstdlib>
11 #include <vector>
12
13 /**
14 * @brief Namespace to host common utility methods.
15 *
16 * A method qualifies as a common utility function if,
17 * A)It is being used by the utility namespace at the same level as well as
18 * other files directly.
19 * B) The utility should be a leaf node and should not be dependent on any other
20 * utility.
21 * *******************
22 * | Commmon Utility | - - - - - - -
23 * ******************* |
24 * /\ |
25 * / \ |
26 * **************** **************** |
27 * | json utility | | dbus utility | |
28 * **************** **************** |
29 * \ / |
30 * \ / |
31 * ************************ |
32 * | Vpd specific Utility | - - - - - - -
33 * ************************
34 */
35
36 namespace vpd
37 {
38
39 namespace commonUtility
40 {
41 /**
42 * @brief API to get error code message.
43 *
44 * @param[in] i_errCode - error code.
45 *
46 * @return Error message set for that error code. Otherwise empty
47 * string.
48 */
getErrCodeMsg(const uint16_t & i_errCode)49 inline std::string getErrCodeMsg(const uint16_t& i_errCode)
50 {
51 if (errorCodeMap.find(i_errCode) != errorCodeMap.end())
52 {
53 return errorCodeMap.at(i_errCode);
54 }
55
56 return std::string{};
57 }
58
59 /** @brief Return the hex representation of the incoming byte.
60 *
61 * @param [in] i_aByte - The input byte.
62 * @returns Null character if input byte is out of bound else returns hex
63 * representation of the byte as a character.
64 */
toHex(const size_t & i_aByte)65 constexpr auto toHex(const size_t& i_aByte) noexcept
66 {
67 constexpr auto l_map = "0123456789abcdef";
68
69 return (i_aByte < std::strlen(l_map)) ? l_map[i_aByte] : '\0';
70 }
71
72 /**
73 * @brief API to return null at the end of variadic template args.
74 *
75 * @return empty string.
76 */
getCommand()77 inline std::string getCommand()
78 {
79 return "";
80 }
81
82 /**
83 * @brief API to arrange create command.
84 *
85 * @param[in] arguments to create the command
86 * @return Command string
87 */
88 template <typename T, typename... Types>
getCommand(T i_arg1,Types...i_args)89 inline std::string getCommand(T i_arg1, Types... i_args)
90 {
91 std::string l_cmd = " " + i_arg1 + getCommand(i_args...);
92
93 return l_cmd;
94 }
95
96 /**
97 * @brief API to create shell command and execute.
98 *
99 * @throw std::runtime_error.
100 *
101 * @param[in] arguments for command
102 * @returns output of that command
103 */
104 template <typename T, typename... Types>
executeCmd(T && i_path,Types...i_args)105 inline std::vector<std::string> executeCmd(T&& i_path, Types... i_args)
106 {
107 std::vector<std::string> l_cmdOutput;
108 std::array<char, constants::CMD_BUFFER_LENGTH> l_buffer;
109
110 std::string l_cmd = i_path + getCommand(i_args...);
111
112 std::unique_ptr<FILE, decltype(&pclose)> l_cmdPipe(
113 popen(l_cmd.c_str(), "r"), pclose);
114
115 if (!l_cmdPipe)
116 {
117 logging::logMessage(
118 "popen failed with error " + std::string(strerror(errno)));
119 throw std::runtime_error("popen failed!");
120 }
121 while (fgets(l_buffer.data(), l_buffer.size(), l_cmdPipe.get()) != nullptr)
122 {
123 l_cmdOutput.emplace_back(l_buffer.data());
124 }
125
126 return l_cmdOutput;
127 }
128
129 /** @brief Converts string to lower case.
130 *
131 * @param [in] i_string - Input string.
132 */
toLower(std::string & i_string)133 inline void toLower(std::string& i_string)
134 {
135 std::transform(i_string.begin(), i_string.end(), i_string.begin(),
136 [](unsigned char l_char) { return std::tolower(l_char); });
137 }
138
139 /**
140 * @brief An API to get hex representation of the incoming bytes.
141 *
142 * The API returns the hex represented value of the given input in string format
143 * with 0x prefix.
144 *
145 * @param[in] i_keywordValue - Vector of input byte.
146 *
147 * @return - Returns the converted string value.
148 */
convertByteVectorToHex(const types::BinaryVector & i_keywordValue)149 inline std::string convertByteVectorToHex(
150 const types::BinaryVector& i_keywordValue)
151 {
152 std::ostringstream l_oss;
153 l_oss << "0x";
154 for (const auto& l_byte : i_keywordValue)
155 {
156 l_oss << std::setfill('0') << std::setw(2) << std::hex
157 << static_cast<int>(l_byte);
158 }
159
160 return l_oss.str();
161 }
162
163 /**
164 * @brief An API to convert binary value into ascii/hex representation.
165 *
166 * If given data contains printable characters, ASCII formated string value of
167 * the input data will be returned. Otherwise if the data has any non-printable
168 * value, returns the hex represented value of the given data in string format.
169 *
170 * @param[in] i_keywordValue - Data in binary format.
171 *
172 * @throw - Throws std::bad_alloc or std::terminate in case of error.
173 *
174 * @return - Returns the converted string value.
175 */
getPrintableValue(const types::BinaryVector & i_keywordValue)176 inline std::string getPrintableValue(const types::BinaryVector& i_keywordValue)
177 {
178 bool l_allPrintable =
179 std::all_of(i_keywordValue.begin(), i_keywordValue.end(),
180 [](const auto& l_byte) { return std::isprint(l_byte); });
181
182 std::ostringstream l_oss;
183 if (l_allPrintable)
184 {
185 l_oss << std::string(i_keywordValue.begin(), i_keywordValue.end());
186 }
187 else
188 {
189 l_oss << "0x";
190 for (const auto& l_byte : i_keywordValue)
191 {
192 l_oss << std::setfill('0') << std::setw(2) << std::hex
193 << static_cast<int>(l_byte);
194 }
195 }
196
197 return l_oss.str();
198 }
199
200 /**
201 * @brief API to get data in binary format.
202 *
203 * This API converts given string value present in hexadecimal or decimal format
204 * into array of binary data.
205 *
206 * @param[in] i_value - Input data.
207 *
208 * @return - Array of binary data on success, throws as exception in case
209 * of any error.
210 *
211 * @throw std::runtime_error, std::out_of_range, std::bad_alloc,
212 * std::invalid_argument
213 */
convertToBinary(const std::string & i_value)214 inline types::BinaryVector convertToBinary(const std::string& i_value)
215 {
216 if (i_value.empty())
217 {
218 throw std::runtime_error("Empty input provided");
219 }
220
221 types::BinaryVector l_binaryValue{};
222
223 if (i_value.substr(0, 2).compare("0x") == constants::STR_CMP_SUCCESS)
224 {
225 if (i_value.length() % 2 != 0)
226 {
227 throw std::runtime_error(
228 "Write option accepts 2 digit hex numbers. (Ex. 0x1 "
229 "should be given as 0x01).");
230 }
231
232 auto l_value = i_value.substr(2);
233
234 if (l_value.empty())
235 {
236 throw std::runtime_error(
237 "Provide a valid hexadecimal input. (Ex. 0x30313233)");
238 }
239
240 if (l_value.find_first_not_of("0123456789abcdefABCDEF") !=
241 std::string::npos)
242 {
243 throw std::runtime_error("Provide a valid hexadecimal input.");
244 }
245
246 for (size_t l_pos = 0; l_pos < l_value.length(); l_pos += 2)
247 {
248 uint8_t l_byte = static_cast<uint8_t>(
249 std::stoi(l_value.substr(l_pos, 2), nullptr, 16));
250 l_binaryValue.push_back(l_byte);
251 }
252 }
253 else
254 {
255 l_binaryValue.assign(i_value.begin(), i_value.end());
256 }
257 return l_binaryValue;
258 }
259
260 /**
261 * @brief API to get current time stamp since Epoch.
262 *
263 * @return time stamp in seconds.
264 */
getCurrentTimeSinceEpoch()265 inline size_t getCurrentTimeSinceEpoch() noexcept
266 {
267 // Use high_resolution_clock for better precision
268 const auto l_now = std::chrono::high_resolution_clock::now();
269 auto l_durationSinceEpoch = l_now.time_since_epoch();
270
271 auto l_timeStampSeconds =
272 std::chrono::duration_cast<std::chrono::seconds>(l_durationSinceEpoch)
273 .count();
274 return static_cast<size_t>(l_timeStampSeconds);
275 }
276
277 } // namespace commonUtility
278 } // namespace vpd
279