]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/json.h
4eba91c27204d39952eb7bc726aa50ef36cf9363
[thirdparty/systemd.git] / src / shared / json.h
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #pragma once
4
5 #include <stdbool.h>
6 #include <stddef.h>
7 #include <stdint.h>
8
9 #include "macro.h"
10 #include "string-util.h"
11 #include "util.h"
12
13 /*
14 In case you wonder why we have our own JSON implementation, here are a couple of reasons why this implementation has
15 benefits over various other implementatins:
16
17 - We need support for 64bit signed and unsigned integers, i.e. the full 64,5bit range of -9223372036854775808…18446744073709551615
18 - All our variants are immutable after creation
19 - Special values such as true, false, zero, null, empty strings, empty array, empty objects require zero dynamic memory
20 - Progressive parsing
21 - Our integer/real type implicitly converts, but only if that's safe and loss-lessly possible
22 - There's a "builder" for putting together objects easily in varargs function calls
23 - There's a "dispatcher" for mapping objects to C data structures
24 - Every variant optionally carries parsing location information, which simplifies debugging and parse log error generation
25 - Formatter has color, line, column support
26
27 Limitations:
28 - Doesn't allow embedded NUL in strings
29 - Can't store integers outside of the -9223372036854775808…18446744073709551615 range (it will use 'long double' for
30 values outside this range, which is lossy)
31 - Can't store negative zero (will be treated identical to positive zero, and not retained across serialization)
32 - Can't store non-integer numbers that can't be stored in "long double" losslessly
33 - Allows creation and parsing of objects with duplicate keys. The "dispatcher" will refuse them however. This means
34 we can parse and pass around such objects, but will carefully refuse them when we convert them into our own data.
35
36 (These limitations should be pretty much in line with those of other JSON implementations, in fact might be less
37 limiting in most cases even.)
38 */
39
40 typedef struct JsonVariant JsonVariant;
41
42 typedef enum JsonVariantType {
43 JSON_VARIANT_STRING,
44 JSON_VARIANT_INTEGER,
45 JSON_VARIANT_UNSIGNED,
46 JSON_VARIANT_REAL,
47 JSON_VARIANT_NUMBER, /* This a pseudo-type: we can never create variants of this type, but we use it as wildcard check for the above three types */
48 JSON_VARIANT_BOOLEAN,
49 JSON_VARIANT_ARRAY,
50 JSON_VARIANT_OBJECT,
51 JSON_VARIANT_NULL,
52 _JSON_VARIANT_TYPE_MAX,
53 _JSON_VARIANT_TYPE_INVALID = -1
54 } JsonVariantType;
55
56 int json_variant_new_stringn(JsonVariant **ret, const char *s, size_t n);
57 int json_variant_new_integer(JsonVariant **ret, intmax_t i);
58 int json_variant_new_unsigned(JsonVariant **ret, uintmax_t u);
59 int json_variant_new_real(JsonVariant **ret, long double d);
60 int json_variant_new_boolean(JsonVariant **ret, bool b);
61 int json_variant_new_array(JsonVariant **ret, JsonVariant **array, size_t n);
62 int json_variant_new_array_bytes(JsonVariant **ret, const void *p, size_t n);
63 int json_variant_new_array_strv(JsonVariant **ret, char **l);
64 int json_variant_new_object(JsonVariant **ret, JsonVariant **array, size_t n);
65 int json_variant_new_null(JsonVariant **ret);
66
67 static inline int json_variant_new_string(JsonVariant **ret, const char *s) {
68 return json_variant_new_stringn(ret, s, strlen_ptr(s));
69 }
70
71 JsonVariant *json_variant_ref(JsonVariant *v);
72 JsonVariant *json_variant_unref(JsonVariant *v);
73 void json_variant_unref_many(JsonVariant **array, size_t n);
74
75 DEFINE_TRIVIAL_CLEANUP_FUNC(JsonVariant *, json_variant_unref);
76
77 const char *json_variant_string(JsonVariant *v);
78 intmax_t json_variant_integer(JsonVariant *v);
79 uintmax_t json_variant_unsigned(JsonVariant *v);
80 long double json_variant_real(JsonVariant *v);
81 bool json_variant_boolean(JsonVariant *v);
82
83 JsonVariantType json_variant_type(JsonVariant *v);
84 bool json_variant_has_type(JsonVariant *v, JsonVariantType type);
85
86 static inline bool json_variant_is_string(JsonVariant *v) {
87 return json_variant_has_type(v, JSON_VARIANT_STRING);
88 }
89
90 static inline bool json_variant_is_integer(JsonVariant *v) {
91 return json_variant_has_type(v, JSON_VARIANT_INTEGER);
92 }
93
94 static inline bool json_variant_is_unsigned(JsonVariant *v) {
95 return json_variant_has_type(v, JSON_VARIANT_UNSIGNED);
96 }
97
98 static inline bool json_variant_is_real(JsonVariant *v) {
99 return json_variant_has_type(v, JSON_VARIANT_REAL);
100 }
101
102 static inline bool json_variant_is_number(JsonVariant *v) {
103 return json_variant_has_type(v, JSON_VARIANT_NUMBER);
104 }
105
106 static inline bool json_variant_is_boolean(JsonVariant *v) {
107 return json_variant_has_type(v, JSON_VARIANT_BOOLEAN);
108 }
109
110 static inline bool json_variant_is_array(JsonVariant *v) {
111 return json_variant_has_type(v, JSON_VARIANT_ARRAY);
112 }
113
114 static inline bool json_variant_is_object(JsonVariant *v) {
115 return json_variant_has_type(v, JSON_VARIANT_OBJECT);
116 }
117
118 static inline bool json_variant_is_null(JsonVariant *v) {
119 return json_variant_has_type(v, JSON_VARIANT_NULL);
120 }
121
122 bool json_variant_is_negative(JsonVariant *v);
123
124 size_t json_variant_elements(JsonVariant *v);
125 JsonVariant *json_variant_by_index(JsonVariant *v, size_t index);
126 JsonVariant *json_variant_by_key(JsonVariant *v, const char *key);
127 JsonVariant *json_variant_by_key_full(JsonVariant *v, const char *key, JsonVariant **ret_key);
128
129 bool json_variant_equal(JsonVariant *a, JsonVariant *b);
130
131 struct json_variant_foreach_state {
132 JsonVariant *variant;
133 size_t idx;
134 };
135
136 #define JSON_VARIANT_ARRAY_FOREACH(i, v) \
137 for (struct json_variant_foreach_state _state = { (v), 0 }; \
138 _state.idx < json_variant_elements(_state.variant) && \
139 ({ i = json_variant_by_index(_state.variant, _state.idx); \
140 true; }); \
141 _state.idx++)
142
143 #define JSON_VARIANT_OBJECT_FOREACH(k, e, v) \
144 for (struct json_variant_foreach_state _state = { (v), 0 }; \
145 _state.idx < json_variant_elements(_state.variant) && \
146 ({ k = json_variant_by_index(_state.variant, _state.idx); \
147 e = json_variant_by_index(_state.variant, _state.idx + 1); \
148 true; }); \
149 _state.idx += 2)
150
151 int json_variant_get_source(JsonVariant *v, const char **ret_source, unsigned *ret_line, unsigned *ret_column);
152
153 typedef enum JsonFormatFlags {
154 JSON_FORMAT_NEWLINE = 1 << 0, /* suffix with newline */
155 JSON_FORMAT_PRETTY = 1 << 1, /* add internal whitespace to appeal to human readers */
156 JSON_FORMAT_COLOR = 1 << 2, /* insert ANSI color sequences */
157 JSON_FORMAT_COLOR_AUTO = 1 << 3, /* insetr ANSI color sequences if colors_enabled() says so */
158 JSON_FORMAT_SOURCE = 1 << 4, /* prefix with source filename/line/column */
159 JSON_FORMAT_SSE = 1 << 5, /* prefix/suffix with W3C server-sent events */
160 JSON_FORMAT_SEQ = 1 << 6, /* prefix/suffix with RFC 7464 application/json-seq */
161 } JsonFormatFlags;
162
163 int json_variant_format(JsonVariant *v, JsonFormatFlags flags, char **ret);
164 void json_variant_dump(JsonVariant *v, JsonFormatFlags flags, FILE *f, const char *prefix);
165
166 int json_parse(const char *string, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column);
167 int json_parse_continue(const char **p, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column);
168 int json_parse_file(FILE *f, const char *path, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column);
169
170 enum {
171 _JSON_BUILD_STRING,
172 _JSON_BUILD_INTEGER,
173 _JSON_BUILD_UNSIGNED,
174 _JSON_BUILD_REAL,
175 _JSON_BUILD_BOOLEAN,
176 _JSON_BUILD_ARRAY_BEGIN,
177 _JSON_BUILD_ARRAY_END,
178 _JSON_BUILD_OBJECT_BEGIN,
179 _JSON_BUILD_OBJECT_END,
180 _JSON_BUILD_PAIR,
181 _JSON_BUILD_PAIR_CONDITION,
182 _JSON_BUILD_NULL,
183 _JSON_BUILD_VARIANT,
184 _JSON_BUILD_LITERAL,
185 _JSON_BUILD_STRV,
186 _JSON_BUILD_MAX,
187 };
188
189 #define JSON_BUILD_STRING(s) _JSON_BUILD_STRING, ({ const char *_x = s; _x; })
190 #define JSON_BUILD_INTEGER(i) _JSON_BUILD_INTEGER, ({ intmax_t _x = i; _x; })
191 #define JSON_BUILD_UNSIGNED(u) _JSON_BUILD_UNSIGNED, ({ uintmax_t _x = u; _x; })
192 #define JSON_BUILD_REAL(d) _JSON_BUILD_REAL, ({ long double _x = d; _x; })
193 #define JSON_BUILD_BOOLEAN(b) _JSON_BUILD_BOOLEAN, ({ bool _x = b; _x; })
194 #define JSON_BUILD_ARRAY(...) _JSON_BUILD_ARRAY_BEGIN, __VA_ARGS__, _JSON_BUILD_ARRAY_END
195 #define JSON_BUILD_OBJECT(...) _JSON_BUILD_OBJECT_BEGIN, __VA_ARGS__, _JSON_BUILD_OBJECT_END
196 #define JSON_BUILD_PAIR(n, ...) _JSON_BUILD_PAIR, ({ const char *_x = n; _x; }), __VA_ARGS__
197 #define JSON_BUILD_PAIR_CONDITION(c, n, ...) _JSON_BUILD_PAIR_CONDITION, ({ bool _x = c; _x; }), ({ const char *_x = n; _x; }), __VA_ARGS__
198 #define JSON_BUILD_NULL _JSON_BUILD_NULL
199 #define JSON_BUILD_VARIANT(v) _JSON_BUILD_VARIANT, ({ JsonVariant *_x = v; _x; })
200 #define JSON_BUILD_LITERAL(l) _JSON_BUILD_LITERAL, ({ const char *_x = l; _x; })
201 #define JSON_BUILD_STRV(l) _JSON_BUILD_STRV, ({ char **_x = l; _x; })
202
203 int json_build(JsonVariant **ret, ...);
204 int json_buildv(JsonVariant **ret, va_list ap);
205
206 /* A bitmask of flags used by the dispatch logic. Note that this is a combined bit mask, that is generated from the bit
207 * mask originally passed into json_dispatch(), the individual bitmask associated with the static JsonDispatch callout
208 * entry, as well the bitmask specified for json_log() calls */
209 typedef enum JsonDispatchFlags {
210 /* The following three may be set in JsonDispatch's .flags field or the json_dispatch() flags parameter */
211 JSON_PERMISSIVE = 1 << 0, /* Shall parsing errors be considered fatal for this property? */
212 JSON_MANDATORY = 1 << 1, /* Should existance of this property be mandatory? */
213 JSON_LOG = 1 << 2, /* Should the parser log about errors? */
214
215 /* The following two may be passed into log_json() in addition to the three above */
216 JSON_DEBUG = 1 << 3, /* Indicates that this log message is a debug message */
217 JSON_WARNING = 1 << 4, /* Indicates that this log message is a warning message */
218 } JsonDispatchFlags;
219
220 typedef int (*JsonDispatchCallback)(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
221
222 typedef struct JsonDispatch {
223 const char *name;
224 JsonVariantType type;
225 JsonDispatchCallback callback;
226 size_t offset;
227 JsonDispatchFlags flags;
228 } JsonDispatch;
229
230 int json_dispatch(JsonVariant *v, const JsonDispatch table[], JsonDispatchCallback bad, JsonDispatchFlags flags, void *userdata);
231
232 int json_dispatch_string(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
233 int json_dispatch_strv(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
234 int json_dispatch_boolean(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
235 int json_dispatch_tristate(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
236 int json_dispatch_variant(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
237 int json_dispatch_integer(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
238 int json_dispatch_unsigned(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
239 int json_dispatch_uint32(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
240 int json_dispatch_int32(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
241
242 assert_cc(sizeof(uintmax_t) == sizeof(uint64_t))
243 #define json_dispatch_uint64 json_dispatch_unsigned
244
245 assert_cc(sizeof(intmax_t) == sizeof(int64_t))
246 #define json_dispatch_int64 json_dispatch_integer
247
248 static inline int json_dispatch_level(JsonDispatchFlags flags) {
249
250 /* Did the user request no logging? If so, then never log higher than LOG_DEBUG. Also, if this is marked as
251 * debug message, then also log at debug level. */
252
253 if (!(flags & JSON_LOG) ||
254 (flags & JSON_DEBUG))
255 return LOG_DEBUG;
256
257 /* Are we invoked in permissive mode, or is this explicitly marked as warning message? Then this should be
258 * printed at LOG_WARNING */
259 if (flags & (JSON_PERMISSIVE|JSON_WARNING))
260 return LOG_WARNING;
261
262 /* Otherwise it's an error. */
263 return LOG_ERR;
264 }
265
266 int json_log_internal(JsonVariant *variant, int level, int error, const char *file, int line, const char *func, const char *format, ...) _printf_(7, 8);
267
268 #define json_log(variant, flags, error, ...) \
269 ({ \
270 int _level = json_dispatch_level(flags), _e = (error); \
271 (log_get_max_level() >= LOG_PRI(_level)) \
272 ? json_log_internal(variant, _level, _e, __FILE__, __LINE__, __func__, __VA_ARGS__) \
273 : -abs(_e); \
274 })
275
276 #define JSON_VARIANT_STRING_CONST(x) _JSON_VARIANT_STRING_CONST(UNIQ, (x))
277
278 #define _JSON_VARIANT_STRING_CONST(xq, x) \
279 ({ \
280 _align_(2) static const char UNIQ_T(json_string_const, xq)[] = (x); \
281 assert((((uintptr_t) UNIQ_T(json_string_const, xq)) & 1) == 0); \
282 (JsonVariant*) ((uintptr_t) UNIQ_T(json_string_const, xq) + 1); \
283 })
284
285 const char *json_variant_type_to_string(JsonVariantType t);
286 JsonVariantType json_variant_type_from_string(const char *s);