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 */ 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 */ 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> 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> 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 */ 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 */ 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 */ 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 */ 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 */ 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