16a957f6fSShawn McCarney /** 26a957f6fSShawn McCarney * Copyright © 2024 IBM Corporation 36a957f6fSShawn McCarney * 46a957f6fSShawn McCarney * Licensed under the Apache License, Version 2.0 (the "License"); 56a957f6fSShawn McCarney * you may not use this file except in compliance with the License. 66a957f6fSShawn McCarney * You may obtain a copy of the License at 76a957f6fSShawn McCarney * 86a957f6fSShawn McCarney * http://www.apache.org/licenses/LICENSE-2.0 96a957f6fSShawn McCarney * 106a957f6fSShawn McCarney * Unless required by applicable law or agreed to in writing, software 116a957f6fSShawn McCarney * distributed under the License is distributed on an "AS IS" BASIS, 126a957f6fSShawn McCarney * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 136a957f6fSShawn McCarney * See the License for the specific language governing permissions and 146a957f6fSShawn McCarney * limitations under the License. 156a957f6fSShawn McCarney */ 166a957f6fSShawn McCarney #pragma once 176a957f6fSShawn McCarney 186a957f6fSShawn McCarney #include "rail.hpp" 196a957f6fSShawn McCarney 206a957f6fSShawn McCarney #include <nlohmann/json.hpp> 216a957f6fSShawn McCarney 226a957f6fSShawn McCarney #include <cstdint> 236a957f6fSShawn McCarney #include <filesystem> 24*906cc3f3SShawn McCarney #include <memory> 256a957f6fSShawn McCarney #include <stdexcept> 266a957f6fSShawn McCarney #include <string> 276a957f6fSShawn McCarney #include <vector> 286a957f6fSShawn McCarney 296a957f6fSShawn McCarney namespace phosphor::power::sequencer::config_file_parser 306a957f6fSShawn McCarney { 316a957f6fSShawn McCarney 326a957f6fSShawn McCarney /** 336a957f6fSShawn McCarney * Parses the specified JSON configuration file. 346a957f6fSShawn McCarney * 356a957f6fSShawn McCarney * Returns the corresponding C++ Rail objects. 366a957f6fSShawn McCarney * 376a957f6fSShawn McCarney * Throws a ConfigFileParserError if an error occurs. 386a957f6fSShawn McCarney * 396a957f6fSShawn McCarney * @param pathName configuration file path name 406a957f6fSShawn McCarney * @return vector of Rail objects 416a957f6fSShawn McCarney */ 426a957f6fSShawn McCarney std::vector<std::unique_ptr<Rail>> parse(const std::filesystem::path& pathName); 436a957f6fSShawn McCarney 446a957f6fSShawn McCarney /* 456a957f6fSShawn McCarney * Internal implementation details for parse() 466a957f6fSShawn McCarney */ 476a957f6fSShawn McCarney namespace internal 486a957f6fSShawn McCarney { 496a957f6fSShawn McCarney 506a957f6fSShawn McCarney /** 516a957f6fSShawn McCarney * Returns the specified property of the specified JSON element. 526a957f6fSShawn McCarney * 536a957f6fSShawn McCarney * Throws an invalid_argument exception if the property does not exist. 546a957f6fSShawn McCarney * 556a957f6fSShawn McCarney * @param element JSON element 566a957f6fSShawn McCarney * @param property property name 576a957f6fSShawn McCarney */ 586a957f6fSShawn McCarney #pragma GCC diagnostic push 596a957f6fSShawn McCarney #if __GNUC__ == 13 606a957f6fSShawn McCarney #pragma GCC diagnostic ignored "-Wdangling-reference" 616a957f6fSShawn McCarney #endif 626a957f6fSShawn McCarney inline const nlohmann::json& getRequiredProperty(const nlohmann::json& element, 636a957f6fSShawn McCarney const std::string& property) 646a957f6fSShawn McCarney { 656a957f6fSShawn McCarney auto it = element.find(property); 666a957f6fSShawn McCarney if (it == element.end()) 676a957f6fSShawn McCarney { 686a957f6fSShawn McCarney throw std::invalid_argument{"Required property missing: " + property}; 696a957f6fSShawn McCarney } 706a957f6fSShawn McCarney return *it; 716a957f6fSShawn McCarney } 726a957f6fSShawn McCarney #pragma GCC diagnostic pop 736a957f6fSShawn McCarney 746a957f6fSShawn McCarney /** 756a957f6fSShawn McCarney * Parses a JSON element containing a boolean. 766a957f6fSShawn McCarney * 776a957f6fSShawn McCarney * Returns the corresponding C++ boolean value. 786a957f6fSShawn McCarney * 796a957f6fSShawn McCarney * Throws an exception if parsing fails. 806a957f6fSShawn McCarney * 816a957f6fSShawn McCarney * @param element JSON element 826a957f6fSShawn McCarney * @return boolean value 836a957f6fSShawn McCarney */ 846a957f6fSShawn McCarney inline bool parseBoolean(const nlohmann::json& element) 856a957f6fSShawn McCarney { 866a957f6fSShawn McCarney // Verify element contains a boolean 876a957f6fSShawn McCarney if (!element.is_boolean()) 886a957f6fSShawn McCarney { 896a957f6fSShawn McCarney throw std::invalid_argument{"Element is not a boolean"}; 906a957f6fSShawn McCarney } 916a957f6fSShawn McCarney return element.get<bool>(); 926a957f6fSShawn McCarney } 936a957f6fSShawn McCarney 946a957f6fSShawn McCarney /** 956a957f6fSShawn McCarney * Parses a JSON element containing a GPIO. 966a957f6fSShawn McCarney * 976a957f6fSShawn McCarney * Returns the corresponding C++ GPIO object. 986a957f6fSShawn McCarney * 996a957f6fSShawn McCarney * Throws an exception if parsing fails. 1006a957f6fSShawn McCarney * 1016a957f6fSShawn McCarney * @param element JSON element 1026a957f6fSShawn McCarney * @return GPIO object 1036a957f6fSShawn McCarney */ 1046a957f6fSShawn McCarney GPIO parseGPIO(const nlohmann::json& element); 1056a957f6fSShawn McCarney 1066a957f6fSShawn McCarney /** 1076a957f6fSShawn McCarney * Parses a JSON element containing a rail. 1086a957f6fSShawn McCarney * 1096a957f6fSShawn McCarney * Returns the corresponding C++ Rail object. 1106a957f6fSShawn McCarney * 1116a957f6fSShawn McCarney * Throws an exception if parsing fails. 1126a957f6fSShawn McCarney * 1136a957f6fSShawn McCarney * @param element JSON element 1146a957f6fSShawn McCarney * @return Rail object 1156a957f6fSShawn McCarney */ 1166a957f6fSShawn McCarney std::unique_ptr<Rail> parseRail(const nlohmann::json& element); 1176a957f6fSShawn McCarney 1186a957f6fSShawn McCarney /** 1196a957f6fSShawn McCarney * Parses a JSON element containing an array of rails. 1206a957f6fSShawn McCarney * 1216a957f6fSShawn McCarney * Returns the corresponding C++ Rail objects. 1226a957f6fSShawn McCarney * 1236a957f6fSShawn McCarney * Throws an exception if parsing fails. 1246a957f6fSShawn McCarney * 1256a957f6fSShawn McCarney * @param element JSON element 1266a957f6fSShawn McCarney * @return vector of Rail objects 1276a957f6fSShawn McCarney */ 1286a957f6fSShawn McCarney std::vector<std::unique_ptr<Rail>> 1296a957f6fSShawn McCarney parseRailArray(const nlohmann::json& element); 1306a957f6fSShawn McCarney 1316a957f6fSShawn McCarney /** 1326a957f6fSShawn McCarney * Parses the JSON root element of the entire configuration file. 1336a957f6fSShawn McCarney * 1346a957f6fSShawn McCarney * Returns the corresponding C++ Rail objects. 1356a957f6fSShawn McCarney * 1366a957f6fSShawn McCarney * Throws an exception if parsing fails. 1376a957f6fSShawn McCarney * 1386a957f6fSShawn McCarney * @param element JSON element 1396a957f6fSShawn McCarney * @return vector of Rail objects 1406a957f6fSShawn McCarney */ 1416a957f6fSShawn McCarney std::vector<std::unique_ptr<Rail>> parseRoot(const nlohmann::json& element); 1426a957f6fSShawn McCarney 1436a957f6fSShawn McCarney /** 1446a957f6fSShawn McCarney * Parses a JSON element containing a string. 1456a957f6fSShawn McCarney * 1466a957f6fSShawn McCarney * Returns the corresponding C++ string. 1476a957f6fSShawn McCarney * 1486a957f6fSShawn McCarney * Throws an exception if parsing fails. 1496a957f6fSShawn McCarney * 1506a957f6fSShawn McCarney * @param element JSON element 1516a957f6fSShawn McCarney * @param isEmptyValid indicates whether an empty string value is valid 1526a957f6fSShawn McCarney * @return string value 1536a957f6fSShawn McCarney */ 1546a957f6fSShawn McCarney inline std::string parseString(const nlohmann::json& element, 1556a957f6fSShawn McCarney bool isEmptyValid = false) 1566a957f6fSShawn McCarney { 1576a957f6fSShawn McCarney if (!element.is_string()) 1586a957f6fSShawn McCarney { 1596a957f6fSShawn McCarney throw std::invalid_argument{"Element is not a string"}; 1606a957f6fSShawn McCarney } 1616a957f6fSShawn McCarney std::string value = element.get<std::string>(); 1626a957f6fSShawn McCarney if (value.empty() && !isEmptyValid) 1636a957f6fSShawn McCarney { 1646a957f6fSShawn McCarney throw std::invalid_argument{"Element contains an empty string"}; 1656a957f6fSShawn McCarney } 1666a957f6fSShawn McCarney return value; 1676a957f6fSShawn McCarney } 1686a957f6fSShawn McCarney 1696a957f6fSShawn McCarney /** 1706a957f6fSShawn McCarney * Parses a JSON element containing an 8-bit unsigned integer. 1716a957f6fSShawn McCarney * 1726a957f6fSShawn McCarney * Returns the corresponding C++ uint8_t value. 1736a957f6fSShawn McCarney * 1746a957f6fSShawn McCarney * Throws an exception if parsing fails. 1756a957f6fSShawn McCarney * 1766a957f6fSShawn McCarney * @param element JSON element 1776a957f6fSShawn McCarney * @return uint8_t value 1786a957f6fSShawn McCarney */ 1796a957f6fSShawn McCarney inline uint8_t parseUint8(const nlohmann::json& element) 1806a957f6fSShawn McCarney { 1816a957f6fSShawn McCarney // Verify element contains an integer 1826a957f6fSShawn McCarney if (!element.is_number_integer()) 1836a957f6fSShawn McCarney { 1846a957f6fSShawn McCarney throw std::invalid_argument{"Element is not an integer"}; 1856a957f6fSShawn McCarney } 1866a957f6fSShawn McCarney int value = element.get<int>(); 1876a957f6fSShawn McCarney if ((value < 0) || (value > UINT8_MAX)) 1886a957f6fSShawn McCarney { 1896a957f6fSShawn McCarney throw std::invalid_argument{"Element is not an 8-bit unsigned integer"}; 1906a957f6fSShawn McCarney } 1916a957f6fSShawn McCarney return static_cast<uint8_t>(value); 1926a957f6fSShawn McCarney } 1936a957f6fSShawn McCarney 1946a957f6fSShawn McCarney /** 1956a957f6fSShawn McCarney * Parses a JSON element containing an unsigned integer. 1966a957f6fSShawn McCarney * 1976a957f6fSShawn McCarney * Returns the corresponding C++ unsigned int value. 1986a957f6fSShawn McCarney * 1996a957f6fSShawn McCarney * Throws an exception if parsing fails. 2006a957f6fSShawn McCarney * 2016a957f6fSShawn McCarney * @param element JSON element 2026a957f6fSShawn McCarney * @return unsigned int value 2036a957f6fSShawn McCarney */ 2046a957f6fSShawn McCarney inline unsigned int parseUnsignedInteger(const nlohmann::json& element) 2056a957f6fSShawn McCarney { 2066a957f6fSShawn McCarney // Verify element contains an unsigned integer 2076a957f6fSShawn McCarney if (!element.is_number_unsigned()) 2086a957f6fSShawn McCarney { 2096a957f6fSShawn McCarney throw std::invalid_argument{"Element is not an unsigned integer"}; 2106a957f6fSShawn McCarney } 2116a957f6fSShawn McCarney return element.get<unsigned int>(); 2126a957f6fSShawn McCarney } 2136a957f6fSShawn McCarney 2146a957f6fSShawn McCarney /** 2156a957f6fSShawn McCarney * Verifies that the specified JSON element is a JSON array. 2166a957f6fSShawn McCarney * 2176a957f6fSShawn McCarney * Throws an invalid_argument exception if the element is not an array. 2186a957f6fSShawn McCarney * 2196a957f6fSShawn McCarney * @param element JSON element 2206a957f6fSShawn McCarney */ 2216a957f6fSShawn McCarney inline void verifyIsArray(const nlohmann::json& element) 2226a957f6fSShawn McCarney { 2236a957f6fSShawn McCarney if (!element.is_array()) 2246a957f6fSShawn McCarney { 2256a957f6fSShawn McCarney throw std::invalid_argument{"Element is not an array"}; 2266a957f6fSShawn McCarney } 2276a957f6fSShawn McCarney } 2286a957f6fSShawn McCarney 2296a957f6fSShawn McCarney /** 2306a957f6fSShawn McCarney * Verifies that the specified JSON element is a JSON object. 2316a957f6fSShawn McCarney * 2326a957f6fSShawn McCarney * Throws an invalid_argument exception if the element is not an object. 2336a957f6fSShawn McCarney * 2346a957f6fSShawn McCarney * @param element JSON element 2356a957f6fSShawn McCarney */ 2366a957f6fSShawn McCarney inline void verifyIsObject(const nlohmann::json& element) 2376a957f6fSShawn McCarney { 2386a957f6fSShawn McCarney if (!element.is_object()) 2396a957f6fSShawn McCarney { 2406a957f6fSShawn McCarney throw std::invalid_argument{"Element is not an object"}; 2416a957f6fSShawn McCarney } 2426a957f6fSShawn McCarney } 2436a957f6fSShawn McCarney 2446a957f6fSShawn McCarney /** 2456a957f6fSShawn McCarney * Verifies that the specified JSON element contains the expected number of 2466a957f6fSShawn McCarney * properties. 2476a957f6fSShawn McCarney * 2486a957f6fSShawn McCarney * Throws an invalid_argument exception if the element contains a different 2496a957f6fSShawn McCarney * number of properties. This indicates the element contains an invalid 2506a957f6fSShawn McCarney * property. 2516a957f6fSShawn McCarney * 2526a957f6fSShawn McCarney * @param element JSON element 2536a957f6fSShawn McCarney * @param expectedCount expected number of properties in element 2546a957f6fSShawn McCarney */ 2556a957f6fSShawn McCarney inline void verifyPropertyCount(const nlohmann::json& element, 2566a957f6fSShawn McCarney unsigned int expectedCount) 2576a957f6fSShawn McCarney { 2586a957f6fSShawn McCarney if (element.size() != expectedCount) 2596a957f6fSShawn McCarney { 2606a957f6fSShawn McCarney throw std::invalid_argument{"Element contains an invalid property"}; 2616a957f6fSShawn McCarney } 2626a957f6fSShawn McCarney } 2636a957f6fSShawn McCarney 2646a957f6fSShawn McCarney } // namespace internal 2656a957f6fSShawn McCarney 2666a957f6fSShawn McCarney } // namespace phosphor::power::sequencer::config_file_parser 267