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