xref: /openbmc/phosphor-power/json_parser_utils.hpp (revision 8873f428276818761348b4091574334870ae51a7)
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
getRequiredProperty(const nlohmann::json & element,const std::string & property)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 a 16-bit unsigned integer.
233  *
234  * Returns the corresponding C++ uint16_t 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 uint16_t value
241  */
242 uint16_t parseUint16(
243     const nlohmann::json& element,
244     const std::map<std::string, std::string>& variables = NO_VARIABLES);
245 
246 /**
247  * Parses a JSON element containing an unsigned integer.
248  *
249  * Returns the corresponding C++ unsigned int value.
250  *
251  * Throws an exception if parsing fails.
252  *
253  * @param element JSON element
254  * @param variables variables map used to expand variables in element value
255  * @return unsigned int value
256  */
257 unsigned int parseUnsignedInteger(
258     const nlohmann::json& element,
259     const std::map<std::string, std::string>& variables = NO_VARIABLES);
260 
261 /**
262  * Verifies that the specified JSON element is a JSON array.
263  *
264  * Throws an invalid_argument exception if the element is not an array.
265  *
266  * @param element JSON element
267  */
verifyIsArray(const nlohmann::json & element)268 inline void verifyIsArray(const nlohmann::json& element)
269 {
270     if (!element.is_array())
271     {
272         throw std::invalid_argument{"Element is not an array"};
273     }
274 }
275 
276 /**
277  * Verifies that the specified JSON element is a JSON object.
278  *
279  * Throws an invalid_argument exception if the element is not an object.
280  *
281  * @param element JSON element
282  */
verifyIsObject(const nlohmann::json & element)283 inline void verifyIsObject(const nlohmann::json& element)
284 {
285     if (!element.is_object())
286     {
287         throw std::invalid_argument{"Element is not an object"};
288     }
289 }
290 
291 /**
292  * Verifies that the specified JSON element contains the expected number of
293  * properties.
294  *
295  * Throws an invalid_argument exception if the element contains a different
296  * number of properties.  This indicates the element contains an invalid
297  * property.
298  *
299  * @param element JSON element
300  * @param expectedCount expected number of properties in element
301  */
verifyPropertyCount(const nlohmann::json & element,unsigned int expectedCount)302 inline void verifyPropertyCount(const nlohmann::json& element,
303                                 unsigned int expectedCount)
304 {
305     if (element.size() != expectedCount)
306     {
307         throw std::invalid_argument{"Element contains an invalid property"};
308     }
309 }
310 
311 namespace internal
312 {
313 
314 /**
315  * Expands any variables that appear in the specified string value.
316  *
317  * Does nothing if the variables map is empty or the value contains no
318  * variables.
319  *
320  * Throws an invalid_argument exception if a variable occurs in the value that
321  * does not exist in the variables map.
322  *
323  * @param value string value in which to perform variable expansion
324  * @param variables variables map containing variable values
325  */
326 void expandVariables(std::string& value,
327                      const std::map<std::string, std::string>& variables);
328 
329 } // namespace internal
330 
331 } // namespace phosphor::power::json_parser_utils
332