PipeWire 1.7.0
Loading...
Searching...
No Matches
json-builder.h
Go to the documentation of this file.
1/* Simple Plugin API */
2/* SPDX-FileCopyrightText: Copyright © 2026 Wim Taymans */
3/* SPDX-License-Identifier: MIT */
4
5#ifndef SPA_UTILS_JSON_BUILDER_H
6#define SPA_UTILS_JSON_BUILDER_H
7
8#include <stddef.h>
9#include <stdlib.h>
10#include <stdint.h>
11#include <string.h>
12#include <math.h>
13#include <float.h>
14#include <inttypes.h>
15#include <limits.h>
16
17#include <spa/utils/defs.h>
18#include <spa/utils/ansi.h>
19#include <spa/utils/json.h>
20#include <spa/utils/cleanup.h>
21
22#ifdef __cplusplus
23extern "C" {
24#else
25#include <stdbool.h>
26#endif
27
28#ifndef SPA_API_JSON_BUILDER
29 #ifdef SPA_API_IMPL
30 #define SPA_API_JSON_BUILDER SPA_API_IMPL
31 #else
32 #define SPA_API_JSON_BUILDER static inline
33 #endif
34#endif
35
44
45struct spa_json_builder {
46 FILE *f;
47#define SPA_JSON_BUILDER_FLAG_CLOSE (1<<0)
48#define SPA_JSON_BUILDER_FLAG_INDENT (1<<1)
49#define SPA_JSON_BUILDER_FLAG_SPACE (1<<2)
50#define SPA_JSON_BUILDER_FLAG_PRETTY (SPA_JSON_BUILDER_FLAG_INDENT|SPA_JSON_BUILDER_FLAG_SPACE)
51#define SPA_JSON_BUILDER_FLAG_COLOR (1<<3)
52#define SPA_JSON_BUILDER_FLAG_SIMPLE (1<<4)
53#define SPA_JSON_BUILDER_FLAG_RAW (1<<5)
54 uint32_t flags;
55 uint32_t indent_off;
56 uint32_t level;
57 uint32_t indent;
58 uint32_t count;
59 const char *delim;
60 const char *comma;
61 const char *key_sep;
62#define SPA_JSON_BUILDER_COLOR_NORMAL 0
63#define SPA_JSON_BUILDER_COLOR_KEY 1
64#define SPA_JSON_BUILDER_COLOR_LITERAL 2
65#define SPA_JSON_BUILDER_COLOR_NUMBER 3
66#define SPA_JSON_BUILDER_COLOR_STRING 4
67#define SPA_JSON_BUILDER_COLOR_CONTAINER 5
68 const char *color[8];
69};
76 spa_zero(*b);
77 b->f = f;
78 b->flags = flags;
79 b->indent = 2;
80 b->delim = "";
81 b->comma = simple ? space ? "" : " " : ",";
82 b->key_sep = simple ? space ? " =" : "=" : ":";
83 b->color[0] = (color ? SPA_ANSI_RESET : "");
84 b->color[1] = (color ? SPA_ANSI_BRIGHT_BLUE : "");
85 b->color[2] = (color ? SPA_ANSI_BRIGHT_MAGENTA : "");
86 b->color[3] = (color ? SPA_ANSI_BRIGHT_CYAN : "");
87 b->color[4] = (color ? SPA_ANSI_BRIGHT_GREEN : "");
89 return 0;
90}
93 char **mem, size_t *size, uint32_t flags)
94{
95 FILE *f;
96 spa_zero(*b);
97 if ((f = open_memstream(mem, size)) == NULL)
98 return -errno;
100}
101
103 char *mem, size_t size, uint32_t flags)
104{
105 FILE *f;
106 spa_zero(*b);
107 if ((f = fmemopen(mem, size, "w")) == NULL)
108 return -errno;
110}
111
113{
114 int res = 0;
116 if (ferror(b->f))
117 res = -EIO;
118 if (fclose(b->f) != 0 && res == 0)
119 res = -errno;
120 }
121 return res;
123
125 bool raw, const char *before, const char *val, int size, const char *after)
126{
127 FILE *f = b->f;
128 int i, len;
129 if (raw) {
130 len = fprintf(f, "%s%.*s%s", before, size, val, after) - 1;
131 } else {
132 len = fprintf(f, "%s\"", before);
133 for (i = 0; i < size && val[i]; i++) {
134 char v = val[i];
135 switch (v) {
136 case '\n': len += fprintf(f, "\\n"); break;
137 case '\r': len += fprintf(f, "\\r"); break;
138 case '\b': len += fprintf(f, "\\b"); break;
139 case '\t': len += fprintf(f, "\\t"); break;
140 case '\f': len += fprintf(f, "\\f"); break;
141 case '\\':
142 case '"': len += fprintf(f, "\\%c", v); break;
143 default:
144 if (v > 0 && v < 0x20)
145 len += fprintf(f, "\\u%04x", v);
146 else
147 len += fprintf(f, "%c", v);
148 break;
149 }
150 }
151 len += fprintf(f, "\"%s", after);
152 }
153 return len-1;
154}
155
157void spa_json_builder_add_simple(struct spa_json_builder *b, const char *key, int key_len,
158 char type, const char *val, int val_len)
159{
160 bool indent = b->indent_off == 0 && (b->flags & SPA_JSON_BUILDER_FLAG_INDENT);
161 bool space = b->flags & SPA_JSON_BUILDER_FLAG_SPACE;
162 bool force_raw = b->flags & SPA_JSON_BUILDER_FLAG_RAW;
163 bool raw = true, simple = b->flags & SPA_JSON_BUILDER_FLAG_SIMPLE;
164 int color;
165
166 if (val == NULL || val_len == 0) {
167 val = "null";
168 val_len = 4;
169 type = 'l';
170 }
171 if (type == 0) {
172 if (spa_json_is_container(val, val_len))
173 type = simple ? 'C' : 'S';
174 else if (val_len > 0 && (*val == '}' || *val == ']'))
175 type = 'e';
176 else if (spa_json_is_null(val, val_len) ||
178 type = 'l';
179 else if (spa_json_is_string(val, val_len))
180 type = 's';
181 else if (spa_json_is_json_number(val, val_len))
182 type = 'd';
183 else if (simple && (spa_json_is_float(val, val_len) ||
184 spa_json_is_int(val, val_len)))
185 type = 'd';
186 else
187 type = 'S';
188 }
189 switch (type) {
190 case 'e':
191 b->level -= b->indent;
192 b->delim = "";
193 break;
194 }
195
196 fprintf(b->f, "%s%s%*s", b->delim, b->count == 0 ? "" : indent ? "\n" : space ? " " : "",
197 indent ? b->level : 0, "");
198 if (key) {
199 bool key_raw = force_raw || (simple && spa_json_make_simple_string(&key, &key_len)) ||
200 spa_json_is_string(key, key_len);
202 b->color[1], key, key_len, b->color[0]);
203 fprintf(b->f, "%s%s", b->key_sep, space ? " " : "");
204 }
205 b->delim = b->comma;
206 switch (type) {
207 case 'c':
209 val_len = 1;
210 b->delim = "";
211 b->level += b->indent;
212 if (val[1] == '-') b->indent_off++;
213 break;
214 case 'e':
216 val_len = 1;
217 if (val[1] == '-') b->indent_off--;
218 break;
219 case 'l':
221 break;
222 case 'd':
224 break;
225 case 's':
227 break;
228 case 'C':
230 break;
231 default:
233 raw = force_raw || (simple && spa_json_make_simple_string(&val, &val_len));
234 break;
235 }
236 spa_json_builder_encode_string(b, raw, b->color[color], val, val_len, b->color[0]);
237 b->count++;
238}
239
241 const char *key, const char *val)
242{
243 spa_json_builder_add_simple(b, key, INT_MAX, 'c', val, INT_MAX);
244}
246 const char *val)
247{
248 spa_json_builder_add_simple(b, NULL, 0, 'e', val, INT_MAX);
249}
251 const char *key)
252{
253 spa_json_builder_add_simple(b, key, INT_MAX, 'l', "null", 4);
254}
256 const char *key, bool val)
257{
258 spa_json_builder_add_simple(b, key, INT_MAX, 'l', val ? "true" : "false", INT_MAX);
259}
261 const char *key, int64_t val)
262{
263 char str[128];
264 snprintf(str, sizeof(str), "%" PRIi64, val);
265 spa_json_builder_add_simple(b, key, INT_MAX, 'd', str, INT_MAX);
266}
268 const char *key, uint64_t val)
269{
270 char str[128];
271 snprintf(str, sizeof(str), "%" PRIu64, val);
272 spa_json_builder_add_simple(b, key, INT_MAX, 'd', str, INT_MAX);
273}
275 const char *key, double val)
276{
277 char str[64];
278 spa_json_format_float(str, sizeof(str), (float)val);
279 spa_json_builder_add_simple(b, key, INT_MAX, 'd', str, INT_MAX);
282 const char *key, const char *val)
283{
284 spa_json_builder_add_simple(b, key, INT_MAX, 'S', val, INT_MAX);
285}
288 const char *key, const char *fmt, va_list va)
289{
290 char *val;
291 if (vasprintf(&val, fmt, va) > 0) {
293 free(val);
295}
296
298void spa_json_builder_object_stringf(struct spa_json_builder *b,
299 const char *key, const char *fmt, ...)
300{
301 va_list va;
302 va_start(va, fmt);
304 va_end(va);
305}
308 struct spa_json *it, const char *key, int key_len, const char *val, int len)
309{
310 struct spa_json sub;
312 spa_json_builder_add_simple(b, key, key_len, 'c', "[", 1);
313 spa_json_enter(it, &sub);
314 while ((len = spa_json_next(&sub, &val)) > 0)
315 spa_json_builder_object_value_iter(b, &sub, NULL, 0, val, len);
316 spa_json_builder_pop(b, "]");
318 else if (spa_json_is_object(val, len)) {
319 const char *k;
320 int kl;
321 spa_json_builder_add_simple(b, key, key_len, 'c', "{", 1);
322 spa_json_enter(it, &sub);
323 while ((kl = spa_json_next(&sub, &k)) > 0) {
324 if ((len = spa_json_next(&sub, &val)) < 0)
325 break;
326 spa_json_builder_object_value_iter(b, &sub, k, kl, val, len);
328 spa_json_builder_pop(b, "}");
329 }
330 else {
331 spa_json_builder_add_simple(b, key, key_len, 0, val, len);
332 }
333}
335 bool recurse, const char *key, int key_len, const char *val, int val_len)
336{
337 if (!recurse || val == NULL) {
338 spa_json_builder_add_simple(b, key, key_len, 0, val, val_len);
339 } else {
340 struct spa_json it[1];
341 const char *v;
342 if (spa_json_begin(&it[0], val, val_len, &v) >= 0)
343 spa_json_builder_object_value_iter(b, &it[0], key, key_len, val, val_len);
344 }
345}
347 bool recurse, const char *key, const char *val)
348{
350 val, val ? strlen(val) : 0);
351}
353void spa_json_builder_object_valuef(struct spa_json_builder *b,
354 bool recurse, const char *key, const char *fmt, ...)
355{
356 va_list va;
357 char *val;
358 va_start(va, fmt);
359 if (vasprintf(&val, fmt, va) > 0) {
361 free(val);
362 }
363 va_end(va);
364}
365
367/* array functions */
369 const char *val)
370{
376}
378 bool val)
379{
381}
383 int64_t val)
384{
386}
393 double val)
394{
396}
403void spa_json_builder_array_stringf(struct spa_json_builder *b,
404 const char *fmt, ...)
405{
406 va_list va;
412 bool recurse, const char *val)
413{
415}
417void spa_json_builder_array_valuef(struct spa_json_builder *b, bool recurse, const char *fmt, ...)
418{
419 va_list va;
420 char *val;
421 va_start(va, fmt);
422 if (vasprintf(&val, fmt, va) > 0) {
424 free(val);
425 }
426 va_end(va);
427}
429SPA_API_JSON_BUILDER char *spa_json_builder_reformat(const char *json, uint32_t flags)
430{
432 spa_autofree char *mem = NULL;
433 size_t size;
434 int res;
435 if ((res = spa_json_builder_memstream(&b, &mem, &size, flags)) < 0)
436 goto error;
437 spa_json_builder_array_value(&b, true, json);
438 if ((res = spa_json_builder_close(&b)) < 0)
439 goto error;
440 return spa_steal_ptr(mem);
441error:
442 errno = -res;
443 return NULL;
444}
445
450#ifdef __cplusplus
451} /* extern "C" */
452#endif
453
454#endif /* SPA_UTILS_JSON_BUILDER_H */
spa/utils/ansi.h
spa/utils/defs.h
uint32_t int int res
Definition core.h:433
#define SPA_ANSI_BRIGHT_BLUE
Definition ansi.h:66
#define SPA_ANSI_BRIGHT_GREEN
Definition ansi.h:62
#define SPA_ANSI_BRIGHT_MAGENTA
Definition ansi.h:68
#define SPA_ANSI_RESET
Ansi escape sequences.
Definition ansi.h:33
#define SPA_ANSI_BRIGHT_CYAN
Definition ansi.h:70
#define SPA_ANSI_BRIGHT_YELLOW
Definition ansi.h:64
SPA_API_JSON_BUILDER void spa_json_builder_object_null(struct spa_json_builder *b, const char *key)
Definition json-builder.h:270
SPA_API_JSON_BUILDER int spa_json_builder_file(struct spa_json_builder *b, FILE *f, uint32_t flags)
Definition json-builder.h:91
SPA_API_JSON_BUILDER void spa_json_builder_object_bool(struct spa_json_builder *b, const char *key, bool val)
Definition json-builder.h:275
SPA_API_JSON_BUILDER void spa_json_builder_array_null(struct spa_json_builder *b)
Definition json-builder.h:393
#define SPA_JSON_BUILDER_FLAG_CLOSE
Definition json-builder.h:55
SPA_API_JSON_BUILDER void spa_json_builder_object_value(struct spa_json_builder *b, bool recurse, const char *key, const char *val)
Definition json-builder.h:366
#define SPA_JSON_BUILDER_COLOR_LITERAL
Definition json-builder.h:81
const char const char * fmt
Definition json-builder.h:308
SPA_API_JSON_BUILDER void spa_json_builder_array_int(struct spa_json_builder *b, int64_t val)
Definition json-builder.h:402
SPA_API_JSON_BUILDER int spa_json_builder_encode_string(struct spa_json_builder *b, bool raw, const char *before, const char *val, int size, const char *after)
Definition json-builder.h:144
SPA_API_JSON_BUILDER int spa_json_builder_memstream(struct spa_json_builder *b, char **mem, size_t *size, uint32_t flags)
Definition json-builder.h:112
SPA_API_JSON_BUILDER void spa_json_builder_array_push(struct spa_json_builder *b, const char *val)
Definition json-builder.h:388
bool const char const char char * val
Definition json-builder.h:377
va_end(va)
SPA_API_JSON_BUILDER void spa_json_builder_object_push(struct spa_json_builder *b, const char *key, const char *val)
Definition json-builder.h:260
SPA_API_JSON_BUILDER void spa_json_builder_array_value(struct spa_json_builder *b, bool recurse, const char *val)
Definition json-builder.h:431
SPA_API_JSON_BUILDER void spa_json_builder_object_value_full(struct spa_json_builder *b, bool recurse, const char *key, int key_len, const char *val, int val_len)
Definition json-builder.h:354
SPA_API_JSON_BUILDER int spa_json_builder_membuf(struct spa_json_builder *b, char *mem, size_t size, uint32_t flags)
Definition json-builder.h:122
#define SPA_JSON_BUILDER_FLAG_COLOR
Definition json-builder.h:63
#define SPA_JSON_BUILDER_COLOR_CONTAINER
Definition json-builder.h:87
#define SPA_JSON_BUILDER_FLAG_SPACE
Definition json-builder.h:59
SPA_API_JSON_BUILDER char * spa_json_builder_reformat(const char *json, uint32_t flags)
Definition json-builder.h:449
SPA_API_JSON_BUILDER void spa_json_builder_object_uint(struct spa_json_builder *b, const char *key, uint64_t val)
Definition json-builder.h:287
#define SPA_JSON_BUILDER_FLAG_INDENT
Definition json-builder.h:57
SPA_API_JSON_BUILDER void spa_json_builder_array_string(struct spa_json_builder *b, const char *val)
Definition json-builder.h:417
SPA_API_JSON_BUILDER void spa_json_builder_array_double(struct spa_json_builder *b, double val)
Definition json-builder.h:412
#define SPA_JSON_BUILDER_COLOR_STRING
Definition json-builder.h:85
SPA_API_JSON_BUILDER void spa_json_builder_add_simple(struct spa_json_builder *b, const char *key, int key_len, char type, const char *val, int val_len)
Definition json-builder.h:177
const char const char va_start(va, fmt)
#define SPA_JSON_BUILDER_COLOR_NUMBER
Definition json-builder.h:83
SPA_API_JSON_BUILDER void spa_json_builder_object_value_iter(struct spa_json_builder *b, struct spa_json *it, const char *key, int key_len, const char *val, int len)
Definition json-builder.h:327
#define SPA_JSON_BUILDER_FLAG_RAW
Definition json-builder.h:67
#define SPA_JSON_BUILDER_COLOR_NORMAL
Definition json-builder.h:77
SPA_API_JSON_BUILDER void spa_json_builder_array_uint(struct spa_json_builder *b, uint64_t val)
Definition json-builder.h:407
spa_json_builder_object_stringv(b, key, fmt, va)
const char * key
Definition json-builder.h:308
SPA_API_JSON_BUILDER void spa_json_builder_object_int(struct spa_json_builder *b, const char *key, int64_t val)
Definition json-builder.h:280
SPA_API_JSON_BUILDER void spa_json_builder_object_string(struct spa_json_builder *b, const char *key, const char *val)
Definition json-builder.h:301
bool recurse
Definition json-builder.h:374
SPA_API_JSON_BUILDER void spa_json_builder_array_bool(struct spa_json_builder *b, bool val)
Definition json-builder.h:397
#define SPA_JSON_BUILDER_FLAG_SIMPLE
Definition json-builder.h:65
const char const char va_list va
Definition json-builder.h:309
SPA_API_JSON_BUILDER int spa_json_builder_close(struct spa_json_builder *b)
Definition json-builder.h:132
SPA_API_JSON_BUILDER void spa_json_builder_object_double(struct spa_json_builder *b, const char *key, double val)
Definition json-builder.h:294
SPA_API_JSON_BUILDER void spa_json_builder_pop(struct spa_json_builder *b, const char *val)
Definition json-builder.h:265
SPA_API_JSON_UTILS int spa_json_begin(struct spa_json *iter, const char *data, size_t size, const char **val)
Definition json.h:47
SPA_API_JSON bool spa_json_is_string(const char *val, int len)
Definition json-core.h:548
SPA_API_JSON int spa_json_next(struct spa_json *iter, const char **value)
Get the next token.
Definition json-core.h:101
SPA_API_JSON int spa_json_is_object(const char *val, int len)
Definition json-core.h:420
SPA_API_JSON char * spa_json_format_float(char *str, int size, float val)
Definition json-core.h:458
SPA_API_JSON bool spa_json_is_null(const char *val, int len)
Definition json-core.h:432
SPA_API_JSON bool spa_json_is_bool(const char *val, int len)
Definition json-core.h:533
SPA_API_JSON bool spa_json_is_int(const char *val, int len)
Definition json-core.h:483
SPA_API_JSON bool spa_json_make_simple_string(const char **val, int *len)
Definition json-core.h:562
SPA_API_JSON bool spa_json_is_json_number(const char *val, int len)
Definition json-core.h:489
SPA_API_JSON void spa_json_enter(struct spa_json *iter, struct spa_json *sub)
Definition json-core.h:78
SPA_API_JSON bool spa_json_is_array(const char *val, int len)
Definition json-core.h:426
SPA_API_JSON bool spa_json_is_float(const char *val, int len)
Definition json-core.h:452
SPA_API_JSON int spa_json_is_container(const char *val, int len)
Definition json-core.h:410
#define spa_zero(x)
Definition defs.h:522
#define SPA_PRINTF_FUNC(fmt, arg1)
Definition defs.h:297
#define SPA_API_JSON_BUILDER
Definition json-builder.h:39
spa/utils/json.h
spa/utils/string.h
Definition json-builder.h:52
uint32_t indent
Definition json-builder.h:71
const char * comma
Definition json-builder.h:74
FILE * f
Definition json-builder.h:53
uint32_t count
Definition json-builder.h:72
const char * color[8]
Definition json-builder.h:88
const char * key_sep
Definition json-builder.h:75
const char * delim
Definition json-builder.h:73
uint32_t flags
Definition json-builder.h:68
uint32_t indent_off
Definition json-builder.h:69
uint32_t level
Definition json-builder.h:70
Definition json-core.h:49