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