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