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