1 /* This file is part of the YAZ toolkit.
2 * Copyright (C) 1995-2009 Index Data
3 * See the file LICENSE for details.
8 * \brief JSON encoding/decoding
19 #include <yaz/xmalloc.h>
21 struct json_parser_s {
27 json_parser_t json_parser_create(void)
29 json_parser_t p = (json_parser_t) xmalloc(sizeof(*p));
37 void json_parser_destroy(json_parser_t p)
42 static int look_ch(json_parser_t p)
44 while (*p->cp && strchr(" \t\r\n\f", *p->cp))
49 static void move_ch(json_parser_t p)
55 static struct json_node *json_new_node(json_parser_t p, enum json_node_type type)
57 struct json_node *n = (struct json_node *) xmalloc(sizeof(*n));
59 n->u.link[0] = n->u.link[1] = 0;
63 void json_remove_node(struct json_node *n)
69 case json_node_object:
73 json_remove_node(n->u.link[0]);
74 json_remove_node(n->u.link[1]);
76 case json_node_string:
79 case json_node_number:
88 static struct json_node *json_parse_object(json_parser_t p);
89 static struct json_node *json_parse_array(json_parser_t p);
91 static int json_one_char(const char **p, char *out)
93 if (**p == '\\' && p[0][1])
120 size_t outbytesleft = 6;
121 sscanf(*p + 1, "%4x", &code);
122 if (!yaz_write_UTF8_char(code, &outp, &outbytesleft, &error))
143 static struct json_node *json_parse_string(json_parser_t p)
149 if (look_ch(p) != '\"')
151 p->err_msg = "string expected";
157 while (*cp && *cp != '"')
160 l += json_one_char(&cp, out);
164 p->err_msg = "missing \"";
167 n = json_new_node(p, json_node_string);
168 dst = n->u.string = (char *) xmalloc(l + 1);
171 while (*cp && *cp != '"')
175 l = json_one_char(&cp, out);
184 static struct json_node *json_parse_number(json_parser_t p)
190 look_ch(p); // skip spaces
191 v = strtod(p->cp, &endptr);
195 p->err_msg = "bad number";
199 n = json_new_node(p, json_node_number);
204 static struct json_node *json_parse_value(json_parser_t p)
208 return json_parse_string(p);
209 else if (strchr("0123456789-+", c))
210 return json_parse_number(p);
212 return json_parse_object(p);
214 return json_parse_array(p);
219 while (c >= 'a' && c <= 'z' && i < 7)
226 if (!strcmp(tok, "true"))
227 return json_new_node(p, json_node_true);
228 else if (!strcmp(tok, "false"))
229 return json_new_node(p, json_node_false);
230 else if (!strcmp(tok, "null"))
231 return json_new_node(p, json_node_null);
234 p->err_msg = "bad value";
240 static struct json_node *json_parse_elements(json_parser_t p)
242 struct json_node *n1 = json_parse_value(p);
243 struct json_node *m0, *m1;
246 m0 = m1 = json_new_node(p, json_node_list);
248 while (look_ch(p) == ',')
250 struct json_node *n2, *m2;
252 n2 = json_parse_value(p);
255 json_remove_node(m0);
258 m2 = json_new_node(p, json_node_list);
267 static struct json_node *json_parse_array(json_parser_t p)
270 if (look_ch(p) != '[')
272 p->err_msg = "expecting [";
276 n = json_new_node(p, json_node_array);
277 if (look_ch(p) != ']')
278 n->u.link[0] = json_parse_elements(p);
280 if (look_ch(p) != ']')
282 p->err_msg = "expecting ]";
290 static struct json_node *json_parse_pair(json_parser_t p)
292 struct json_node *s = json_parse_string(p);
293 struct json_node *v, *n;
296 if (look_ch(p) != ':')
302 v = json_parse_value(p);
308 n = json_new_node(p, json_node_pair);
314 static struct json_node *json_parse_members(json_parser_t p)
316 struct json_node *n1 = json_parse_pair(p);
317 struct json_node *m0, *m1;
320 m0 = m1 = json_new_node(p, json_node_list);
322 while (look_ch(p) == ',')
324 struct json_node *n2, *m2;
326 n2 = json_parse_pair(p);
329 json_remove_node(m0);
332 m2 = json_new_node(p, json_node_list);
341 static struct json_node *json_parse_object(json_parser_t p)
344 if (look_ch(p) != '{')
346 p->err_msg = "{ expected";
351 n = json_new_node(p, json_node_object);
352 if (look_ch(p) != '}')
354 struct json_node *m = json_parse_members(p);
362 if (look_ch(p) != '}')
364 p->err_msg = "Missing }";
372 struct json_node *json_parser_parse(json_parser_t p, const char *json_str)
379 n = json_parse_object(p);
383 p->err_msg = "extra characters";
390 void json_write_wrbuf(struct json_node *node, WRBUF result)
394 case json_node_object:
395 wrbuf_puts(result, "{");
397 json_write_wrbuf(node->u.link[0], result);
398 wrbuf_puts(result, "}");
400 case json_node_array:
401 wrbuf_puts(result, "[");
403 json_write_wrbuf(node->u.link[0], result);
404 wrbuf_puts(result, "]");
407 json_write_wrbuf(node->u.link[0], result);
410 wrbuf_puts(result, ",");
411 json_write_wrbuf(node->u.link[1], result);
415 json_write_wrbuf(node->u.link[0], result);
416 wrbuf_puts(result, ":");
417 json_write_wrbuf(node->u.link[1], result);
419 case json_node_string:
420 wrbuf_puts(result, "\"");
421 wrbuf_puts(result, node->u.string);
422 wrbuf_puts(result, "\"");
424 case json_node_number:
425 wrbuf_printf(result, "%lg", node->u.number);
428 wrbuf_puts(result, "true");
430 case json_node_false:
431 wrbuf_puts(result, "false");
434 wrbuf_puts(result, "null");
439 const char *json_parser_get_errmsg(json_parser_t p)
447 * c-file-style: "Stroustrup"
448 * indent-tabs-mode: nil
450 * vim: shiftwidth=4 tabstop=8 expandtab