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