1 /** 2 * Copyright © 2024 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 "rail.hpp" 19 20 #include <nlohmann/json.hpp> 21 22 #include <cstdint> 23 #include <filesystem> 24 #include <stdexcept> 25 #include <string> 26 #include <vector> 27 28 namespace phosphor::power::sequencer::config_file_parser 29 { 30 31 /** 32 * Parses the specified JSON configuration file. 33 * 34 * Returns the corresponding C++ Rail objects. 35 * 36 * Throws a ConfigFileParserError if an error occurs. 37 * 38 * @param pathName configuration file path name 39 * @return vector of Rail objects 40 */ 41 std::vector<std::unique_ptr<Rail>> parse(const std::filesystem::path& pathName); 42 43 /* 44 * Internal implementation details for parse() 45 */ 46 namespace internal 47 { 48 49 /** 50 * Returns the specified property of the specified JSON element. 51 * 52 * Throws an invalid_argument exception if the property does not exist. 53 * 54 * @param element JSON element 55 * @param property property name 56 */ 57 #pragma GCC diagnostic push 58 #if __GNUC__ == 13 59 #pragma GCC diagnostic ignored "-Wdangling-reference" 60 #endif 61 inline const nlohmann::json& getRequiredProperty(const nlohmann::json& element, 62 const std::string& property) 63 { 64 auto it = element.find(property); 65 if (it == element.end()) 66 { 67 throw std::invalid_argument{"Required property missing: " + property}; 68 } 69 return *it; 70 } 71 #pragma GCC diagnostic pop 72 73 /** 74 * Parses a JSON element containing a boolean. 75 * 76 * Returns the corresponding C++ boolean value. 77 * 78 * Throws an exception if parsing fails. 79 * 80 * @param element JSON element 81 * @return boolean value 82 */ 83 inline bool parseBoolean(const nlohmann::json& element) 84 { 85 // Verify element contains a boolean 86 if (!element.is_boolean()) 87 { 88 throw std::invalid_argument{"Element is not a boolean"}; 89 } 90 return element.get<bool>(); 91 } 92 93 /** 94 * Parses a JSON element containing a GPIO. 95 * 96 * Returns the corresponding C++ GPIO object. 97 * 98 * Throws an exception if parsing fails. 99 * 100 * @param element JSON element 101 * @return GPIO object 102 */ 103 GPIO parseGPIO(const nlohmann::json& element); 104 105 /** 106 * Parses a JSON element containing a rail. 107 * 108 * Returns the corresponding C++ Rail object. 109 * 110 * Throws an exception if parsing fails. 111 * 112 * @param element JSON element 113 * @return Rail object 114 */ 115 std::unique_ptr<Rail> parseRail(const nlohmann::json& element); 116 117 /** 118 * Parses a JSON element containing an array of rails. 119 * 120 * Returns the corresponding C++ Rail objects. 121 * 122 * Throws an exception if parsing fails. 123 * 124 * @param element JSON element 125 * @return vector of Rail objects 126 */ 127 std::vector<std::unique_ptr<Rail>> 128 parseRailArray(const nlohmann::json& element); 129 130 /** 131 * Parses the JSON root element of the entire configuration file. 132 * 133 * Returns the corresponding C++ Rail objects. 134 * 135 * Throws an exception if parsing fails. 136 * 137 * @param element JSON element 138 * @return vector of Rail objects 139 */ 140 std::vector<std::unique_ptr<Rail>> parseRoot(const nlohmann::json& element); 141 142 /** 143 * Parses a JSON element containing a string. 144 * 145 * Returns the corresponding C++ string. 146 * 147 * Throws an exception if parsing fails. 148 * 149 * @param element JSON element 150 * @param isEmptyValid indicates whether an empty string value is valid 151 * @return string value 152 */ 153 inline std::string parseString(const nlohmann::json& element, 154 bool isEmptyValid = false) 155 { 156 if (!element.is_string()) 157 { 158 throw std::invalid_argument{"Element is not a string"}; 159 } 160 std::string value = element.get<std::string>(); 161 if (value.empty() && !isEmptyValid) 162 { 163 throw std::invalid_argument{"Element contains an empty string"}; 164 } 165 return value; 166 } 167 168 /** 169 * Parses a JSON element containing an 8-bit unsigned integer. 170 * 171 * Returns the corresponding C++ uint8_t value. 172 * 173 * Throws an exception if parsing fails. 174 * 175 * @param element JSON element 176 * @return uint8_t value 177 */ 178 inline uint8_t parseUint8(const nlohmann::json& element) 179 { 180 // Verify element contains an integer 181 if (!element.is_number_integer()) 182 { 183 throw std::invalid_argument{"Element is not an integer"}; 184 } 185 int value = element.get<int>(); 186 if ((value < 0) || (value > UINT8_MAX)) 187 { 188 throw std::invalid_argument{"Element is not an 8-bit unsigned integer"}; 189 } 190 return static_cast<uint8_t>(value); 191 } 192 193 /** 194 * Parses a JSON element containing an unsigned integer. 195 * 196 * Returns the corresponding C++ unsigned int value. 197 * 198 * Throws an exception if parsing fails. 199 * 200 * @param element JSON element 201 * @return unsigned int value 202 */ 203 inline unsigned int parseUnsignedInteger(const nlohmann::json& element) 204 { 205 // Verify element contains an unsigned integer 206 if (!element.is_number_unsigned()) 207 { 208 throw std::invalid_argument{"Element is not an unsigned integer"}; 209 } 210 return element.get<unsigned int>(); 211 } 212 213 /** 214 * Verifies that the specified JSON element is a JSON array. 215 * 216 * Throws an invalid_argument exception if the element is not an array. 217 * 218 * @param element JSON element 219 */ 220 inline void verifyIsArray(const nlohmann::json& element) 221 { 222 if (!element.is_array()) 223 { 224 throw std::invalid_argument{"Element is not an array"}; 225 } 226 } 227 228 /** 229 * Verifies that the specified JSON element is a JSON object. 230 * 231 * Throws an invalid_argument exception if the element is not an object. 232 * 233 * @param element JSON element 234 */ 235 inline void verifyIsObject(const nlohmann::json& element) 236 { 237 if (!element.is_object()) 238 { 239 throw std::invalid_argument{"Element is not an object"}; 240 } 241 } 242 243 /** 244 * Verifies that the specified JSON element contains the expected number of 245 * properties. 246 * 247 * Throws an invalid_argument exception if the element contains a different 248 * number of properties. This indicates the element contains an invalid 249 * property. 250 * 251 * @param element JSON element 252 * @param expectedCount expected number of properties in element 253 */ 254 inline void verifyPropertyCount(const nlohmann::json& element, 255 unsigned int expectedCount) 256 { 257 if (element.size() != expectedCount) 258 { 259 throw std::invalid_argument{"Element contains an invalid property"}; 260 } 261 } 262 263 } // namespace internal 264 265 } // namespace phosphor::power::sequencer::config_file_parser 266