X-Git-Url: http://git.indexdata.com/?p=yaz-moved-to-github.git;a=blobdiff_plain;f=src%2Fjson.c;h=91cb4e47eb7493b773b3bfa47f168be3284a5668;hp=41b99ebba7fa202e3be24c20353e9d246504cb17;hb=a606039bceb5fb70f8ea8cfd88261f6f25ccc736;hpb=8cd41e6a09e7279587dc29774669fbc13685566d diff --git a/src/json.c b/src/json.c index 41b99eb..91cb4e4 100644 --- a/src/json.c +++ b/src/json.c @@ -1,5 +1,5 @@ /* 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. */ @@ -18,10 +18,17 @@ #include +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) @@ -31,11 +38,34 @@ 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); } @@ -104,7 +134,7 @@ static int json_one_char(const char **p, char *out) case 'b': *out = '\b'; break; case 'f': - *out = '\b'; break; + *out = '\f'; break; case 'n': *out = '\n'; break; case 'r': @@ -212,6 +242,22 @@ static struct json_node *json_parse_value(json_parser_t p) 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]; @@ -229,12 +275,9 @@ static struct json_node *json_parse_value(json_parser_t p) 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) @@ -295,6 +338,7 @@ static struct json_node *json_parse_pair(json_parser_t p) return 0; if (look_ch(p) != ':') { + p->err_msg = "missing :"; json_remove_node(s); return 0; } @@ -376,7 +420,9 @@ struct json_node *json_parser_parse(json_parser_t p, const char *json_str) 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) { @@ -387,6 +433,73 @@ struct json_node *json_parser_parse(json_parser_t p, const char *json_str) 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) +{ + wrbuf_json_write(b, str, strlen(str)); +} + void json_write_wrbuf(struct json_node *node, WRBUF result) { switch (node->type) @@ -418,7 +531,7 @@ void json_write_wrbuf(struct json_node *node, WRBUF result) 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: @@ -436,11 +549,96 @@ void json_write_wrbuf(struct json_node *node, WRBUF result) } } +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