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