/* This file is part of the YAZ toolkit.
- * Copyright (C) 1995-2010 Index Data
+ * Copyright (C) 1995-2013 Index Data
* See the file LICENSE for details.
*/
-
/**
* \file json.c
* \brief JSON encoding/decoding
*/
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
#include <yaz/json.h>
json_parser_t json_parser_create(void)
{
json_parser_t p = (json_parser_t) xmalloc(sizeof(*p));
-
+
p->buf = 0;
p->cp = 0;
p->err_msg = 0;
case 'b':
*out = '\b'; break;
case 'f':
- *out = '\b'; break;
+ *out = '\f'; break;
case 'n':
*out = '\n'; break;
case 'r':
}
n = json_new_node(p, json_node_string);
dst = n->u.string = (char *) xmalloc(l + 1);
-
+
cp = p->cp;
while (*cp && *cp != '"')
{
}
m2 = json_new_node(p, json_node_list);
m2->u.link[0] = n2;
-
+
m1->u.link[1] = m2;
m1 = m2;
}
}
m2 = json_new_node(p, json_node_list);
m2->u.link[0] = n2;
-
+
m1->u.link[1] = m2;
m1 = m2;
}
return n;
}
-struct json_node *json_parse(const char *json_str, const char **errmsg)
+struct json_node *json_parse2(const char *json_str, const char **errmsg,
+ size_t *pos)
{
json_parser_t p = json_parser_create();
struct json_node *n = 0;
n = json_parser_parse(p, json_str);
if (!n && errmsg)
*errmsg = json_parser_get_errmsg(p);
+ if (pos)
+ *pos = json_parser_get_position(p);
json_parser_destroy(p);
}
return n;
}
-void json_write_wrbuf(struct json_node *node, WRBUF result)
+struct json_node *json_parse(const char *json_str, const char **errmsg)
+{
+ return json_parse2(json_str, errmsg, 0);
+}
+
+static void wrbuf_json_write(WRBUF b, const char *cp, size_t sz)
{
+ size_t i;
+ for (i = 0; i < sz; i++)
+ {
+ if (cp[i] > 0 && cp[i] < 32)
+ {
+ wrbuf_putc(b, '\\');
+ switch (cp[i])
+ {
+ case '\b': wrbuf_putc(b, 'b'); break;
+ case '\f': wrbuf_putc(b, 'f'); break;
+ case '\n': wrbuf_putc(b, 'n'); break;
+ case '\r': wrbuf_putc(b, 'r'); break;
+ case '\t': wrbuf_putc(b, 't'); break;
+ default:
+ wrbuf_printf(b, "u%04x", cp[i]);
+ }
+ }
+ else if (cp[i] == '"')
+ {
+ wrbuf_putc(b, '\\'); wrbuf_putc(b, '"');
+ }
+ else if (cp[i] == '\\')
+ {
+ wrbuf_putc(b, '\\'); wrbuf_putc(b, '\\');
+ }
+ else
+ { /* leave encoding as raw UTF-8 */
+ wrbuf_putc(b, cp[i]);
+ }
+ }
+
+}
+
+void wrbuf_json_puts(WRBUF b, const char *str)
+{
+ wrbuf_json_write(b, str, strlen(str));
+}
+
+static void json_indent(WRBUF result, int indent)
+{
+ size_t l = wrbuf_len(result);
+ if (l == 0 || wrbuf_buf(result)[l-1] == '\n')
+ {
+ int i;
+ for (i = 0; i < indent; i++)
+ wrbuf_putc(result, ' ');
+ }
+}
+
+static void json_write_wrbuf_r(struct json_node *node, WRBUF result, int indent)
+{
+ int sub_indent = -1;
+ if (indent >= 0)
+ sub_indent = indent + 1;
switch (node->type)
{
case json_node_object:
+ json_indent(result, indent);
wrbuf_puts(result, "{");
+ if (indent >= 0)
+ {
+ wrbuf_puts(result, "\n");
+ json_indent(result, sub_indent);
+ }
if (node->u.link[0])
- json_write_wrbuf(node->u.link[0], result);
+ json_write_wrbuf_r(node->u.link[0], result, sub_indent);
+ if (indent >= 0)
+ {
+ wrbuf_puts(result, "\n");
+ json_indent(result, indent);
+ }
wrbuf_puts(result, "}");
break;
case json_node_array:
+ json_indent(result, indent);
wrbuf_puts(result, "[");
+ if (indent >= 0)
+ {
+ wrbuf_puts(result, "\n");
+ json_indent(result, sub_indent);
+ }
if (node->u.link[0])
- json_write_wrbuf(node->u.link[0], result);
+ {
+ json_write_wrbuf_r(node->u.link[0], result, sub_indent);
+ }
+ if (indent >= 0)
+ {
+ wrbuf_puts(result, "\n");
+ json_indent(result, indent);
+ }
wrbuf_puts(result, "]");
break;
case json_node_list:
- json_write_wrbuf(node->u.link[0], result);
+ json_write_wrbuf_r(node->u.link[0], result, indent);
if (node->u.link[1])
{
wrbuf_puts(result, ",");
- json_write_wrbuf(node->u.link[1], result);
+ if (indent >= 0)
+ wrbuf_puts(result, " ");
+ json_write_wrbuf_r(node->u.link[1], result, indent);
}
break;
case json_node_pair:
- json_write_wrbuf(node->u.link[0], result);
+ json_write_wrbuf_r(node->u.link[0], result, indent);
wrbuf_puts(result, ":");
- json_write_wrbuf(node->u.link[1], result);
+ if (indent >= 0)
+ wrbuf_puts(result, " ");
+ json_write_wrbuf_r(node->u.link[1], result, indent);
break;
case json_node_string:
wrbuf_puts(result, "\"");
- wrbuf_puts(result, node->u.string);
+ wrbuf_json_puts(result, node->u.string);
wrbuf_puts(result, "\"");
break;
case json_node_number:
}
}
+void json_write_wrbuf_pretty(struct json_node *node, WRBUF result)
+{
+ json_write_wrbuf_r(node, result, 1);
+}
+
+void json_write_wrbuf(struct json_node *node, WRBUF result)
+{
+ json_write_wrbuf_r(node, result, -1);
+}
+
static struct json_node **json_get_objectp(struct json_node *n,
const char *name)
{
struct json_node *json_get_object(struct json_node *n, const char *name)
{
struct json_node **np = json_get_objectp(n, name);
-
+
if (np)
return *np;
return 0;
struct json_node *json_detach_object(struct json_node *n, const char *name)
{
struct json_node **np = json_get_objectp(n, name);
-
+
if (np)
{
struct json_node *n = *np;
return p->err_msg;
}
+size_t json_parser_get_position(json_parser_t p)
+{
+ return p->cp - p->buf;
+}
+
/*
* Local variables:
* c-basic-offset: 4