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