xref: /openbmc/openpower-vpd-parser/vpd-manager/include/utility/common_utility.hpp (revision bffecd9da1c699c231e1541564c4cfd476e31750)
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