1 /** 2 * Copyright © 2025 IBM Corporation 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 #pragma once 17 18 #include <nlohmann/json.hpp> 19 20 #include <cstdint> 21 #include <map> 22 #include <stdexcept> 23 #include <string> 24 #include <vector> 25 26 /** 27 * @namespace json_parser_utils 28 * 29 * Contains utility functions for parsing JSON data. 30 * 31 * ## Variables 32 * The parsing functions support optional usage of variables. JSON string values 33 * can contain one or more variables. A variable is specified using the format 34 * `${variable_name}`. A variables map is specified to parsing functions that 35 * provides the variable values. Any variable in a JSON string value will be 36 * replaced by the variable value. 37 * 38 * Variables can only appear in a JSON string value. The parsing functions for 39 * other data types, such as integer and double, support a string value if it 40 * contains a variable. After variable expansion, the string is converted to the 41 * expected data type. 42 */ 43 namespace phosphor::power::json_parser_utils 44 { 45 46 /** 47 * Empty variables map used as a default value for parsing functions. 48 */ 49 extern const std::map<std::string, std::string> NO_VARIABLES; 50 51 /** 52 * Returns the specified property of the specified JSON element. 53 * 54 * Throws an invalid_argument exception if the property does not exist. 55 * 56 * @param element JSON element 57 * @param property property name 58 */ 59 #pragma GCC diagnostic push 60 #if __GNUC__ >= 13 61 #pragma GCC diagnostic ignored "-Wdangling-reference" 62 #endif 63 inline const nlohmann::json& getRequiredProperty(const nlohmann::json& element, 64 const std::string& property) 65 { 66 auto it = element.find(property); 67 if (it == element.end()) 68 { 69 throw std::invalid_argument{"Required property missing: " + property}; 70 } 71 return *it; 72 } 73 #pragma GCC diagnostic pop 74 75 /** 76 * Parses a JSON element containing a bit position (from 0-7). 77 * 78 * Returns the corresponding C++ uint8_t value. 79 * 80 * Throws an exception if parsing fails. 81 * 82 * @param element JSON element 83 * @param variables variables map used to expand variables in element value 84 * @return uint8_t value 85 */ 86 uint8_t parseBitPosition( 87 const nlohmann::json& element, 88 const std::map<std::string, std::string>& variables = NO_VARIABLES); 89 90 /** 91 * Parses a JSON element containing a bit value (0 or 1). 92 * 93 * Returns the corresponding C++ uint8_t value. 94 * 95 * Throws an exception if parsing fails. 96 * 97 * @param element JSON element 98 * @param variables variables map used to expand variables in element value 99 * @return uint8_t value 100 */ 101 uint8_t parseBitValue( 102 const nlohmann::json& element, 103 const std::map<std::string, std::string>& variables = NO_VARIABLES); 104 105 /** 106 * Parses a JSON element containing a boolean. 107 * 108 * Returns the corresponding C++ boolean value. 109 * 110 * Throws an exception if parsing fails. 111 * 112 * @param element JSON element 113 * @param variables variables map used to expand variables in element value 114 * @return boolean value 115 */ 116 bool parseBoolean( 117 const nlohmann::json& element, 118 const std::map<std::string, std::string>& variables = NO_VARIABLES); 119 120 /** 121 * Parses a JSON element containing a double (floating point number). 122 * 123 * Returns the corresponding C++ double value. 124 * 125 * Throws an exception if parsing fails. 126 * 127 * @param element JSON element 128 * @param variables variables map used to expand variables in element value 129 * @return double value 130 */ 131 double parseDouble( 132 const nlohmann::json& element, 133 const std::map<std::string, std::string>& variables = NO_VARIABLES); 134 135 /** 136 * Parses a JSON element containing a byte value expressed as a hexadecimal 137 * string. 138 * 139 * The JSON number data type does not support the hexadecimal format. For this 140 * reason, a hexadecimal byte value is stored in a JSON string. 141 * 142 * Returns the corresponding C++ uint8_t value. 143 * 144 * Throws an exception if parsing fails. 145 * 146 * @param element JSON element 147 * @param variables variables map used to expand variables in element value 148 * @return uint8_t value 149 */ 150 uint8_t parseHexByte( 151 const nlohmann::json& element, 152 const std::map<std::string, std::string>& variables = NO_VARIABLES); 153 154 /** 155 * Parses a JSON element containing an array of byte values expressed as a 156 * hexadecimal strings. 157 * 158 * Returns the corresponding C++ uint8_t values. 159 * 160 * Throws an exception if parsing fails. 161 * 162 * @param element JSON element 163 * @param variables variables map used to expand variables in element value 164 * @return vector of uint8_t 165 */ 166 std::vector<uint8_t> parseHexByteArray( 167 const nlohmann::json& element, 168 const std::map<std::string, std::string>& variables = NO_VARIABLES); 169 170 /** 171 * Parses a JSON element containing an 8-bit signed integer. 172 * 173 * Returns the corresponding C++ int8_t value. 174 * 175 * Throws an exception if parsing fails. 176 * 177 * @param element JSON element 178 * @param variables variables map used to expand variables in element value 179 * @return int8_t value 180 */ 181 int8_t parseInt8( 182 const nlohmann::json& element, 183 const std::map<std::string, std::string>& variables = NO_VARIABLES); 184 185 /** 186 * Parses a JSON element containing an integer. 187 * 188 * Returns the corresponding C++ int value. 189 * 190 * Throws an exception if parsing fails. 191 * 192 * @param element JSON element 193 * @param variables variables map used to expand variables in element value 194 * @return integer value 195 */ 196 int parseInteger( 197 const nlohmann::json& element, 198 const std::map<std::string, std::string>& variables = NO_VARIABLES); 199 200 /** 201 * Parses a JSON element containing a string. 202 * 203 * Returns the corresponding C++ string. 204 * 205 * Throws an exception if parsing fails. 206 * 207 * @param element JSON element 208 * @param isEmptyValid indicates whether an empty string value is valid 209 * @param variables variables map used to expand variables in element value 210 * @return string value 211 */ 212 std::string parseString( 213 const nlohmann::json& element, bool isEmptyValid = false, 214 const std::map<std::string, std::string>& variables = NO_VARIABLES); 215 216 /** 217 * Parses a JSON element containing an 8-bit unsigned integer. 218 * 219 * Returns the corresponding C++ uint8_t value. 220 * 221 * Throws an exception if parsing fails. 222 * 223 * @param element JSON element 224 * @param variables variables map used to expand variables in element value 225 * @return uint8_t value 226 */ 227 uint8_t parseUint8( 228 const nlohmann::json& element, 229 const std::map<std::string, std::string>& variables = NO_VARIABLES); 230 231 /** 232 * Parses a JSON element containing an unsigned integer. 233 * 234 * Returns the corresponding C++ unsigned int value. 235 * 236 * Throws an exception if parsing fails. 237 * 238 * @param element JSON element 239 * @param variables variables map used to expand variables in element value 240 * @return unsigned int value 241 */ 242 unsigned int parseUnsignedInteger( 243 const nlohmann::json& element, 244 const std::map<std::string, std::string>& variables = NO_VARIABLES); 245 246 /** 247 * Verifies that the specified JSON element is a JSON array. 248 * 249 * Throws an invalid_argument exception if the element is not an array. 250 * 251 * @param element JSON element 252 */ 253 inline void verifyIsArray(const nlohmann::json& element) 254 { 255 if (!element.is_array()) 256 { 257 throw std::invalid_argument{"Element is not an array"}; 258 } 259 } 260 261 /** 262 * Verifies that the specified JSON element is a JSON object. 263 * 264 * Throws an invalid_argument exception if the element is not an object. 265 * 266 * @param element JSON element 267 */ 268 inline void verifyIsObject(const nlohmann::json& element) 269 { 270 if (!element.is_object()) 271 { 272 throw std::invalid_argument{"Element is not an object"}; 273 } 274 } 275 276 /** 277 * Verifies that the specified JSON element contains the expected number of 278 * properties. 279 * 280 * Throws an invalid_argument exception if the element contains a different 281 * number of properties. This indicates the element contains an invalid 282 * property. 283 * 284 * @param element JSON element 285 * @param expectedCount expected number of properties in element 286 */ 287 inline void verifyPropertyCount(const nlohmann::json& element, 288 unsigned int expectedCount) 289 { 290 if (element.size() != expectedCount) 291 { 292 throw std::invalid_argument{"Element contains an invalid property"}; 293 } 294 } 295 296 namespace internal 297 { 298 299 /** 300 * Expands any variables that appear in the specified string value. 301 * 302 * Does nothing if the variables map is empty or the value contains no 303 * variables. 304 * 305 * Throws an invalid_argument exception if a variable occurs in the value that 306 * does not exist in the variables map. 307 * 308 * @param value string value in which to perform variable expansion 309 * @param variables variables map containing variable values 310 */ 311 void expandVariables(std::string& value, 312 const std::map<std::string, std::string>& variables); 313 314 } // namespace internal 315 316 } // namespace phosphor::power::json_parser_utils 317