19 : _buf(buf), _cap(cap), _len(0), _ok(buf != nullptr && cap >= 1), _after_key(false), _depth(0)
25void JsonWriter::put(
char c)
38void JsonWriter::put_raw(
const char *s)
46void JsonWriter::put_escaped(
const char *s)
52 unsigned char c = (
unsigned char)*s;
87 static const char hexd[] =
"0123456789abcdef";
92 put(hexd[(c >> 4) & 0x0f]);
104void JsonWriter::value_prefix()
113 size_t lvl = (size_t)(_depth - 1);
114 if (_need_comma[lvl])
116 _need_comma[lvl] =
true;
120void JsonWriter::push(
char open)
126 _need_comma[_depth] =
false;
135void JsonWriter::pop(
char close)
182 snprintf(tmp,
sizeof(tmp),
"%ld", v);
190 snprintf(tmp,
sizeof(tmp),
"%lu", v);
198 put_raw(v ?
"true" :
"false");
248static bool is_ws(
char c)
250 return c ==
' ' || c ==
'\t' || c ==
'\n' || c ==
'\r';
253static const char *skip_ws(
const char *p)
255 while (*p && is_ws(*p))
262static const char *skip_string(
const char *p)
267 if (*p ==
'\\' && p[1])
281static const char *skip_value(
const char *p)
284 return skip_string(p);
285 if (*p ==
'{' || *p ==
'[')
288 char close = (open ==
'{') ?
'}' :
']';
299 else if (*p == close)
310 while (*p && *p !=
',' && *p !=
'}' && *p !=
']' && !is_ws(*p))
317static const char *json_find_value(
const char *json,
const char *key)
321 const char *p = skip_ws(json);
326 constexpr size_t key_max = 256;
327 size_t keylen = strnlen(key, key_max);
331 if (*p ==
'}' || *p ==
'\0')
336 const char *kstart = p + 1;
337 const char *kend = skip_string(p);
338 size_t klen = (kend > kstart) ? (
size_t)((kend - 1) - kstart) : 0;
339 bool match = (klen == keylen) && (strncmp(kstart, key, klen) == 0);
360static int hex_val(
char c)
362 if (c >=
'0' && c <=
'9')
364 if (c >=
'a' && c <=
'f')
366 if (c >=
'A' && c <=
'F')
383static int json_hex4(
const char *src)
385 int h0 = src[0] ? hex_val(src[0]) : -1;
386 int h1 = (h0 >= 0 && src[1]) ? hex_val(src[1]) : -1;
387 int h2 = (h1 >= 0 && src[2]) ? hex_val(src[2]) : -1;
388 int h3 = (h2 >= 0 && src[3]) ? hex_val(src[3]) : -1;
391 return (h0 << 12) | (h1 << 8) | (h2 << 4) | h3;
394static long json_decode_u(
const char *&p)
396 int v = json_hex4(p + 1);
399 unsigned cp = (unsigned)v;
401 if (cp >= 0xD800 && cp <= 0xDBFF)
404 int lo = (p[1] ==
'\\' && p[2] ==
'u') ? json_hex4(p + 3) : -1;
405 if (lo >= 0xDC00 && lo <= 0xDFFF)
407 cp = 0x10000u + ((cp - 0xD800u) << 10) + ((unsigned)lo - 0xDC00u);
413 else if (cp >= 0xDC00 && cp <= 0xDFFF)
422static JsonEsc json_emit_utf8(
unsigned cp,
char *out,
size_t &i,
size_t out_cap)
428 u8[0] = (
unsigned char)cp;
431 else if (cp < 0x800u)
433 u8[0] = (
unsigned char)(0xC0u | (cp >> 6));
434 u8[1] = (
unsigned char)(0x80u | (cp & 0x3Fu));
437 else if (cp < 0x10000u)
439 u8[0] = (
unsigned char)(0xE0u | (cp >> 12));
440 u8[1] = (
unsigned char)(0x80u | ((cp >> 6) & 0x3Fu));
441 u8[2] = (
unsigned char)(0x80u | (cp & 0x3Fu));
446 u8[0] = (
unsigned char)(0xF0u | (cp >> 18));
447 u8[1] = (
unsigned char)(0x80u | ((cp >> 12) & 0x3Fu));
448 u8[2] = (
unsigned char)(0x80u | ((cp >> 6) & 0x3Fu));
449 u8[3] = (
unsigned char)(0x80u | (cp & 0x3Fu));
452 if (i + (
size_t)un >= out_cap)
457 for (
int k = 0; k < un; k++)
458 out[i++] = (
char)u8[k];
466static JsonEsc json_decode_escape(
const char *&p,
char *out,
size_t &i,
size_t out_cap,
char *c_out)
503 long cp = json_decode_u(p);
509 return json_emit_utf8((
unsigned)cp, out, i, out_cap);
512bool json_get_str(
const char *json,
const char *key,
char *out,
size_t out_cap)
514 if (!out || out_cap == 0)
516 const char *v = json_find_value(json, key);
520 const char *p = v + 1;
522 while (*p && *p !=
'"')
525 if (c ==
'\\' && p[1])
528 JsonEsc r = json_decode_escape(p, out, i, out_cap, &c);
556 const char *v = json_find_value(json, key);
559 const char *end =
nullptr;
571 const char *v = json_find_value(json, key);
574 if (strncmp(v,
"true", 4) == 0 && (v[4] ==
'\0' || v[4] ==
',' || v[4] ==
'}' || v[4] ==
']' || is_ws(v[4])))
579 if (strncmp(v,
"false", 5) == 0 && (v[5] ==
'\0' || v[5] ==
',' || v[5] ==
'}' || v[5] ==
']' || is_ws(v[5])))
#define JSON_MAX_DEPTH
Maximum object/array nesting depth for the JsonWriter (see json.h).
void str(const char *v)
Emit a quoted, escaped string value.
void begin_object()
Open { (as a value/element where applicable).
void key(const char *k)
Emit an object member name ("k":); follow with one value.
void raw(const char *literal)
Emit a pre-formatted literal verbatim.
JsonWriter(char *buf, size_t cap)
Construct over a caller buffer.
void kv_bool(const char *k, bool v)
"k":true|false.
void kv_str(const char *k, const char *v)
"k":"v" (escaped).
void boolean(bool v)
Emit true/false.
void integer(long v)
Emit a signed integer value.
void kv_uint(const char *k, unsigned long v)
"k":<uint>.
void kv_int(const char *k, long v)
"k":<int>.
void uinteger(unsigned long v)
Emit an unsigned integer value.
void end_object()
Close }.
void kv_raw(const char *k, const char *literal)
"k":<literal>.
void null_value()
Emit null.
void kv_null(const char *k)
"k":null.
void begin_array()
Open [.
bool json_get_str(const char *json, const char *key, char *out, size_t out_cap)
Read a top-level string member from a JSON object body.
bool json_get_bool(const char *json, const char *key, bool *out)
Read a top-level boolean member (true/false) from a JSON object body.
bool json_get_int(const char *json, const char *key, long *out)
Read a top-level integer member from a JSON object body.
Layer 6 (Presentation) - zero-heap JSON: a bounded writer and top-level reader.
Tiny no-stdlib base-10 number parsers (strtol/strtoul/strtof replacements).
long det_strtol(const char *s, const char **end)
Parse a base-10 long; sets end past the digits (or to s if none).