]>
Commit | Line | Data |
---|---|---|
cd0b6c53 LP |
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 | enum { | |
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_SOURCE = 1 << 3, /* prefix with source filename/line/column */ | |
158 | JSON_FORMAT_SSE = 1 << 4, /* prefix/suffix with W3C server-sent events */ | |
159 | JSON_FORMAT_SEQ = 1 << 5, /* prefix/suffix with RFC 7464 application/json-seq */ | |
160 | }; | |
161 | ||
162 | int json_variant_format(JsonVariant *v, unsigned flags, char **ret); | |
163 | void json_variant_dump(JsonVariant *v, unsigned flags, FILE *f, const char *prefix); | |
164 | ||
165 | int json_parse(const char *string, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column); | |
166 | int json_parse_continue(const char **p, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column); | |
167 | int json_parse_file(FILE *f, const char *path, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column); | |
168 | ||
169 | enum { | |
170 | _JSON_BUILD_STRING, | |
171 | _JSON_BUILD_INTEGER, | |
172 | _JSON_BUILD_UNSIGNED, | |
173 | _JSON_BUILD_REAL, | |
174 | _JSON_BUILD_BOOLEAN, | |
175 | _JSON_BUILD_ARRAY_BEGIN, | |
176 | _JSON_BUILD_ARRAY_END, | |
177 | _JSON_BUILD_OBJECT_BEGIN, | |
178 | _JSON_BUILD_OBJECT_END, | |
179 | _JSON_BUILD_PAIR, | |
180 | _JSON_BUILD_NULL, | |
181 | _JSON_BUILD_VARIANT, | |
182 | _JSON_BUILD_LITERAL, | |
183 | _JSON_BUILD_STRV, | |
184 | _JSON_BUILD_MAX, | |
185 | }; | |
186 | ||
187 | #define JSON_BUILD_STRING(s) _JSON_BUILD_STRING, ({ const char *_x = s; _x; }) | |
188 | #define JSON_BUILD_INTEGER(i) _JSON_BUILD_INTEGER, ({ intmax_t _x = i; _x; }) | |
189 | #define JSON_BUILD_UNSIGNED(u) _JSON_BUILD_UNSIGNED, ({ uintmax_t _x = u; _x; }) | |
190 | #define JSON_BUILD_REAL(d) _JSON_BUILD_REAL, ({ long double _x = d; _x; }) | |
191 | #define JSON_BUILD_BOOLEAN(b) _JSON_BUILD_BOOLEAN, ({ bool _x = b; _x; }) | |
192 | #define JSON_BUILD_ARRAY(...) _JSON_BUILD_ARRAY_BEGIN, __VA_ARGS__, _JSON_BUILD_ARRAY_END | |
193 | #define JSON_BUILD_OBJECT(...) _JSON_BUILD_OBJECT_BEGIN, __VA_ARGS__, _JSON_BUILD_OBJECT_END | |
194 | #define JSON_BUILD_PAIR(n, ...) _JSON_BUILD_PAIR, ({ const char *_x = n; _x; }), __VA_ARGS__ | |
195 | #define JSON_BUILD_NULL _JSON_BUILD_NULL | |
196 | #define JSON_BUILD_VARIANT(v) _JSON_BUILD_VARIANT, ({ JsonVariant *_x = v; _x; }) | |
197 | #define JSON_BUILD_LITERAL(l) _JSON_BUILD_LITERAL, ({ const char *_x = l; _x; }) | |
198 | #define JSON_BUILD_STRV(l) _JSON_BUILD_STRV, ({ char **_x = l; _x; }) | |
199 | ||
200 | int json_build(JsonVariant **ret, ...); | |
201 | int json_buildv(JsonVariant **ret, va_list ap); | |
202 | ||
203 | /* A bitmask of flags used by the dispatch logic. Note that this is a combined bit mask, that is generated from the bit | |
204 | * mask originally passed into json_dispatch(), the individual bitmask associated with the static JsonDispatch callout | |
205 | * entry, as well the bitmask specified for json_log() calls */ | |
206 | typedef enum JsonDispatchFlags { | |
207 | /* The following three may be set in JsonDispatch's .flags field or the json_dispatch() flags parameter */ | |
208 | JSON_PERMISSIVE = 1 << 0, /* Shall parsing errors be considered fatal for this property? */ | |
209 | JSON_MANDATORY = 1 << 1, /* Should existance of this property be mandatory? */ | |
210 | JSON_LOG = 1 << 2, /* Should the parser log about errors? */ | |
211 | ||
212 | /* The following two may be passed into log_json() in addition to the three above */ | |
213 | JSON_DEBUG = 1 << 3, /* Indicates that this log message is a debug message */ | |
214 | JSON_WARNING = 1 << 4, /* Indicates that this log message is a warning message */ | |
215 | } JsonDispatchFlags; | |
216 | ||
217 | typedef int (*JsonDispatchCallback)(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata); | |
218 | ||
219 | typedef struct JsonDispatch { | |
220 | const char *name; | |
221 | JsonVariantType type; | |
222 | JsonDispatchCallback callback; | |
223 | size_t offset; | |
224 | JsonDispatchFlags flags; | |
225 | } JsonDispatch; | |
226 | ||
227 | int json_dispatch(JsonVariant *v, const JsonDispatch table[], JsonDispatchCallback bad, JsonDispatchFlags flags, void *userdata); | |
228 | ||
229 | int json_dispatch_string(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata); | |
230 | int json_dispatch_strv(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata); | |
231 | int json_dispatch_boolean(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata); | |
232 | int json_dispatch_tristate(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata); | |
233 | int json_dispatch_variant(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata); | |
234 | int json_dispatch_integer(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata); | |
235 | int json_dispatch_unsigned(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata); | |
236 | int json_dispatch_uint32(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata); | |
237 | int json_dispatch_int32(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata); | |
238 | ||
239 | assert_cc(sizeof(uintmax_t) == sizeof(uint64_t)) | |
240 | #define json_dispatch_uint64 json_dispatch_unsigned | |
241 | ||
242 | assert_cc(sizeof(intmax_t) == sizeof(int64_t)) | |
243 | #define json_dispatch_int64 json_dispatch_integer | |
244 | ||
245 | static inline int json_dispatch_level(JsonDispatchFlags flags) { | |
246 | ||
247 | /* Did the user request no logging? If so, then never log higher than LOG_DEBUG. Also, if this is marked as | |
248 | * debug message, then also log at debug level. */ | |
249 | ||
250 | if (!(flags & JSON_LOG) || | |
251 | (flags & JSON_DEBUG)) | |
252 | return LOG_DEBUG; | |
253 | ||
254 | /* Are we invoked in permissive mode, or is this explicitly marked as warning message? Then this should be | |
255 | * printed at LOG_WARNING */ | |
256 | if (flags & (JSON_PERMISSIVE|JSON_WARNING)) | |
257 | return LOG_WARNING; | |
258 | ||
259 | /* Otherwise it's an error. */ | |
260 | return LOG_ERR; | |
261 | } | |
262 | ||
263 | int json_log_internal(JsonVariant *variant, int level, int error, const char *file, int line, const char *func, const char *format, ...) _printf_(7, 8); | |
264 | ||
265 | #define json_log(variant, flags, error, ...) \ | |
266 | ({ \ | |
267 | int _level = json_dispatch_level(flags), _e = (error); \ | |
268 | (log_get_max_level() >= LOG_PRI(_level)) \ | |
269 | ? json_log_internal(variant, _level, _e, __FILE__, __LINE__, __func__, __VA_ARGS__) \ | |
270 | : -abs(_e); \ | |
271 | }) | |
272 | ||
d520d519 LP |
273 | #define JSON_VARIANT_STRING_CONST(x) _JSON_VARIANT_STRING_CONST(UNIQ, (x)) |
274 | ||
275 | #define _JSON_VARIANT_STRING_CONST(xq, x) \ | |
276 | ({ \ | |
277 | __attribute__((aligned(2))) static const char UNIQ_T(json_string_const, xq)[] = (x); \ | |
278 | assert((((uintptr_t) UNIQ_T(json_string_const, xq)) & 1) == 0); \ | |
279 | (JsonVariant*) ((uintptr_t) UNIQ_T(json_string_const, xq) + 1); \ | |
280 | }) | |
281 | ||
cd0b6c53 LP |
282 | const char *json_variant_type_to_string(JsonVariantType t); |
283 | JsonVariantType json_variant_type_from_string(const char *s); |