1 /* This file is part of the YAZ toolkit.
2 * Copyright (C) 1995-2012 Index Data
3 * See the file LICENSE for details.
7 * \brief JSON encoding/decoding
21 #include <yaz/xmalloc.h>
23 struct json_subst_info {
25 struct json_subst_info *next;
26 struct json_node *node;
29 struct json_parser_s {
33 struct json_subst_info *subst;
36 json_parser_t json_parser_create(void)
38 json_parser_t p = (json_parser_t) xmalloc(sizeof(*p));
47 void json_parser_subst(json_parser_t p, int idx, struct json_node *n)
49 struct json_subst_info **sb = &p->subst;
50 for (; *sb; sb = &(*sb)->next)
51 if ((*sb)->idx == idx)
56 *sb = xmalloc(sizeof(**sb));
62 void json_parser_destroy(json_parser_t p)
64 struct json_subst_info *sb = p->subst;
67 struct json_subst_info *sb_next = sb->next;
74 static int look_ch(json_parser_t p)
76 while (*p->cp && strchr(" \t\r\n\f", *p->cp))
81 static void move_ch(json_parser_t p)
87 static struct json_node *json_new_node(json_parser_t p, enum json_node_type type)
89 struct json_node *n = (struct json_node *) xmalloc(sizeof(*n));
91 n->u.link[0] = n->u.link[1] = 0;
95 void json_remove_node(struct json_node *n)
101 case json_node_object:
102 case json_node_array:
105 json_remove_node(n->u.link[0]);
106 json_remove_node(n->u.link[1]);
108 case json_node_string:
111 case json_node_number:
113 case json_node_false:
120 static struct json_node *json_parse_object(json_parser_t p);
121 static struct json_node *json_parse_array(json_parser_t p);
123 static int json_one_char(const char **p, char *out)
125 if (**p == '\\' && p[0][1])
152 size_t outbytesleft = 6;
153 sscanf(*p + 1, "%4x", &code);
154 if (!yaz_write_UTF8_char(code, &outp, &outbytesleft, &error))
175 static struct json_node *json_parse_string(json_parser_t p)
181 if (look_ch(p) != '\"')
183 p->err_msg = "string expected";
189 while (*cp && *cp != '"')
192 l += json_one_char(&cp, out);
196 p->err_msg = "missing \"";
199 n = json_new_node(p, json_node_string);
200 dst = n->u.string = (char *) xmalloc(l + 1);
203 while (*cp && *cp != '"')
207 l = json_one_char(&cp, out);
216 static struct json_node *json_parse_number(json_parser_t p)
222 look_ch(p); // skip spaces
223 v = strtod(p->cp, &endptr);
227 p->err_msg = "bad number";
231 n = json_new_node(p, json_node_number);
236 static struct json_node *json_parse_value(json_parser_t p)
240 return json_parse_string(p);
241 else if (strchr("0123456789-+", c))
242 return json_parse_number(p);
244 return json_parse_object(p);
246 return json_parse_array(p);
249 struct json_subst_info *sb;
253 while (c >= '0' && c <= '9')
255 idx = idx*10 + (c - '0');
259 for (sb = p->subst; sb; sb = sb->next)
267 while (c >= 'a' && c <= 'z' && i < 7)
274 if (!strcmp(tok, "true"))
275 return json_new_node(p, json_node_true);
276 else if (!strcmp(tok, "false"))
277 return json_new_node(p, json_node_false);
278 else if (!strcmp(tok, "null"))
279 return json_new_node(p, json_node_null);
281 p->err_msg = "bad token";
285 static struct json_node *json_parse_elements(json_parser_t p)
287 struct json_node *n1 = json_parse_value(p);
288 struct json_node *m0, *m1;
291 m0 = m1 = json_new_node(p, json_node_list);
293 while (look_ch(p) == ',')
295 struct json_node *n2, *m2;
297 n2 = json_parse_value(p);
300 json_remove_node(m0);
303 m2 = json_new_node(p, json_node_list);
312 static struct json_node *json_parse_array(json_parser_t p)
315 if (look_ch(p) != '[')
317 p->err_msg = "expecting [";
321 n = json_new_node(p, json_node_array);
322 if (look_ch(p) != ']')
323 n->u.link[0] = json_parse_elements(p);
325 if (look_ch(p) != ']')
327 p->err_msg = "expecting ]";
335 static struct json_node *json_parse_pair(json_parser_t p)
337 struct json_node *s = json_parse_string(p);
338 struct json_node *v, *n;
341 if (look_ch(p) != ':')
343 p->err_msg = "missing :";
348 v = json_parse_value(p);
354 n = json_new_node(p, json_node_pair);
360 static struct json_node *json_parse_members(json_parser_t p)
362 struct json_node *n1 = json_parse_pair(p);
363 struct json_node *m0, *m1;
366 m0 = m1 = json_new_node(p, json_node_list);
368 while (look_ch(p) == ',')
370 struct json_node *n2, *m2;
372 n2 = json_parse_pair(p);
375 json_remove_node(m0);
378 m2 = json_new_node(p, json_node_list);
387 static struct json_node *json_parse_object(json_parser_t p)
390 if (look_ch(p) != '{')
392 p->err_msg = "{ expected";
397 n = json_new_node(p, json_node_object);
398 if (look_ch(p) != '}')
400 struct json_node *m = json_parse_members(p);
408 if (look_ch(p) != '}')
410 p->err_msg = "Missing }";
418 struct json_node *json_parser_parse(json_parser_t p, const char *json_str)
425 n = json_parse_value(p);
431 p->err_msg = "extra characters";
438 struct json_node *json_parse2(const char *json_str, const char **errmsg,
441 json_parser_t p = json_parser_create();
442 struct json_node *n = 0;
446 *errmsg = "could not create parser";
450 n = json_parser_parse(p, json_str);
452 *errmsg = json_parser_get_errmsg(p);
454 *pos = json_parser_get_position(p);
455 json_parser_destroy(p);
460 struct json_node *json_parse(const char *json_str, const char **errmsg)
462 return json_parse2(json_str, errmsg, 0);
465 static void wrbuf_json_write(WRBUF b, const char *cp, size_t sz)
468 for (i = 0; i < sz; i++)
470 if (cp[i] > 0 && cp[i] < 32)
475 case '\b': wrbuf_putc(b, 'b'); break;
476 case '\f': wrbuf_putc(b, 'f'); break;
477 case '\n': wrbuf_putc(b, 'n'); break;
478 case '\r': wrbuf_putc(b, 'r'); break;
479 case '\t': wrbuf_putc(b, 't'); break;
481 wrbuf_printf(b, "u%04x", cp[i]);
484 else if (cp[i] == '"')
486 wrbuf_putc(b, '\\'); wrbuf_putc(b, '"');
488 else if (cp[i] == '\\')
490 wrbuf_putc(b, '\\'); wrbuf_putc(b, '\\');
493 { /* leave encoding as raw UTF-8 */
494 wrbuf_putc(b, cp[i]);
500 void wrbuf_json_puts(WRBUF b, const char *str)
502 wrbuf_json_write(b, str, strlen(str));
505 void json_write_wrbuf(struct json_node *node, WRBUF result)
509 case json_node_object:
510 wrbuf_puts(result, "{");
512 json_write_wrbuf(node->u.link[0], result);
513 wrbuf_puts(result, "}");
515 case json_node_array:
516 wrbuf_puts(result, "[");
518 json_write_wrbuf(node->u.link[0], result);
519 wrbuf_puts(result, "]");
522 json_write_wrbuf(node->u.link[0], result);
525 wrbuf_puts(result, ",");
526 json_write_wrbuf(node->u.link[1], result);
530 json_write_wrbuf(node->u.link[0], result);
531 wrbuf_puts(result, ":");
532 json_write_wrbuf(node->u.link[1], result);
534 case json_node_string:
535 wrbuf_puts(result, "\"");
536 wrbuf_json_puts(result, node->u.string);
537 wrbuf_puts(result, "\"");
539 case json_node_number:
540 wrbuf_printf(result, "%lg", node->u.number);
543 wrbuf_puts(result, "true");
545 case json_node_false:
546 wrbuf_puts(result, "false");
549 wrbuf_puts(result, "null");
554 static struct json_node **json_get_objectp(struct json_node *n,
557 if (n && n->type == json_node_object)
559 for (n = n->u.link[0]; n; n = n->u.link[1])
561 struct json_node *c = n->u.link[0];
562 if (c && c->type == json_node_pair &&
563 c->u.link[0] && c->u.link[0]->type == json_node_string)
564 if (!strcmp(name, c->u.link[0]->u.string))
565 return &c->u.link[1];
571 struct json_node *json_get_object(struct json_node *n, const char *name)
573 struct json_node **np = json_get_objectp(n, name);
580 struct json_node *json_detach_object(struct json_node *n, const char *name)
582 struct json_node **np = json_get_objectp(n, name);
586 struct json_node *n = *np;
593 struct json_node *json_get_elem(struct json_node *n, int idx)
595 if (n && n->type == json_node_array)
597 for (n = n->u.link[0]; n; n = n->u.link[1])
606 int json_count_children(struct json_node *n)
610 if (n && (n->type == json_node_array || n->type == json_node_object))
612 for (n = n->u.link[0]; n; n = n->u.link[1])
618 int json_append_array(struct json_node *dst, struct json_node *src)
621 dst->type == json_node_array && src->type == json_node_array)
623 struct json_node **np = &dst->u.link[0];
625 np = &(*np)->u.link[1];
626 *np = src->u.link[0];
628 json_remove_node(src);
634 const char *json_parser_get_errmsg(json_parser_t p)
639 size_t json_parser_get_position(json_parser_t p)
641 return p->cp - p->buf;
647 * c-file-style: "Stroustrup"
648 * indent-tabs-mode: nil
650 * vim: shiftwidth=4 tabstop=8 expandtab