/* This file is part of the YAZ toolkit.
- * Copyright (C) 1995-2009 Index Data
+ * Copyright (C) 1995-2010 Index Data
* See the file LICENSE for details.
*/
#include <yaz/xmalloc.h>
+struct json_subst_info {
+ int idx;
+ struct json_subst_info *next;
+ struct json_node *node;
+};
+
struct json_parser_s {
const char *buf;
const char *cp;
const char *err_msg;
+ struct json_subst_info *subst;
};
json_parser_t json_parser_create(void)
p->buf = 0;
p->cp = 0;
p->err_msg = 0;
+ p->subst = 0;
return p;
}
+void json_parser_subst(json_parser_t p, int idx, struct json_node *n)
+{
+ struct json_subst_info **sb = &p->subst;
+ for (; *sb; sb = &(*sb)->next)
+ if ((*sb)->idx == idx)
+ {
+ (*sb)->node = n;
+ return;
+ }
+ *sb = xmalloc(sizeof(**sb));
+ (*sb)->next = 0;
+ (*sb)->node = n;
+ (*sb)->idx = idx;
+}
+
void json_parser_destroy(json_parser_t p)
{
+ struct json_subst_info *sb = p->subst;
+ while (sb)
+ {
+ struct json_subst_info *sb_next = sb->next;
+ xfree(sb);
+ sb = sb_next;
+ }
xfree(p);
}
case 'b':
*out = '\b'; break;
case 'f':
- *out = '\b'; break;
+ *out = '\f'; break;
case 'n':
*out = '\n'; break;
case 'r':
return json_parse_object(p);
else if (c == '[')
return json_parse_array(p);
+ else if (c == '%')
+ {
+ struct json_subst_info *sb;
+ int idx = 0;
+ p->cp++;
+ c = *p->cp;
+ while (c >= '0' && c <= '9')
+ {
+ idx = idx*10 + (c - '0');
+ p->cp++;
+ c = *p->cp;
+ }
+ for (sb = p->subst; sb; sb = sb->next)
+ if (sb->idx == idx)
+ return sb->node;
+ }
else
{
char tok[8];
return json_new_node(p, json_node_false);
else if (!strcmp(tok, "null"))
return json_new_node(p, json_node_null);
- else
- {
- p->err_msg = "bad value";
- return 0;
- }
}
+ p->err_msg = "bad token";
+ return 0;
}
static struct json_node *json_parse_elements(json_parser_t p)
return 0;
if (look_ch(p) != ':')
{
+ p->err_msg = "missing :";
json_remove_node(s);
return 0;
}
p->buf = json_str;
p->cp = p->buf;
- n = json_parse_object(p);
+ n = json_parse_value(p);
+ if (!n)
+ return 0;
c = look_ch(p);
if (c != 0)
{
return n;
}
+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;
+ if (!p)
+ {
+ if (errmsg)
+ *errmsg = "could not create parser";
+ }
+ else
+ {
+ 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;
+}
+
+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)
+{
+ return wrbuf_json_write(b, str, strlen(str));
+}
+
void json_write_wrbuf(struct json_node *node, WRBUF result)
{
switch (node->type)
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:
}
}
+static struct json_node **json_get_objectp(struct json_node *n,
+ const char *name)
+{
+ if (n && n->type == json_node_object)
+ {
+ for (n = n->u.link[0]; n; n = n->u.link[1])
+ {
+ struct json_node *c = n->u.link[0];
+ if (c && c->type == json_node_pair &&
+ c->u.link[0] && c->u.link[0]->type == json_node_string)
+ if (!strcmp(name, c->u.link[0]->u.string))
+ return &c->u.link[1];
+ }
+ }
+ return 0;
+}
+
+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;
+ *np = 0;
+ return n;
+ }
+ return 0;
+}
+
+struct json_node *json_get_elem(struct json_node *n, int idx)
+{
+ if (n && n->type == json_node_array)
+ {
+ for (n = n->u.link[0]; n; n = n->u.link[1])
+ {
+ if (--idx < 0)
+ return n->u.link[0];
+ }
+ }
+ return 0;
+}
+
+int json_count_children(struct json_node *n)
+{
+ int i = 0;
+
+ if (n && (n->type == json_node_array || n->type == json_node_object))
+ {
+ for (n = n->u.link[0]; n; n = n->u.link[1])
+ i++;
+ }
+ return i;
+}
+
+int json_append_array(struct json_node *dst, struct json_node *src)
+{
+ if (dst && src &&
+ dst->type == json_node_array && src->type == json_node_array)
+ {
+ struct json_node **np = &dst->u.link[0];
+ while (*np)
+ np = &(*np)->u.link[1];
+ *np = src->u.link[0];
+ src->u.link[0] = 0;
+ json_remove_node(src);
+ return 0;
+ }
+ return -1;
+}
+
const char *json_parser_get_errmsg(json_parser_t p)
{
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