1 // Copyright (c) 2018-2020 Cesanta Software Limited
4 // Permission is hereby granted, free of charge, to any person obtaining a copy
5 // of this software and associated documentation files (the "Software"), to deal
6 // in the Software without restriction, including without limitation the rights
7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 // copies of the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 #define alloca(x) _alloca(x)
31 #if defined(_MSC_VER) && _MSC_VER < 1700
32 #define va_copy(x, y) (x) = (y)
33 #define isinf(x) !_finite(x)
34 #define isnan(x) _isnan(x)
37 static double mystrtod(const char *str, const char **end);
39 static int mjson_esc(int c, int esc) {
40 const char *p, *esc1 = "\b\f\n\r\t\\\"", *esc2 = "bfnrt\\\"";
41 for (p = esc ? esc1 : esc2; *p != '\0'; p++) {
42 if (*p == c) return esc ? esc2[p - esc1] : esc1[p - esc2];
47 static int mjson_escape(int c) {
48 return mjson_esc(c, 1);
51 static int mjson_pass_string(const char *s, int len) {
53 for (i = 0; i < len; i++) {
54 if (s[i] == '\\' && i + 1 < len && mjson_escape(s[i + 1])) {
56 } else if (s[i] == '\0') {
57 return MJSON_ERROR_INVALID_INPUT;
58 } else if (s[i] == '"') {
62 return MJSON_ERROR_INVALID_INPUT;
65 int mjson(const char *s, int len, mjson_cb_t cb, void *ud) {
66 enum { S_VALUE, S_KEY, S_COLON, S_COMMA_OR_EOO } expecting = S_VALUE;
67 unsigned char nesting[MJSON_MAX_DEPTH];
69 #define MJSONCALL(ev) \
70 if (cb != NULL && cb(ev, s, start, i - start + 1, ud)) return i + 1;
72 // In the ascii table, the distance between `[` and `]` is 2.
73 // Ditto for `{` and `}`. Hence +2 in the code below.
76 if (c != nesting[depth - 1] + 2) return MJSON_ERROR_INVALID_INPUT; \
84 for (i = 0; i < len; i++) {
86 unsigned char c = ((const unsigned char *) s)[i];
88 if (c == ' ' || c == '\t' || c == '\n' || c == '\r') continue;
89 // printf("- %c [%.*s] %d %d\n", c, i, s, depth, expecting);
93 if (depth >= (int) sizeof(nesting)) return MJSON_ERROR_TOO_DEEP;
97 } else if (c == '[') {
98 if (depth >= (int) sizeof(nesting)) return MJSON_ERROR_TOO_DEEP;
101 } else if (c == ']' && depth > 0) { // Empty array
103 } else if (c == 't' && i + 3 < len && memcmp(&s[i], "true", 4) == 0) {
105 tok = MJSON_TOK_TRUE;
106 } else if (c == 'n' && i + 3 < len && memcmp(&s[i], "null", 4) == 0) {
108 tok = MJSON_TOK_NULL;
109 } else if (c == 'f' && i + 4 < len && memcmp(&s[i], "false", 5) == 0) {
111 tok = MJSON_TOK_FALSE;
112 } else if (c == '-' || ((c >= '0' && c <= '9'))) {
113 const char *end = NULL;
114 mystrtod(&s[i], &end);
115 if (end != NULL) i += (int) (end - &s[i] - 1);
116 tok = MJSON_TOK_NUMBER;
117 } else if (c == '"') {
118 int n = mjson_pass_string(&s[i + 1], len - i - 1);
121 tok = MJSON_TOK_STRING;
123 return MJSON_ERROR_INVALID_INPUT;
129 expecting = S_COMMA_OR_EOO;
134 int n = mjson_pass_string(&s[i + 1], len - i - 1);
139 } else if (c == '}') { // Empty object
141 expecting = S_COMMA_OR_EOO;
143 return MJSON_ERROR_INVALID_INPUT;
151 return MJSON_ERROR_INVALID_INPUT;
156 if (depth <= 0) return MJSON_ERROR_INVALID_INPUT;
158 expecting = (nesting[depth - 1] == '{') ? S_KEY : S_VALUE;
159 } else if (c == ']' || c == '}') {
162 return MJSON_ERROR_INVALID_INPUT;
168 return MJSON_ERROR_INVALID_INPUT;
171 struct msjon_get_data {
172 const char *path; // Lookup json path
173 int pos; // Current path position
174 int d1; // Current depth of traversal
175 int d2; // Expected depth of traversal
176 int i1; // Index in an array
177 int i2; // Expected index in an array
178 int obj; // If the value is array/object, offset where it starts
179 const char **tokptr; // Destination
180 int *toklen; // Destination length
181 int tok; // Returned token
186 static int plen1(const char *s) {
188 while (s[i] != '\0' && s[i] != '.' && s[i] != '[')
189 n++, i += s[i] == '\\' ? 2 : 1;
190 // printf("PLEN: s: [%s], [%.*s] => %d\n", s, i, s, n);
194 static int plen2(const char *s) {
196 while (s[i] != '\0' && s[i] != '.' && s[i] != '[')
197 i += s[i] == '\\' ? 2 : 1;
198 // printf("PLEN: s: [%s], [%.*s] => %d\n", s, i, s, n);
202 static int kcmp(const char *a, const char *b, int n) {
203 int i = 0, j = 0, r = 0;
204 for (i = 0, j = 0; j < n; i++, j++) {
205 if (b[i] == '\\') i++;
206 if ((r = a[j] - b[i]) != 0) return r;
208 // printf("KCMP: a: [%.*s], b:[%.*s] ==> %d\n", n, a, i, b, r);
212 static int mjson_get_cb(int tok, const char *s, int off, int len, void *ud) {
213 struct msjon_get_data *d = (struct msjon_get_data *) ud;
215 printf("--> %2x %2d %2d %2d %2d\t %2d %2d\t'%s' '%s' '%s' '%s'\n", tok, d->d1,
216 d->d2, d->i1, d->i2, (int) off, (int) d->pos, s, d->path, s + off,
219 if (d->tok != MJSON_TOK_INVALID) return 1; // Found
220 if (tok == '{' || tok == '[') {
221 if (d->d1 < d->d2) d->obj = -1;
222 if (d->d1 == d->d2) d->obj = off;
223 if (d->d1 == d->d2 && tok == '[' && d->path[d->pos] == '[') {
225 d->i2 = (int) mystrtod(&d->path[d->pos + 1], NULL);
226 if (d->i1 == d->i2) {
227 while (d->path[d->pos] && d->path[d->pos] != ']') d->pos++;
228 if (d->path[d->pos] == ']') d->pos++;
233 } else if (tok == '}' || tok == ']') {
234 if (tok == ']' && d->d1 == d->d2) d->i1 = 0;
236 // printf("X %s %d %d %d %d %d\n", d->path + d->pos, d->d1, d->d2, d->i1,
238 if (!d->path[d->pos] && d->d1 == d->d2 && d->obj != -1) {
240 if (d->tokptr) *d->tokptr = s + d->obj;
241 if (d->toklen) *d->toklen = off - d->obj + 1;
244 } else if (tok == ',' && d->d1 == d->d2 && d->pos &&
245 d->path[d->pos - 1] == ']') {
246 return 1; // Not found in the current elem array
247 } else if (tok == ',' && d->d1 == d->d2 + 1 && d->path[d->pos] == '[') {
248 // printf("GG '%s' '%s'\n", d->path, &d->path[d->pos]);
250 if (d->i1 == d->i2) {
251 while (d->path[d->pos] && d->path[d->pos] != ']') d->pos++;
252 if (d->path[d->pos] == ']') d->pos++;
255 } else if (tok == MJSON_TOK_KEY && d->d1 == d->d2 + 1 &&
256 d->path[d->pos] == '.' && s[off] == '"' &&
257 s[off + len - 1] == '"' &&
258 plen1(&d->path[d->pos + 1]) == len - 2 &&
259 kcmp(s + off + 1, &d->path[d->pos + 1], len - 2) == 0) {
261 d->pos += plen2(&d->path[d->pos + 1]) + 1;
262 } else if (tok == MJSON_TOK_KEY && d->d1 == d->d2) {
263 return 1; // Exhausted path, not found
264 } else if (MJSON_TOK_IS_VALUE(tok)) {
265 // printf("T %d %d %d %d %d\n", tok, d->d1, d->d2, d->i1, d->i2);
266 if (d->d1 == d->d2 && d->i1 == d->i2 && !d->path[d->pos]) {
268 if (d->tokptr) *d->tokptr = s + off;
269 if (d->toklen) *d->toklen = len;
276 int mjson_find(const char *s, int n, const char *jp, const char **tp, int *tl) {
277 struct msjon_get_data data = {jp, 1, 0, 0, 0,
278 0, -1, tp, tl, MJSON_TOK_INVALID};
279 if (jp[0] != '$') return MJSON_TOK_INVALID;
280 if (mjson(s, n, mjson_get_cb, &data) < 0) return MJSON_TOK_INVALID;
284 int mjson_get_number(const char *s, int len, const char *path, double *v) {
287 if ((tok = mjson_find(s, len, path, &p, &n)) == MJSON_TOK_NUMBER) {
288 if (v != NULL) *v = mystrtod(p, NULL);
290 return tok == MJSON_TOK_NUMBER ? 1 : 0;
293 int mjson_get_bool(const char *s, int len, const char *path, int *v) {
294 int tok = mjson_find(s, len, path, NULL, NULL);
295 if (tok == MJSON_TOK_TRUE && v != NULL) *v = 1;
296 if (tok == MJSON_TOK_FALSE && v != NULL) *v = 0;
297 return tok == MJSON_TOK_TRUE || tok == MJSON_TOK_FALSE ? 1 : 0;
300 static unsigned char unhex(unsigned char c) {
301 return (c >= '0' && c <= '9') ? (unsigned char) (c - '0')
302 : (c >= 'A' && c <= 'F') ? (unsigned char) (c - '7')
303 : (unsigned char) (c - 'W');
306 static unsigned char mjson_unhex_nimble(const char *s) {
307 const unsigned char *u = (const unsigned char *) s;
308 return (unsigned char) (((unsigned char) (unhex(u[0]) << 4)) | unhex(u[1]));
311 static int mjson_unescape(const char *s, int len, char *to, int n) {
313 for (i = 0, j = 0; i < len && j < n; i++, j++) {
314 if (s[i] == '\\' && i + 5 < len && s[i + 1] == 'u') {
315 // \uXXXX escape. We could process a simple one-byte chars
316 // \u00xx from the ASCII range. More complex chars would require
317 // dragging in a UTF8 library, which is too much for us
318 if (s[i + 2] != '0' || s[i + 3] != '0') return -1; // Too much, give up
319 ((unsigned char *) to)[j] = mjson_unhex_nimble(s + i + 4);
321 } else if (s[i] == '\\' && i + 1 < len) {
322 int c = mjson_esc(s[i + 1], 0);
323 if (c == 0) return -1;
324 to[j] = (char) (unsigned char) c;
330 if (j >= n) return -1;
331 if (n > 0) to[j] = '\0';
335 int mjson_get_string(const char *s, int len, const char *path, char *to,
339 if (mjson_find(s, len, path, &p, &sz) != MJSON_TOK_STRING) return -1;
340 return mjson_unescape(p + 1, sz - 2, to, n);
343 int mjson_get_hex(const char *s, int len, const char *x, char *to, int n) {
346 if (mjson_find(s, len, x, &p, &sz) != MJSON_TOK_STRING) return -1;
347 for (i = j = 0; i < sz - 3 && j < n; i += 2, j++) {
348 ((unsigned char *) to)[j] = mjson_unhex_nimble(p + i + 1);
350 if (j < n) to[j] = '\0';
354 #if MJSON_ENABLE_BASE64
355 static unsigned char mjson_base64rev(int c) {
356 if (c >= 'A' && c <= 'Z') {
357 return (unsigned char) (c - 'A');
358 } else if (c >= 'a' && c <= 'z') {
359 return (unsigned char) (c + 26 - 'a');
360 } else if (c >= '0' && c <= '9') {
361 return (unsigned char) (c + 52 - '0');
362 } else if (c == '+') {
364 } else if (c == '/') {
371 int mjson_base64_dec(const char *src, int n, char *dst, int dlen) {
372 const char *end = src + n;
374 while (src + 3 < end && len < dlen) {
375 unsigned char a = mjson_base64rev(src[0]), b = mjson_base64rev(src[1]),
376 c = mjson_base64rev(src[2]), d = mjson_base64rev(src[3]);
377 dst[len++] = (char) (unsigned char) ((a << 2) | (b >> 4));
378 if (src[2] != '=' && len < dlen) {
379 dst[len++] = (char) (unsigned char) ((b << 4) | (c >> 2));
380 if (src[3] != '=' && len < dlen) {
381 dst[len++] = (char) (unsigned char) ((c << 6) | d);
386 if (len < dlen) dst[len] = '\0';
390 int mjson_get_base64(const char *s, int len, const char *path, char *to,
394 if (mjson_find(s, len, path, &p, &sz) != MJSON_TOK_STRING) return 0;
395 return mjson_base64_dec(p + 1, sz - 2, to, n);
397 #endif // MJSON_ENABLE_BASE64
399 #if MJSON_ENABLE_NEXT
401 int off, len, depth, t, vo, arrayindex;
402 int *koff, *klen, *voff, *vlen, *vtype;
405 static int next_cb(int tok, const char *s, int off, int len, void *ud) {
406 struct nextdata *d = (struct nextdata *) ud;
411 if (d->depth == 0 && tok == '[') d->arrayindex = 0;
412 if (d->depth == 1 && off > d->off) {
414 d->t = tok == '{' ? MJSON_TOK_OBJECT : MJSON_TOK_ARRAY;
415 if (d->voff) *d->voff = off;
416 if (d->vtype) *d->vtype = d->t;
423 if (d->depth == 1 && d->vo) {
425 if (d->vlen) *d->vlen = d->len - d->vo;
426 if (d->arrayindex >= 0) {
427 if (d->koff) *d->koff = d->arrayindex; // koff holds array index
428 if (d->klen) *d->klen = 0; // klen holds 0
432 if (d->depth == 1 && d->arrayindex >= 0) d->arrayindex++;
438 if (d->depth == 1 && d->off < off) {
439 if (d->koff) *d->koff = off; // And report back to the user
440 if (d->klen) *d->klen = len; // If we have to
444 if (d->depth != 1) break;
445 // If we're iterating over the array
448 if (d->vlen) *d->vlen = len; // value length
449 if (d->voff) *d->voff = off; // value offset
450 if (d->vtype) *d->vtype = tok; // value type
451 if (d->arrayindex >= 0) {
452 if (d->koff) *d->koff = d->arrayindex; // koff holds array index
453 if (d->klen) *d->klen = 0; // klen holds 0
457 if (d->arrayindex >= 0) d->arrayindex++;
464 int mjson_next(const char *s, int n, int off, int *koff, int *klen, int *voff,
465 int *vlen, int *vtype) {
466 struct nextdata d = {off, 0, 0, 0, 0, -1, koff, klen, voff, vlen, vtype};
467 mjson(s, n, next_cb, &d);
472 #if MJSON_ENABLE_PRINT
473 int mjson_print_fixed_buf(const char *ptr, int len, void *fn_data) {
474 struct mjson_fixedbuf *fb = (struct mjson_fixedbuf *) fn_data;
475 int i, left = fb->size - 1 - fb->len;
476 if (left < len) len = left;
477 for (i = 0; i < len; i++) fb->ptr[fb->len + i] = ptr[i];
479 fb->ptr[fb->len] = '\0';
483 // This function allocates memory in chunks of size MJSON_DYNBUF_CHUNK
484 // to decrease memory fragmentation, when many calls are executed to
485 // print e.g. a base64 string or a hex string.
486 int mjson_print_dynamic_buf(const char *ptr, int len, void *fn_data) {
487 char *s, *buf = *(char **) fn_data;
488 size_t curlen = buf == NULL ? 0 : strlen(buf);
489 size_t new_size = curlen + (size_t) len + 1 + MJSON_DYNBUF_CHUNK;
490 new_size -= new_size % MJSON_DYNBUF_CHUNK;
492 if ((s = (char *) MJSON_REALLOC(buf, new_size)) == NULL) {
495 memcpy(s + curlen, ptr, (size_t) len);
496 s[curlen + (size_t) len] = '\0';
497 *(char **) fn_data = s;
502 int mjson_snprintf(char *buf, size_t len, const char *fmt, ...) {
504 struct mjson_fixedbuf fb = {buf, (int) len, 0};
506 mjson_vprintf(mjson_print_fixed_buf, &fb, fmt, &ap);
511 char *mjson_aprintf(const char *fmt, ...) {
515 mjson_vprintf(mjson_print_dynamic_buf, &result, fmt, &ap);
520 int mjson_print_null(const char *ptr, int len, void *userdata) {
526 int mjson_print_buf(mjson_print_fn_t fn, void *fnd, const char *buf, int len) {
527 return fn(buf, len, fnd);
530 int mjson_print_long(mjson_print_fn_t fn, void *fnd, long val, int is_signed) {
531 unsigned long v = (unsigned long) val, s = 0, n, i;
533 if (is_signed && val < 0) buf[s++] = '-', v = (unsigned long) (-val);
534 // This loop prints a number in reverse order. I guess this is because we
535 // write numbers from right to left: least significant digit comes last.
536 // Maybe because we use Arabic numbers, and Arabs write RTL?
537 for (n = 0; v > 0; v /= 10) buf[s + n++] = "0123456789"[v % 10];
539 for (i = 0; i < n / 2; i++)
540 t = buf[s + i], buf[s + i] = buf[s + n - i - 1], buf[s + n - i - 1] = t;
541 if (val == 0) buf[n++] = '0'; // Handle special case
542 return fn(buf, (int) (s + n), fnd);
545 int mjson_print_int(mjson_print_fn_t fn, void *fnd, int v, int s) {
546 return mjson_print_long(fn, fnd, s ? (long) v : (long) (unsigned) v, s);
549 static int addexp(char *buf, int e, int sign) {
552 buf[n++] = (char) sign;
553 if (e > 400) return 0;
554 if (e < 10) buf[n++] = '0';
555 if (e >= 100) buf[n++] = (char) (e / 100 + '0'), e -= 100 * (e / 100);
556 if (e >= 10) buf[n++] = (char) (e / 10 + '0'), e -= 10 * (e / 10);
557 buf[n++] = (char) (e + '0');
561 int mjson_print_dbl(mjson_print_fn_t fn, void *fnd, double d, int width) {
563 int i, s = 0, n = 0, e = 0;
564 double t, mul, saved;
565 if (d == 0.0) return fn("0", 1, fnd);
566 if (isinf(d)) return fn(d > 0 ? "inf" : "-inf", d > 0 ? 3 : 4, fnd);
567 if (isnan(d)) return fn("nan", 3, fnd);
568 if (d < 0.0) d = -d, buf[s++] = '-';
573 while (d >= 10.0 && d / mul >= 10.0) mul *= 10.0;
574 while (d <= 1.0 && d / mul <= 1.0) mul /= 10.0;
575 for (i = 0, t = mul * 5; i < width; i++) t /= 10.0;
577 // Calculate exponent, and 'mul' for scientific representation
579 while (d >= 10.0 && d / mul >= 10.0) mul *= 10.0, e++;
580 while (d < 1.0 && d / mul < 1.0) mul /= 10.0, e--;
581 // printf(" --> %g %d %g %g\n", saved, e, t, mul);
584 struct mjson_fixedbuf fb = {buf + s, (int) sizeof(buf) - s, 0};
585 n = mjson_print_dbl(mjson_print_fixed_buf, &fb, saved / mul, width);
586 // printf(" --> %.*g %d [%.*s]\n", 10, d / t, e, fb.len, fb.ptr);
587 n += addexp(buf + s + n, e, '+');
588 return fn(buf, s + n, fnd);
589 } else if (e <= -width) {
590 struct mjson_fixedbuf fb = {buf + s, (int) sizeof(buf) - s, 0};
591 n = mjson_print_dbl(mjson_print_fixed_buf, &fb, saved / mul, width);
592 // printf(" --> %.*g %d [%.*s]\n", 10, d / mul, e, fb.len, fb.ptr);
593 n += addexp(buf + s + n, -e, '-');
594 return fn(buf, s + n, fnd);
596 for (i = 0, t = mul; t >= 1.0 && s + n < (int) sizeof(buf); i++) {
597 int ch = (int) (d / t);
598 if (n > 0 || ch > 0) buf[s + n++] = (char) (ch + '0');
602 // printf(" --> [%g] -> %g %g (%d) [%.*s]\n", saved, d, t, n, s + n, buf);
603 if (n == 0) buf[s++] = '0';
604 while (t >= 1.0 && n + s < (int) sizeof(buf)) buf[n++] = '0', t /= 10.0;
605 if (s + n < (int) sizeof(buf)) buf[n + s++] = '.';
606 // printf(" 1--> [%g] -> [%.*s]\n", saved, s + n, buf);
607 for (i = 0, t = 0.1; s + n < (int) sizeof(buf) && n < width; i++) {
608 int ch = (int) (d / t);
609 buf[s + n++] = (char) (ch + '0');
614 while (n > 0 && buf[s + n - 1] == '0') n--; // Trim trailing zeros
615 if (n > 0 && buf[s + n - 1] == '.') n--; // Trim trailing dot
617 return fn(buf, s + n, fnd);
620 int mjson_print_str(mjson_print_fn_t fn, void *fnd, const char *s, int len) {
621 int i, n = fn("\"", 1, fnd);
622 for (i = 0; i < len; i++) {
623 char c = (char) (unsigned char) mjson_escape(s[i]);
625 n += fn("\\", 1, fnd);
628 n += fn(&s[i], 1, fnd);
631 return n + fn("\"", 1, fnd);
634 #if MJSON_ENABLE_BASE64
635 int mjson_print_b64(mjson_print_fn_t fn, void *fnd, const unsigned char *s,
638 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
639 int i, len = fn("\"", 1, fnd);
640 for (i = 0; i < n; i += 3) {
641 int a = s[i], b = i + 1 < n ? s[i + 1] : 0, c = i + 2 < n ? s[i + 2] : 0;
642 char buf[4] = {t[a >> 2], t[(a & 3) << 4 | (b >> 4)], '=', '='};
643 if (i + 1 < n) buf[2] = t[(b & 15) << 2 | (c >> 6)];
644 if (i + 2 < n) buf[3] = t[c & 63];
645 len += fn(buf, sizeof(buf), fnd);
647 return len + fn("\"", 1, fnd);
649 #endif /* MJSON_ENABLE_BASE64 */
651 int mjson_vprintf(mjson_print_fn_t fn, void *fnd, const char *fmt,
654 while (fmt[i] != '\0') {
663 char *buf = va_arg(*ap, char *);
664 n += mjson_print_str(fn, fnd, buf ? buf : "",
665 buf ? (int) strlen(buf) : 0);
666 } else if (strncmp(&fmt[i], ".*Q", 3) == 0) {
667 int len = va_arg(*ap, int);
668 char *buf = va_arg(*ap, char *);
669 n += mjson_print_str(fn, fnd, buf, len);
671 } else if (fc == 'd' || fc == 'u') {
672 int is_signed = (fc == 'd');
674 long val = va_arg(*ap, long);
675 n += mjson_print_long(fn, fnd, val, is_signed);
678 int val = va_arg(*ap, int);
679 n += mjson_print_int(fn, fnd, val, is_signed);
681 } else if (fc == 'B') {
682 const char *s = va_arg(*ap, int) ? "true" : "false";
683 n += mjson_print_buf(fn, fnd, s, (int) strlen(s));
684 } else if (fc == 's') {
685 char *buf = va_arg(*ap, char *);
686 n += mjson_print_buf(fn, fnd, buf, (int) strlen(buf));
687 } else if (strncmp(&fmt[i], ".*s", 3) == 0) {
688 int len = va_arg(*ap, int);
689 char *buf = va_arg(*ap, char *);
690 n += mjson_print_buf(fn, fnd, buf, len);
692 } else if (fc == 'g') {
693 n += mjson_print_dbl(fn, fnd, va_arg(*ap, double), 6);
694 } else if (strncmp(&fmt[i], ".*g", 3) == 0) {
695 int width = va_arg(*ap, int);
696 n += mjson_print_dbl(fn, fnd, va_arg(*ap, double), width);
698 #if MJSON_ENABLE_BASE64
699 } else if (fc == 'V') {
700 int len = va_arg(*ap, int);
701 const char *buf = va_arg(*ap, const char *);
702 n += mjson_print_b64(fn, fnd, (const unsigned char *) buf, len);
704 } else if (fc == 'H') {
705 const char *hex = "0123456789abcdef";
706 int j, len = va_arg(*ap, int);
707 const unsigned char *p = va_arg(*ap, const unsigned char *);
708 n += fn("\"", 1, fnd);
709 for (j = 0; j < len; j++) {
710 n += fn(&hex[(p[j] >> 4) & 15], 1, fnd);
711 n += fn(&hex[p[j] & 15], 1, fnd);
713 n += fn("\"", 1, fnd);
714 } else if (fc == 'M') {
715 mjson_vprint_fn_t vfn = va_arg(*ap, mjson_vprint_fn_t);
716 n += vfn(fn, fnd, ap);
720 n += mjson_print_buf(fn, fnd, &fmt[i++], 1);
726 int mjson_printf(mjson_print_fn_t fn, void *fnd, const char *fmt, ...) {
730 len = mjson_vprintf(fn, fnd, fmt, &ap);
734 #endif /* MJSON_ENABLE_PRINT */
736 static int is_digit(int c) {
737 return c >= '0' && c <= '9';
740 /* NOTE: strtod() implementation by Yasuhiro Matsumoto. */
741 static double mystrtod(const char *str, const char **end) {
744 const char *p = str, *a = str;
750 } else if (*p == '+') {
754 d = (double) (*p++ - '0');
755 while (*p && is_digit(*p)) {
756 d = d * 10.0 + (double) (*p - '0');
760 } else if (*p != '.') {
772 while (*p && is_digit(*p)) {
773 f += base * (*p - '0');
782 /* exponential part */
783 if ((*p == 'E') || (*p == 'e')) {
784 int i, e = 0, neg = 0;
786 if (*p == '-') p++, neg++;
788 while (is_digit(*p)) e = e * 10 + *p++ - '0';
791 if (d == 2.2250738585072011 && e == -308) {
796 if (d == 2.2250738585072012 && e <= -308) {
802 for (i = 0; i < e; i++) d *= 10;
803 for (i = 0; i < -e; i++) d /= 10;
805 } else if (p > str && !is_digit(*(p - 1))) {
815 #if MJSON_ENABLE_MERGE
816 int mjson_merge(const char *s, int n, const char *s2, int n2,
817 mjson_print_fn_t fn, void *userdata) {
818 int koff, klen, voff, vlen, t, t2, k, off = 0, len = 0, comma = 0;
819 if (n < 2) return len;
820 len += fn("{", 1, userdata);
821 while ((off = mjson_next(s, n, off, &koff, &klen, &voff, &vlen, &t)) != 0) {
822 char *path = (char *) alloca((size_t) klen + 1);
824 memcpy(path, "$.", 2);
825 memcpy(path + 2, s + koff + 1, (size_t) (klen - 2));
827 if ((t2 = mjson_find(s2, n2, path, &val, &k)) != MJSON_TOK_INVALID) {
828 if (t2 == MJSON_TOK_NULL) continue; // null deletes the key
830 val = s + voff; // Key is not found in the update. Copy the old value.
832 if (comma) len += fn(",", 1, userdata);
833 len += fn(s + koff, klen, userdata);
834 len += fn(":", 1, userdata);
835 if (t == MJSON_TOK_OBJECT && t2 == MJSON_TOK_OBJECT) {
836 len += mjson_merge(s + voff, vlen, val, k, fn, userdata);
838 if (t2 != MJSON_TOK_INVALID) vlen = k;
839 len += fn(val, vlen, userdata);
845 while ((off = mjson_next(s2, n2, off, &koff, &klen, &voff, &vlen, &t)) != 0) {
846 char *path = (char *) alloca((size_t) klen + 1);
848 if (t == MJSON_TOK_NULL) continue;
849 memcpy(path, "$.", 2);
850 memcpy(path + 2, s2 + koff + 1, (size_t) (klen - 2));
852 if (mjson_find(s, n, path, &val, &vlen) != MJSON_TOK_INVALID) continue;
853 if (comma) len += fn(",", 1, userdata);
854 len += fn(s2 + koff, klen, userdata);
855 len += fn(":", 1, userdata);
856 len += fn(s2 + voff, vlen, userdata);
859 len += fn("}", 1, userdata);
862 #endif // MJSON_ENABLE_MERGE
864 #if MJSON_ENABLE_PRETTY
875 static int pretty_cb(int ev, const char *s, int off, int len, void *ud) {
876 struct prettydata *d = (struct prettydata *) ud;
882 d->len += d->fn(s + off, len, d->userdata);
887 if (d->prev != '[' && d->prev != '{' && d->padlen > 0) {
888 d->len += d->fn("\n", 1, d->userdata);
889 for (i = 0; i < d->level; i++)
890 d->len += d->fn(d->pad, d->padlen, d->userdata);
892 d->len += d->fn(s + off, len, d->userdata);
895 d->len += d->fn(s + off, len, d->userdata);
897 d->len += d->fn("\n", 1, d->userdata);
898 for (i = 0; i < d->level; i++)
899 d->len += d->fn(d->pad, d->padlen, d->userdata);
903 d->len += d->fn(s + off, len, d->userdata);
904 if (d->padlen > 0) d->len += d->fn(" ", 1, d->userdata);
907 if (d->prev == '{' && d->padlen > 0) {
908 d->len += d->fn("\n", 1, d->userdata);
909 for (i = 0; i < d->level; i++)
910 d->len += d->fn(d->pad, d->padlen, d->userdata);
912 d->len += d->fn(s + off, len, d->userdata);
915 if (d->prev == '[' && d->padlen > 0) {
916 d->len += d->fn("\n", 1, d->userdata);
917 for (i = 0; i < d->level; i++)
918 d->len += d->fn(d->pad, d->padlen, d->userdata);
920 d->len += d->fn(s + off, len, d->userdata);
927 int mjson_pretty(const char *s, int n, const char *pad, mjson_print_fn_t fn,
929 struct prettydata d = {0, 0, 0, pad, (int) strlen(pad), fn, userdata};
930 if (mjson(s, n, pretty_cb, &d) < 0) return -1;
933 #endif // MJSON_ENABLE_PRETTY
936 struct jsonrpc_ctx jsonrpc_default_context;
938 int mjson_globmatch(const char *s1, int n1, const char *s2, int n2) {
939 int i = 0, j = 0, ni = 0, nj = 0;
940 while (i < n1 || j < n2) {
941 if (i < n1 && j < n2 && (s1[i] == '?' || s2[j] == s1[i])) {
943 } else if (i < n1 && (s1[i] == '*' || s1[i] == '#')) {
944 ni = i, nj = j + 1, i++;
945 } else if (nj > 0 && nj <= n2 && (s1[i - 1] == '#' || s2[j] != '/')) {
954 void jsonrpc_return_errorv(struct jsonrpc_request *r, int code,
955 const char *message, const char *data_fmt,
957 if (r->id_len == 0) return;
958 mjson_printf(r->fn, r->fn_data,
959 "{\"id\":%.*s,\"error\":{\"code\":%d,\"message\":%Q", r->id_len,
960 r->id, code, message == NULL ? "" : message);
961 if (data_fmt != NULL) {
962 mjson_printf(r->fn, r->fn_data, ",\"data\":");
963 mjson_vprintf(r->fn, r->fn_data, data_fmt, ap);
965 mjson_printf(r->fn, r->fn_data, "}}\n");
968 void jsonrpc_return_error(struct jsonrpc_request *r, int code,
969 const char *message, const char *data_fmt, ...) {
971 va_start(ap, data_fmt);
972 jsonrpc_return_errorv(r, code, message, data_fmt, &ap);
976 void jsonrpc_return_successv(struct jsonrpc_request *r, const char *result_fmt,
978 if (r->id_len == 0) return;
979 mjson_printf(r->fn, r->fn_data, "{\"id\":%.*s,\"result\":", r->id_len, r->id);
980 if (result_fmt != NULL) {
981 mjson_vprintf(r->fn, r->fn_data, result_fmt, ap);
983 mjson_printf(r->fn, r->fn_data, "%s", "null");
985 mjson_printf(r->fn, r->fn_data, "}\n");
988 void jsonrpc_return_success(struct jsonrpc_request *r, const char *result_fmt,
991 va_start(ap, result_fmt);
992 jsonrpc_return_successv(r, result_fmt, &ap);
996 void jsonrpc_ctx_process(struct jsonrpc_ctx *ctx, const char *buf, int len,
997 mjson_print_fn_t fn, void *fn_data, void *ud) {
998 const char *result = NULL, *error = NULL;
999 int result_sz = 0, error_sz = 0;
1000 struct jsonrpc_method *m = NULL;
1001 struct jsonrpc_request r = {ctx, buf, len, 0, 0, 0, 0, 0, 0, fn, fn_data, ud};
1003 // Is is a response frame?
1004 mjson_find(buf, len, "$.result", &result, &result_sz);
1005 if (result == NULL) mjson_find(buf, len, "$.error", &error, &error_sz);
1006 if (result_sz > 0 || error_sz > 0) {
1007 if (ctx->response_cb) ctx->response_cb(buf, len, ctx->response_cb_data);
1011 // Method must exist and must be a string
1012 if (mjson_find(buf, len, "$.method", &r.method, &r.method_len) !=
1014 mjson_printf(fn, fn_data,
1015 "{\"error\":{\"code\":-32700,\"message\":%.*Q}}\n", len, buf);
1019 // id and params are optional
1020 mjson_find(buf, len, "$.id", &r.id, &r.id_len);
1021 mjson_find(buf, len, "$.params", &r.params, &r.params_len);
1023 for (m = ctx->methods; m != NULL; m = m->next) {
1024 if (mjson_globmatch(m->method, m->method_sz, r.method + 1,
1025 r.method_len - 2) > 0) {
1026 if (r.params == NULL) r.params = "";
1032 jsonrpc_return_error(&r, JSONRPC_ERROR_NOT_FOUND, "method not found", NULL);
1036 static int jsonrpc_print_methods(mjson_print_fn_t fn, void *fn_data,
1038 struct jsonrpc_ctx *ctx = va_arg(*ap, struct jsonrpc_ctx *);
1039 struct jsonrpc_method *m;
1041 for (m = ctx->methods; m != NULL; m = m->next) {
1042 if (m != ctx->methods) len += mjson_print_buf(fn, fn_data, ",", 1);
1043 len += mjson_print_str(fn, fn_data, m->method, (int) strlen(m->method));
1048 void jsonrpc_list(struct jsonrpc_request *r) {
1049 jsonrpc_return_success(r, "[%M]", jsonrpc_print_methods, r->ctx);
1052 void jsonrpc_ctx_init(struct jsonrpc_ctx *ctx, mjson_print_fn_t response_cb,
1053 void *response_cb_data) {
1054 ctx->methods = NULL;
1055 ctx->response_cb = response_cb;
1056 ctx->response_cb_data = response_cb_data;
1059 void jsonrpc_init(mjson_print_fn_t response_cb, void *userdata) {
1060 struct jsonrpc_ctx *ctx = &jsonrpc_default_context;
1061 jsonrpc_ctx_init(ctx, response_cb, userdata);
1062 jsonrpc_ctx_export(ctx, MJSON_RPC_LIST_NAME, jsonrpc_list);
1064 #endif // MJSON_ENABLE_RPC