Line data Source code
1 : /* SPDX-License-Identifier: GPL-3.0-or-later */
2 : /* Copyright 2026 Peter Csaszar */
3 :
4 : /**
5 : * @file core/json_util.c
6 : * @brief Minimal JSON string escaping — see json_util.h.
7 : */
8 :
9 : #include "json_util.h"
10 :
11 : #include <stddef.h>
12 : #include <stdint.h>
13 : #include <stdio.h>
14 :
15 7 : size_t json_escape_str(char *dst, size_t cap, const char *src)
16 : {
17 7 : if (!dst || cap == 0) return 0;
18 7 : if (!src) src = "";
19 :
20 7 : size_t out = 0; /* bytes written so far (excl. NUL) */
21 :
22 : #define PUSH(c) do { if (out + 1 < cap) dst[out++] = (char)(c); else out++; } while (0)
23 : #define PUSH2(a,b) do { PUSH(a); PUSH(b); } while (0)
24 :
25 50 : for (const unsigned char *p = (const unsigned char *)src; *p; p++) {
26 43 : unsigned char c = *p;
27 43 : switch (c) {
28 2 : case '"': PUSH2('\\', '"'); break;
29 1 : case '\\': PUSH2('\\', '\\'); break;
30 0 : case '\b': PUSH2('\\', 'b'); break;
31 0 : case '\f': PUSH2('\\', 'f'); break;
32 1 : case '\n': PUSH2('\\', 'n'); break;
33 1 : case '\r': PUSH2('\\', 'r'); break;
34 1 : case '\t': PUSH2('\\', 't'); break;
35 37 : default:
36 37 : if (c < 0x20u) {
37 : /* Other C0 controls: \uXXXX */
38 : char seq[7];
39 2 : int n = snprintf(seq, sizeof(seq), "\\u%04x", (unsigned)c);
40 14 : for (int i = 0; i < n; i++) PUSH(seq[i]);
41 : } else {
42 : /* ASCII printable or high byte (UTF-8 pass-through) */
43 35 : PUSH(c);
44 : }
45 37 : break;
46 : }
47 : }
48 :
49 : #undef PUSH2
50 : #undef PUSH
51 :
52 : /* Always NUL-terminate within the buffer. */
53 7 : if (out < cap)
54 6 : dst[out] = '\0';
55 1 : else if (cap > 0)
56 1 : dst[cap - 1] = '\0';
57 :
58 7 : return out;
59 : }
|