YAZ 5.35.1
json.c
Go to the documentation of this file.
1/* This file is part of the YAZ toolkit.
2 * Copyright (C) Index Data
3 * See the file LICENSE for details.
4 */
9#if HAVE_CONFIG_H
10#include <config.h>
11#endif
12
13#include <yaz/json.h>
14
15#include <stdlib.h>
16#include <errno.h>
17#include <string.h>
18#include <assert.h>
19#include <stdio.h>
20
21#include <yaz/xmalloc.h>
22
24 int idx;
26 struct json_node *node;
27};
28
30 const char *buf;
31 const char *cp;
32 const char *err_msg;
36};
37
39{
40 json_parser_t p = (json_parser_t) xmalloc(sizeof(*p));
41
42 p->buf = 0;
43 p->cp = 0;
44 p->subst = 0;
45 return p;
46}
47
49{
50 struct json_subst_info **sb = &p->subst;
51 for (; *sb; sb = &(*sb)->next)
52 if ((*sb)->idx == idx)
53 {
54 (*sb)->node = n;
55 return;
56 }
57 *sb = xmalloc(sizeof(**sb));
58 (*sb)->next = 0;
59 (*sb)->node = n;
60 (*sb)->idx = idx;
61}
62
64{
65 struct json_subst_info *sb = p->subst;
66 while (sb)
67 {
68 struct json_subst_info *sb_next = sb->next;
69 xfree(sb);
70 sb = sb_next;
71 }
72 xfree(p);
73}
74
76{
77 while (*p->cp && strchr(" \t\r\n", *p->cp))
78 (p->cp)++;
79 return *p->cp;
80}
81
82static void move_ch(json_parser_t p)
83{
84 if (*p->cp)
85 (p->cp)++;
86}
87
89{
90 struct json_node *n = (struct json_node *) xmalloc(sizeof(*n));
91 n->type = type;
92 n->u.link[0] = n->u.link[1] = 0;
93 return n;
94}
95
97{
98 if (!n)
99 return;
100 switch (n->type)
101 {
102 case json_node_object:
103 case json_node_array:
104 case json_node_list:
105 case json_node_pair:
106 json_remove_node(n->u.link[0]);
107 json_remove_node(n->u.link[1]);
108 break;
109 case json_node_string:
110 xfree(n->u.string);
111 break;
112 case json_node_number:
113 case json_node_true:
114 case json_node_false:
115 case json_node_null:
116 break;
117 }
118 xfree(n);
119}
120
123
124static int json_one_char(const char **p, char *out)
125{
126 if (**p == '\\' && p[0][1])
127 {
128 (*p)++;
129 switch(**p)
130 {
131 case '"':
132 *out = '"'; break;
133 case '\\':
134 *out = '\\'; break;
135 case '/':
136 *out = '/'; break;
137 case 'b':
138 *out = '\b'; break;
139 case 'f':
140 *out = '\f'; break;
141 case 'n':
142 *out = '\n'; break;
143 case 'r':
144 *out = '\r'; break;
145 case 't':
146 *out = '\t'; break;
147 case 'u':
148 if (p[0][1] > 0 && p[0][2] > 0 && p[0][3] > 0 && p[0][4] > 0)
149 {
150 unsigned code;
151 char *outp = out;
152 int error;
153 size_t outbytesleft = 6;
154 int no_read = 0;
155 sscanf(*p + 1, "%4x%n", &code, &no_read);
156 if (no_read != 4)
157 return 0;
158 if (!yaz_write_UTF8_char(code, &outp, &outbytesleft, &error))
159 {
160 *p += 5;
161 return outp - out;
162 }
163 }
164 default:
165 return 0;
166 }
167 (*p)++;
168 return 1;
169 }
170 else if (**p > 0 && **p <= 31)
171 {
172 return 0;
173 }
174 else
175 {
176 *out = **p;
177 (*p)++;
178 return 1;
179 }
180}
181
183{
184 struct json_node *n;
185 const char *cp;
186 char *dst;
187 int l = 0;
188 if (look_ch(p) != '\"')
189 {
190 p->err_msg = "string expected";
191 return 0;
192 }
193 move_ch(p);
194
195 cp = p->cp;
196 while (*cp && *cp != '"')
197 {
198 char out[6];
199 int r = json_one_char(&cp, out);
200 if (r == 0)
201 {
202 p->err_msg = "invalid character";
203 return 0;
204 }
205 l += r;
206 }
207 if (!*cp)
208 {
209 p->err_msg = "missing \"";
210 return 0;
211 }
213 dst = n->u.string = (char *) xmalloc(l + 1);
214
215 cp = p->cp;
216 while (*cp && *cp != '"')
217 {
218 char out[6];
219
220 l = json_one_char(&cp, out);
221 memcpy(dst, out, l);
222 dst += l;
223 }
224 *dst = '\0';
225 p->cp = cp+1;
226 return n;
227}
228
230{
231 struct json_node *n;
232 char *endptr;
233 const char *cp;
234 double v;
235
236 cp = p->cp;
237 if (*cp == '-')
238 cp++;
239 if (*cp == '0')
240 cp++;
241 else if (*cp >= '1' && *cp <= '9')
242 {
243 cp++;
244 while (*cp >= '0' && *cp <= '9')
245 cp++;
246 }
247 else
248 {
249 p->err_msg = "bad number";
250 return 0;
251 }
252 if (*cp == '.')
253 {
254 cp++;
255 if (*cp >= '0' && *cp <= '9')
256 {
257 while (*cp >= '0' && *cp <= '9')
258 cp++;
259 }
260 else
261 {
262 p->err_msg = "bad number";
263 return 0;
264 }
265 }
266 if (*cp == 'e' || *cp == 'E')
267 {
268 cp++;
269 if (*cp == '+' || *cp == '-')
270 cp++;
271 if (*cp >= '0' && *cp <= '9')
272 {
273 while (*cp >= '0' && *cp <= '9')
274 cp++;
275 }
276 else
277 {
278 p->err_msg = "bad number";
279 return 0;
280 }
281 }
282 v = strtod(p->cp, &endptr);
283
284 if (endptr == p->cp)
285 {
286 p->err_msg = "bad number";
287 return 0;
288 }
289 if (endptr != cp)
290 {
291 p->err_msg = "bad number";
292 return 0;
293 }
294 p->cp = endptr;
296 n->u.number = v;
297 return n;
298}
299
301{
302 int c = look_ch(p);
303 if (c == '\"')
304 return json_parse_string(p);
305 else if (strchr("0123456789-", c))
306 return json_parse_number(p);
307 else if (c == '{')
308 return json_parse_object(p);
309 else if (c == '[')
310 return json_parse_array(p);
311 else if (c == '%')
312 {
313 struct json_subst_info *sb;
314 int idx = 0;
315 p->cp++;
316 c = *p->cp;
317 while (c >= '0' && c <= '9')
318 {
319 idx = idx*10 + (c - '0');
320 p->cp++;
321 c = *p->cp;
322 }
323 for (sb = p->subst; sb; sb = sb->next)
324 if (sb->idx == idx)
325 return sb->node;
326 }
327 else if (c == 0)
328 {
329 return 0;
330 }
331 else
332 {
333 char tok[8];
334 int i = 0;
335 while (c >= 'a' && c <= 'z' && i < 7)
336 {
337 tok[i++] = c;
338 p->cp++;
339 c = *p->cp;
340 }
341 tok[i] = 0;
342 if (!strcmp(tok, "true"))
343 return json_new_node(p, json_node_true);
344 else if (!strcmp(tok, "false"))
346 else if (!strcmp(tok, "null"))
347 return json_new_node(p, json_node_null);
348 }
349 p->err_msg = "bad token";
350 return 0;
351}
352
354{
355 struct json_node *n1 = json_parse_value(p);
356 struct json_node *m0, *m1;
357 if (!n1)
358 return 0;
359 m0 = m1 = json_new_node(p, json_node_list);
360 m1->u.link[0] = n1;
361 while (look_ch(p) == ',')
362 {
363 struct json_node *n2, *m2;
364 move_ch(p);
365 n2 = json_parse_value(p);
366 if (!n2)
367 {
369 return 0;
370 }
372 m2->u.link[0] = n2;
373
374 m1->u.link[1] = m2;
375 m1 = m2;
376 }
377 return m0;
378}
379
381{
382 struct json_node *n;
383 if (look_ch(p) != '[')
384 {
385 p->err_msg = "expecting [";
386 return 0;
387 }
388 move_ch(p);
389 if (p->parse_level >= p->max_level)
390 {
391 p->err_msg = "Too much nesting";
392 return 0;
393 }
394 p->parse_level++;
396 if (look_ch(p) != ']')
397 n->u.link[0] = json_parse_elements(p);
398
399 p->parse_level--;
400 if (look_ch(p) != ']')
401 {
402 if (!p->err_msg)
403 p->err_msg = "expecting ]";
405 return 0;
406 }
407 move_ch(p);
408 return n;
409}
410
412{
413 struct json_node *s = json_parse_string(p);
414 struct json_node *v, *n;
415 if (!s)
416 return 0;
417 if (look_ch(p) != ':')
418 {
419 p->err_msg = "missing :";
421 return 0;
422 }
423 move_ch(p);
424 v = json_parse_value(p);
425 if (!v)
426 {
428 return 0;
429 }
431 n->u.link[0] = s;
432 n->u.link[1] = v;
433 return n;
434}
435
437{
438 struct json_node *n1 = json_parse_pair(p);
439 struct json_node *m0, *m1;
440 if (!n1)
441 return 0;
442 m0 = m1 = json_new_node(p, json_node_list);
443 m1->u.link[0] = n1;
444 while (look_ch(p) == ',')
445 {
446 struct json_node *n2, *m2;
447 move_ch(p);
448 n2 = json_parse_pair(p);
449 if (!n2)
450 {
452 return 0;
453 }
455 m2->u.link[0] = n2;
456
457 m1->u.link[1] = m2;
458 m1 = m2;
459 }
460 return m0;
461}
462
464{
465 struct json_node *n;
466 if (look_ch(p) != '{')
467 {
468 p->err_msg = "{ expected";
469 return 0;
470 }
471 move_ch(p);
472
474 if (look_ch(p) != '}')
475 {
476 struct json_node *m;
477 if (p->parse_level >= p->max_level)
478 {
479 p->err_msg = "Too much nesting";
481 return 0;
482 }
483 p->parse_level++;
484 m = json_parse_members(p);
485 p->parse_level--;
486 if (!m)
487 {
489 return 0;
490 }
491 n->u.link[0] = m;
492 }
493 if (look_ch(p) != '}')
494 {
495 p->err_msg = "Missing }";
497 return 0;
498 }
499 move_ch(p);
500 return n;
501}
502
503struct json_node *json_parser_parse(json_parser_t p, const char *json_str)
504{
505 int c;
506 struct json_node *n;
507 p->buf = json_str;
508 p->cp = p->buf;
509 p->err_msg = 0;
510 p->parse_level = 0;
511 p->max_level = 1000;
512
513 n = json_parse_value(p);
514 if (!n)
515 return 0;
516 if (p->err_msg)
517 {
519 return 0;
520 }
521 c = look_ch(p);
522 if (c != 0)
523 {
524 p->err_msg = "extra characters";
526 return 0;
527 }
528 return n;
529}
530
531struct json_node *json_parse2(const char *json_str, const char **errmsg,
532 size_t *pos)
533{
535 struct json_node *n = 0;
536 if (!p)
537 {
538 if (errmsg)
539 *errmsg = "could not create parser";
540 }
541 else
542 {
543 n = json_parser_parse(p, json_str);
544 if (!n && errmsg)
545 *errmsg = json_parser_get_errmsg(p);
546 if (pos)
547 *pos = json_parser_get_position(p);
549 }
550 return n;
551}
552
553struct json_node *json_parse(const char *json_str, const char **errmsg)
554{
555 return json_parse2(json_str, errmsg, 0);
556}
557
558static void json_indent(WRBUF result, int indent)
559{
560 size_t l = wrbuf_len(result);
561 if (l == 0 || wrbuf_buf(result)[l-1] == '\n')
562 {
563 int i;
564 for (i = 0; i < indent; i++)
565 wrbuf_putc(result, ' ');
566 }
567}
568
569static void json_write_wrbuf_r(struct json_node *node, WRBUF result, int indent)
570{
571 int sub_indent = -1;
572 if (indent >= 0)
573 sub_indent = indent + 2;
574 switch (node->type)
575 {
576 case json_node_object:
577 json_indent(result, indent);
578 wrbuf_puts(result, "{");
579 if (node->u.link[0])
580 {
581 if (indent >= 0)
582 {
583 wrbuf_puts(result, "\n");
584 json_indent(result, sub_indent);
585 }
586 json_write_wrbuf_r(node->u.link[0], result, sub_indent);
587 if (indent >= 0)
588 {
589 wrbuf_puts(result, "\n");
590 json_indent(result, indent);
591 }
592 }
593 wrbuf_puts(result, "}");
594 break;
595 case json_node_array:
596 json_indent(result, indent);
597 wrbuf_puts(result, "[");
598 if (node->u.link[0])
599 {
600 if (indent >= 0)
601 wrbuf_puts(result, "\n");
602 json_write_wrbuf_r(node->u.link[0], result, sub_indent);
603 if (indent >= 0)
604 {
605 wrbuf_puts(result, "\n");
606 json_indent(result, indent);
607 }
608 }
609 wrbuf_puts(result, "]");
610 break;
611 case json_node_list:
612 json_write_wrbuf_r(node->u.link[0], result, indent);
613 if (node->u.link[1])
614 {
615 wrbuf_puts(result, ",");
616 if (indent >= 0) {
617 wrbuf_puts(result, "\n");
618 }
619 json_write_wrbuf_r(node->u.link[1], result, indent);
620 }
621 break;
622 case json_node_pair:
623 if (indent >= 0)
624 json_indent(result, indent);
625 json_write_wrbuf_r(node->u.link[0], result, indent);
626 wrbuf_puts(result, ":");
627 if (indent >= 0)
628 wrbuf_puts(result, " ");
629 json_write_wrbuf_r(node->u.link[1], result, indent);
630 break;
631 case json_node_string:
632 wrbuf_puts(result, "\"");
633 wrbuf_json_puts(result, node->u.string);
634 wrbuf_puts(result, "\"");
635 break;
636 case json_node_number:
637 wrbuf_printf(result, "%lg", node->u.number);
638 break;
639 case json_node_true:
640 wrbuf_puts(result, "true");
641 break;
642 case json_node_false:
643 wrbuf_puts(result, "false");
644 break;
645 case json_node_null:
646 wrbuf_puts(result, "null");
647 break;
648 }
649}
650
651void json_write_wrbuf_pretty(struct json_node *node, WRBUF result)
652{
653 json_write_wrbuf_r(node, result, 0);
654}
655
656void json_write_wrbuf(struct json_node *node, WRBUF result)
657{
658 json_write_wrbuf_r(node, result, -1);
659}
660
661static struct json_node **json_get_objectp(struct json_node *n,
662 const char *name)
663{
664 if (n && n->type == json_node_object)
665 {
666 for (n = n->u.link[0]; n; n = n->u.link[1])
667 {
668 struct json_node *c = n->u.link[0];
669 if (c && c->type == json_node_pair &&
670 c->u.link[0] && c->u.link[0]->type == json_node_string)
671 if (!strcmp(name, c->u.link[0]->u.string))
672 return &c->u.link[1];
673 }
674 }
675 return 0;
676}
677
678struct json_node *json_get_object(struct json_node *n, const char *name)
679{
680 struct json_node **np = json_get_objectp(n, name);
681
682 if (np)
683 return *np;
684 return 0;
685}
686
687struct json_node *json_detach_object(struct json_node *n, const char *name)
688{
689 struct json_node **np = json_get_objectp(n, name);
690
691 if (np)
692 {
693 struct json_node *n = *np;
694 *np = 0;
695 return n;
696 }
697 return 0;
698}
699
700struct json_node *json_get_elem(struct json_node *n, int idx)
701{
702 if (n && n->type == json_node_array)
703 {
704 for (n = n->u.link[0]; n; n = n->u.link[1])
705 {
706 if (--idx < 0)
707 return n->u.link[0];
708 }
709 }
710 return 0;
711}
712
714{
715 int i = 0;
716
717 if (n && (n->type == json_node_array || n->type == json_node_object))
718 {
719 for (n = n->u.link[0]; n; n = n->u.link[1])
720 i++;
721 }
722 return i;
723}
724
725int json_append_array(struct json_node *dst, struct json_node *src)
726{
727 if (dst && src &&
728 dst->type == json_node_array && src->type == json_node_array)
729 {
730 struct json_node **np = &dst->u.link[0];
731 while (*np)
732 np = &(*np)->u.link[1];
733 *np = src->u.link[0];
734 src->u.link[0] = 0;
735 json_remove_node(src);
736 return 0;
737 }
738 return -1;
739}
740
742{
743 return p->err_msg;
744}
745
747{
748 return p->cp - p->buf;
749}
750
751/*
752 * Local variables:
753 * c-basic-offset: 4
754 * c-file-style: "Stroustrup"
755 * indent-tabs-mode: nil
756 * End:
757 * vim: shiftwidth=4 tabstop=8 expandtab
758 */
Header for errno utilities.
char * name
Definition initopt.c:18
void json_parser_destroy(json_parser_t p)
destroys JSON parser
Definition json.c:63
struct json_node * json_parse(const char *json_str, const char **errmsg)
parses JSON string
Definition json.c:553
static int json_one_char(const char **p, char *out)
Definition json.c:124
struct json_node * json_get_object(struct json_node *n, const char *name)
gets object pair value for some name
Definition json.c:678
static struct json_node * json_parse_pair(json_parser_t p)
Definition json.c:411
void json_parser_subst(json_parser_t p, int idx, struct json_node *n)
configure subst rule
Definition json.c:48
static void json_indent(WRBUF result, int indent)
Definition json.c:558
struct json_node * json_parse2(const char *json_str, const char **errmsg, size_t *pos)
parses JSON string
Definition json.c:531
static int look_ch(json_parser_t p)
Definition json.c:75
static void move_ch(json_parser_t p)
Definition json.c:82
struct json_node * json_get_elem(struct json_node *n, int idx)
gets array element
Definition json.c:700
void json_write_wrbuf(struct json_node *node, WRBUF result)
converts JSON tree to JSON string
Definition json.c:656
static struct json_node * json_parse_elements(json_parser_t p)
Definition json.c:353
void json_write_wrbuf_pretty(struct json_node *node, WRBUF result)
writes JSON tree with indentation (pretty print)
Definition json.c:651
size_t json_parser_get_position(json_parser_t p)
returns parser position
Definition json.c:746
static void json_write_wrbuf_r(struct json_node *node, WRBUF result, int indent)
Definition json.c:569
static struct json_node * json_parse_members(json_parser_t p)
Definition json.c:436
static struct json_node ** json_get_objectp(struct json_node *n, const char *name)
Definition json.c:661
static struct json_node * json_parse_string(json_parser_t p)
Definition json.c:182
int json_count_children(struct json_node *n)
returns number of children (array or object)
Definition json.c:713
static struct json_node * json_new_node(json_parser_t p, enum json_node_type type)
Definition json.c:88
static struct json_node * json_parse_object(json_parser_t p)
Definition json.c:463
void json_remove_node(struct json_node *n)
destroys JSON tree node and its children
Definition json.c:96
const char * json_parser_get_errmsg(json_parser_t p)
returns parser error
Definition json.c:741
static struct json_node * json_parse_number(json_parser_t p)
Definition json.c:229
struct json_node * json_parser_parse(json_parser_t p, const char *json_str)
parses JSON string
Definition json.c:503
static struct json_node * json_parse_array(json_parser_t p)
Definition json.c:380
struct json_node * json_detach_object(struct json_node *n, const char *name)
gets object value and detaches from existing tree
Definition json.c:687
static struct json_node * json_parse_value(json_parser_t p)
Definition json.c:300
json_parser_t json_parser_create(void)
create JSON parser
Definition json.c:38
int json_append_array(struct json_node *dst, struct json_node *src)
appends array to another
Definition json.c:725
Header for JSON functions.
struct json_parser_s * json_parser_t
JSON parser (opaque)
Definition json.h:63
json_node_type
JSON node type for json_node.
Definition json.h:39
@ json_node_null
Definition json.h:49
@ json_node_pair
Definition json.h:44
@ json_node_array
Definition json.h:41
@ json_node_list
Definition json.h:42
@ json_node_string
Definition json.h:45
@ json_node_true
Definition json.h:47
@ json_node_number
Definition json.h:46
@ json_node_false
Definition json.h:48
@ json_node_object
Definition json.h:40
enum l_file_type type
Definition log.c:47
JSON node.
Definition json.h:53
char * string
Definition json.h:56
double number
Definition json.h:57
union json_node::@25 u
struct json_node * link[2]
Definition json.h:58
enum json_node_type type
Definition json.h:54
const char * cp
Definition json.c:31
struct json_subst_info * subst
Definition json.c:35
const char * err_msg
Definition json.c:32
int max_level
Definition json.c:34
const char * buf
Definition json.c:30
int parse_level
Definition json.c:33
struct json_node * node
Definition json.c:26
struct json_subst_info * next
Definition json.c:25
string buffer
Definition wrbuf.h:43
size_t yaz_write_UTF8_char(unsigned long x, char **outbuf, size_t *outbytesleft, int *error)
encodes UTF-8 sequence
Definition utf8.c:159
void wrbuf_json_puts(WRBUF b, const char *str)
writes JSON text to WRBUF with escaping
Definition wrbuf.c:372
void wrbuf_printf(WRBUF b, const char *fmt,...)
writes printf result to WRBUF
Definition wrbuf.c:189
void wrbuf_puts(WRBUF b, const char *buf)
appends C-string to WRBUF
Definition wrbuf.c:89
#define wrbuf_putc(b, c)
Definition wrbuf.h:287
#define wrbuf_buf(b)
Definition wrbuf.h:270
#define wrbuf_len(b)
Definition wrbuf.h:269
Header for memory handling functions.
#define xfree(x)
utility macro which calls xfree_f
Definition xmalloc.h:53
#define xmalloc(x)
utility macro which calls malloc_f
Definition xmalloc.h:49