blob: 6dba42b0eaa1f60c6d674ad052a72375135a6bd4 [file] [log] [blame]
Shawn McCarney38f85002025-10-31 17:59:36 -05001/**
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 <stdexcept>
22#include <string>
23#include <vector>
24
25/**
26 * @namespace json_parser_utils
27 *
28 * Contains utility functions for parsing JSON data.
29 */
30namespace phosphor::power::json_parser_utils
31{
32
33/**
34 * Returns the specified property of the specified JSON element.
35 *
36 * Throws an invalid_argument exception if the property does not exist.
37 *
38 * @param element JSON element
39 * @param property property name
40 */
41#pragma GCC diagnostic push
42#if __GNUC__ >= 13
43#pragma GCC diagnostic ignored "-Wdangling-reference"
44#endif
45inline const nlohmann::json& getRequiredProperty(const nlohmann::json& element,
46 const std::string& property)
47{
48 auto it = element.find(property);
49 if (it == element.end())
50 {
51 throw std::invalid_argument{"Required property missing: " + property};
52 }
53 return *it;
54}
55#pragma GCC diagnostic pop
56
57/**
58 * Parses a JSON element containing a bit position (from 0-7).
59 *
60 * Returns the corresponding C++ uint8_t value.
61 *
62 * Throws an exception if parsing fails.
63 *
64 * @param element JSON element
65 * @return uint8_t value
66 */
67inline uint8_t parseBitPosition(const nlohmann::json& element)
68{
69 // Verify element contains an integer
70 if (!element.is_number_integer())
71 {
72 throw std::invalid_argument{"Element is not an integer"};
73 }
74 int value = element.get<int>();
75 if ((value < 0) || (value > 7))
76 {
77 throw std::invalid_argument{"Element is not a bit position"};
78 }
79 return static_cast<uint8_t>(value);
80}
81
82/**
83 * Parses a JSON element containing a bit value (0 or 1).
84 *
85 * Returns the corresponding C++ uint8_t value.
86 *
87 * Throws an exception if parsing fails.
88 *
89 * @param element JSON element
90 * @return uint8_t value
91 */
92inline uint8_t parseBitValue(const nlohmann::json& element)
93{
94 // Verify element contains an integer
95 if (!element.is_number_integer())
96 {
97 throw std::invalid_argument{"Element is not an integer"};
98 }
99 int value = element.get<int>();
100 if ((value < 0) || (value > 1))
101 {
102 throw std::invalid_argument{"Element is not a bit value"};
103 }
104 return static_cast<uint8_t>(value);
105}
106
107/**
108 * Parses a JSON element containing a boolean.
109 *
110 * Returns the corresponding C++ boolean value.
111 *
112 * Throws an exception if parsing fails.
113 *
114 * @param element JSON element
115 * @return boolean value
116 */
117inline bool parseBoolean(const nlohmann::json& element)
118{
119 // Verify element contains a boolean
120 if (!element.is_boolean())
121 {
122 throw std::invalid_argument{"Element is not a boolean"};
123 }
124 return element.get<bool>();
125}
126
127/**
128 * Parses a JSON element containing a double (floating point number).
129 *
130 * Returns the corresponding C++ double value.
131 *
132 * Throws an exception if parsing fails.
133 *
134 * @param element JSON element
135 * @return double value
136 */
137inline double parseDouble(const nlohmann::json& element)
138{
139 // Verify element contains a number (integer or floating point)
140 if (!element.is_number())
141 {
142 throw std::invalid_argument{"Element is not a number"};
143 }
144 return element.get<double>();
145}
146
147/**
148 * Parses a JSON element containing a byte value expressed as a hexadecimal
149 * string.
150 *
151 * The JSON number data type does not support the hexadecimal format. For this
152 * reason, hexadecimal byte values are stored as strings in the configuration
153 * file.
154 *
155 * Returns the corresponding C++ uint8_t value.
156 *
157 * Throws an exception if parsing fails.
158 *
159 * @param element JSON element
160 * @return uint8_t value
161 */
162inline uint8_t parseHexByte(const nlohmann::json& element)
163{
164 if (!element.is_string())
165 {
166 throw std::invalid_argument{"Element is not a string"};
167 }
168 std::string value = element.get<std::string>();
169
170 bool isHex = (value.compare(0, 2, "0x") == 0) && (value.size() > 2) &&
171 (value.size() < 5) &&
172 (value.find_first_not_of("0123456789abcdefABCDEF", 2) ==
173 std::string::npos);
174 if (!isHex)
175 {
176 throw std::invalid_argument{"Element is not hexadecimal string"};
177 }
178 return static_cast<uint8_t>(std::stoul(value, nullptr, 0));
179}
180
181/**
182 * Parses a JSON element containing an array of byte values expressed as a
183 * hexadecimal strings.
184 *
185 * Returns the corresponding C++ uint8_t values.
186 *
187 * Throws an exception if parsing fails.
188 *
189 * @param element JSON element
190 * @return vector of uint8_t
191 */
192std::vector<uint8_t> parseHexByteArray(const nlohmann::json& element);
193
194/**
195 * Parses a JSON element containing an 8-bit signed integer.
196 *
197 * Returns the corresponding C++ int8_t value.
198 *
199 * Throws an exception if parsing fails.
200 *
201 * @param element JSON element
202 * @return int8_t value
203 */
204inline int8_t parseInt8(const nlohmann::json& element)
205{
206 // Verify element contains an integer
207 if (!element.is_number_integer())
208 {
209 throw std::invalid_argument{"Element is not an integer"};
210 }
211 int value = element.get<int>();
212 if ((value < INT8_MIN) || (value > INT8_MAX))
213 {
214 throw std::invalid_argument{"Element is not an 8-bit signed integer"};
215 }
216 return static_cast<int8_t>(value);
217}
218
219/**
220 * Parses a JSON element containing a string.
221 *
222 * Returns the corresponding C++ string.
223 *
224 * Throws an exception if parsing fails.
225 *
226 * @param element JSON element
227 * @param isEmptyValid indicates whether an empty string value is valid
228 * @return string value
229 */
230inline std::string parseString(const nlohmann::json& element,
231 bool isEmptyValid = false)
232{
233 if (!element.is_string())
234 {
235 throw std::invalid_argument{"Element is not a string"};
236 }
237 std::string value = element.get<std::string>();
238 if (value.empty() && !isEmptyValid)
239 {
240 throw std::invalid_argument{"Element contains an empty string"};
241 }
242 return value;
243}
244
245/**
246 * Parses a JSON element containing an 8-bit unsigned integer.
247 *
248 * Returns the corresponding C++ uint8_t value.
249 *
250 * Throws an exception if parsing fails.
251 *
252 * @param element JSON element
253 * @return uint8_t value
254 */
255inline uint8_t parseUint8(const nlohmann::json& element)
256{
257 // Verify element contains an integer
258 if (!element.is_number_integer())
259 {
260 throw std::invalid_argument{"Element is not an integer"};
261 }
262 int value = element.get<int>();
263 if ((value < 0) || (value > UINT8_MAX))
264 {
265 throw std::invalid_argument{"Element is not an 8-bit unsigned integer"};
266 }
267 return static_cast<uint8_t>(value);
268}
269
270/**
271 * Parses a JSON element containing an unsigned integer.
272 *
273 * Returns the corresponding C++ unsigned int value.
274 *
275 * Throws an exception if parsing fails.
276 *
277 * @param element JSON element
278 * @return unsigned int value
279 */
280inline unsigned int parseUnsignedInteger(const nlohmann::json& element)
281{
282 // Verify element contains an unsigned integer
283 if (!element.is_number_unsigned())
284 {
285 throw std::invalid_argument{"Element is not an unsigned integer"};
286 }
287 return element.get<unsigned int>();
288}
289
290/**
291 * Verifies that the specified JSON element is a JSON array.
292 *
293 * Throws an invalid_argument exception if the element is not an array.
294 *
295 * @param element JSON element
296 */
297inline void verifyIsArray(const nlohmann::json& element)
298{
299 if (!element.is_array())
300 {
301 throw std::invalid_argument{"Element is not an array"};
302 }
303}
304
305/**
306 * Verifies that the specified JSON element is a JSON object.
307 *
308 * Throws an invalid_argument exception if the element is not an object.
309 *
310 * @param element JSON element
311 */
312inline void verifyIsObject(const nlohmann::json& element)
313{
314 if (!element.is_object())
315 {
316 throw std::invalid_argument{"Element is not an object"};
317 }
318}
319
320/**
321 * Verifies that the specified JSON element contains the expected number of
322 * properties.
323 *
324 * Throws an invalid_argument exception if the element contains a different
325 * number of properties. This indicates the element contains an invalid
326 * property.
327 *
328 * @param element JSON element
329 * @param expectedCount expected number of properties in element
330 */
331inline void verifyPropertyCount(const nlohmann::json& element,
332 unsigned int expectedCount)
333{
334 if (element.size() != expectedCount)
335 {
336 throw std::invalid_argument{"Element contains an invalid property"};
337 }
338}
339
340} // namespace phosphor::power::json_parser_utils