1 /* This file is part of the YAZ toolkit.
2 * Copyright (C) 1995-2012 Index Data
3 * See the file LICENSE for details.
4 */
5 /**
6 * \file json.c
7 * \brief JSON encoding/decoding
8 */
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
23 struct json_subst_info {
24 int idx;
25 struct json_subst_info *next;
26 struct json_node *node;
27 };
28
29 struct json_parser_s {
30 const char *buf;
31 const char *cp;
32 const char *err_msg;
33 struct json_subst_info *subst;
34 };
35
json_parser_create(void)36 json_parser_t json_parser_create(void)
37 {
38 json_parser_t p = (json_parser_t) xmalloc(sizeof(*p));
39
40 p->buf = 0;
41 p->cp = 0;
42 p->err_msg = 0;
43 p->subst = 0;
44 return p;
45 }
46
json_parser_subst(json_parser_t p,int idx,struct json_node * n)47 void json_parser_subst(json_parser_t p, int idx, struct json_node *n)
48 {
49 struct json_subst_info **sb = &p->subst;
50 for (; *sb; sb = &(*sb)->next)
51 if ((*sb)->idx == idx)
52 {
53 (*sb)->node = n;
54 return;
55 }
56 *sb = xmalloc(sizeof(**sb));
57 (*sb)->next = 0;
58 (*sb)->node = n;
59 (*sb)->idx = idx;
60 }
61
json_parser_destroy(json_parser_t p)62 void json_parser_destroy(json_parser_t p)
63 {
64 struct json_subst_info *sb = p->subst;
65 while (sb)
66 {
67 struct json_subst_info *sb_next = sb->next;
68 xfree(sb);
69 sb = sb_next;
70 }
71 xfree(p);
72 }
73
look_ch(json_parser_t p)74 static int look_ch(json_parser_t p)
75 {
76 while (*p->cp && strchr(" \t\r\n\f", *p->cp))
77 (p->cp)++;
78 return *p->cp;
79 }
80
move_ch(json_parser_t p)81 static void move_ch(json_parser_t p)
82 {
83 if (*p->cp)
84 (p->cp)++;
85 }
86
json_new_node(json_parser_t p,enum json_node_type type)87 static struct json_node *json_new_node(json_parser_t p, enum json_node_type type)
88 {
89 struct json_node *n = (struct json_node *) xmalloc(sizeof(*n));
90 n->type = type;
91 n->u.link[0] = n->u.link[1] = 0;
92 return n;
93 }
94
json_remove_node(struct json_node * n)95 void json_remove_node(struct json_node *n)
96 {
97 if (!n)
98 return;
99 switch (n->type)
100 {
101 case json_node_object:
102 case json_node_array:
103 case json_node_list:
104 case json_node_pair:
105 json_remove_node(n->u.link[0]);
106 json_remove_node(n->u.link[1]);
107 break;
108 case json_node_string:
109 xfree(n->u.string);
110 break;
111 case json_node_number:
112 case json_node_true:
113 case json_node_false:
114 case json_node_null:
115 break;
116 }
117 xfree(n);
118 }
119
120 static struct json_node *json_parse_object(json_parser_t p);
121 static struct json_node *json_parse_array(json_parser_t p);
122
json_one_char(const char ** p,char * out)123 static int json_one_char(const char **p, char *out)
124 {
125 if (**p == '\\' && p[0][1])
126 {
127 (*p)++;
128 switch(**p)
129 {
130 case '"':
131 *out = '"'; break;
132 case '\\':
133 *out = '\\'; break;
134 case '/':
135 *out = '/'; break;
136 case 'b':
137 *out = '\b'; break;
138 case 'f':
139 *out = '\f'; break;
140 case 'n':
141 *out = '\n'; break;
142 case 'r':
143 *out = '\r'; break;
144 case 't':
145 *out = '\t'; break;
146 case 'u':
147 if (p[0][1])
148 {
149 unsigned code;
150 char *outp = out;
151 int error;
152 size_t outbytesleft = 6;
153 sscanf(*p + 1, "%4x", &code);
154 if (!yaz_write_UTF8_char(code, &outp, &outbytesleft, &error))
155 {
156 *p += 5;
157 return outp - out;
158 }
159 }
160 default:
161 *out = '_'; break;
162 break;
163 }
164 (*p)++;
165 return 1;
166 }
167 else
168 {
169 *out = **p;
170 (*p)++;
171 return 1;
172 }
173 }
174
json_parse_string(json_parser_t p)175 static struct json_node *json_parse_string(json_parser_t p)
176 {
177 struct json_node *n;
178 const char *cp;
179 char *dst;
180 int l = 0;
181 if (look_ch(p) != '\"')
182 {
183 p->err_msg = "string expected";
184 return 0;
185 }
186 move_ch(p);
187
188 cp = p->cp;
189 while (*cp && *cp != '"')
190 {
191 char out[6];
192 l += json_one_char(&cp, out);
193 }
194 if (!*cp)
195 {
196 p->err_msg = "missing \"";
197 return 0;
198 }
199 n = json_new_node(p, json_node_string);
200 dst = n->u.string = (char *) xmalloc(l + 1);
201
202 cp = p->cp;
203 while (*cp && *cp != '"')
204 {
205 char out[6];
206
207 l = json_one_char(&cp, out);
208 memcpy(dst, out, l);
209 dst += l;
210 }
211 *dst = '\0';
212 p->cp = cp+1;
213 return n;
214 }
215
json_parse_number(json_parser_t p)216 static struct json_node *json_parse_number(json_parser_t p)
217 {
218 struct json_node *n;
219 char *endptr;
220 double v;
221
222 look_ch(p); // skip spaces
223 v = strtod(p->cp, &endptr);
224
225 if (endptr == p->cp)
226 {
227 p->err_msg = "bad number";
228 return 0;
229 }
230 p->cp = endptr;
231 n = json_new_node(p, json_node_number);
232 n->u.number = v;
233 return n;
234 }
235
json_parse_value(json_parser_t p)236 static struct json_node *json_parse_value(json_parser_t p)
237 {
238 int c = look_ch(p);
239 if (c == '\"')
240 return json_parse_string(p);
241 else if (strchr("0123456789-+", c))
242 return json_parse_number(p);
243 else if (c == '{')
244 return json_parse_object(p);
245 else if (c == '[')
246 return json_parse_array(p);
247 else if (c == '%')
248 {
249 struct json_subst_info *sb;
250 int idx = 0;
251 p->cp++;
252 c = *p->cp;
253 while (c >= '0' && c <= '9')
254 {
255 idx = idx*10 + (c - '0');
256 p->cp++;
257 c = *p->cp;
258 }
259 for (sb = p->subst; sb; sb = sb->next)
260 if (sb->idx == idx)
261 return sb->node;
262 }
263 else
264 {
265 char tok[8];
266 int i = 0;
267 while (c >= 'a' && c <= 'z' && i < 7)
268 {
269 tok[i++] = c;
270 p->cp++;
271 c = *p->cp;
272 }
273 tok[i] = 0;
274 if (!strcmp(tok, "true"))
275 return json_new_node(p, json_node_true);
276 else if (!strcmp(tok, "false"))
277 return json_new_node(p, json_node_false);
278 else if (!strcmp(tok, "null"))
279 return json_new_node(p, json_node_null);
280 }
281 p->err_msg = "bad token";
282 return 0;
283 }
284
json_parse_elements(json_parser_t p)285 static struct json_node *json_parse_elements(json_parser_t p)
286 {
287 struct json_node *n1 = json_parse_value(p);
288 struct json_node *m0, *m1;
289 if (!n1)
290 return 0;
291 m0 = m1 = json_new_node(p, json_node_list);
292 m1->u.link[0] = n1;
293 while (look_ch(p) == ',')
294 {
295 struct json_node *n2, *m2;
296 move_ch(p);
297 n2 = json_parse_value(p);
298 if (!n2)
299 {
300 json_remove_node(m0);
301 return 0;
302 }
303 m2 = json_new_node(p, json_node_list);
304 m2->u.link[0] = n2;
305
306 m1->u.link[1] = m2;
307 m1 = m2;
308 }
309 return m0;
310 }
311
json_parse_array(json_parser_t p)312 static struct json_node *json_parse_array(json_parser_t p)
313 {
314 struct json_node *n;
315 if (look_ch(p) != '[')
316 {
317 p->err_msg = "expecting [";
318 return 0;
319 }
320 move_ch(p);
321 n = json_new_node(p, json_node_array);
322 if (look_ch(p) != ']')
323 n->u.link[0] = json_parse_elements(p);
324
325 if (look_ch(p) != ']')
326 {
327 p->err_msg = "expecting ]";
328 json_remove_node(n);
329 return 0;
330 }
331 move_ch(p);
332 return n;
333 }
334
json_parse_pair(json_parser_t p)335 static struct json_node *json_parse_pair(json_parser_t p)
336 {
337 struct json_node *s = json_parse_string(p);
338 struct json_node *v, *n;
339 if (!s)
340 return 0;
341 if (look_ch(p) != ':')
342 {
343 p->err_msg = "missing :";
344 json_remove_node(s);
345 return 0;
346 }
347 move_ch(p);
348 v = json_parse_value(p);
349 if (!v)
350 {
351 json_remove_node(s);
352 return 0;
353 }
354 n = json_new_node(p, json_node_pair);
355 n->u.link[0] = s;
356 n->u.link[1] = v;
357 return n;
358 }
359
json_parse_members(json_parser_t p)360 static struct json_node *json_parse_members(json_parser_t p)
361 {
362 struct json_node *n1 = json_parse_pair(p);
363 struct json_node *m0, *m1;
364 if (!n1)
365 return 0;
366 m0 = m1 = json_new_node(p, json_node_list);
367 m1->u.link[0] = n1;
368 while (look_ch(p) == ',')
369 {
370 struct json_node *n2, *m2;
371 move_ch(p);
372 n2 = json_parse_pair(p);
373 if (!n2)
374 {
375 json_remove_node(m0);
376 return 0;
377 }
378 m2 = json_new_node(p, json_node_list);
379 m2->u.link[0] = n2;
380
381 m1->u.link[1] = m2;
382 m1 = m2;
383 }
384 return m0;
385 }
386
json_parse_object(json_parser_t p)387 static struct json_node *json_parse_object(json_parser_t p)
388 {
389 struct json_node *n;
390 if (look_ch(p) != '{')
391 {
392 p->err_msg = "{ expected";
393 return 0;
394 }
395 move_ch(p);
396
397 n = json_new_node(p, json_node_object);
398 if (look_ch(p) != '}')
399 {
400 struct json_node *m = json_parse_members(p);
401 if (!m)
402 {
403 json_remove_node(n);
404 return 0;
405 }
406 n->u.link[0] = m;
407 }
408 if (look_ch(p) != '}')
409 {
410 p->err_msg = "Missing }";
411 json_remove_node(n);
412 return 0;
413 }
414 move_ch(p);
415 return n;
416 }
417
json_parser_parse(json_parser_t p,const char * json_str)418 struct json_node *json_parser_parse(json_parser_t p, const char *json_str)
419 {
420 int c;
421 struct json_node *n;
422 p->buf = json_str;
423 p->cp = p->buf;
424
425 n = json_parse_value(p);
426 if (!n)
427 return 0;
428 c = look_ch(p);
429 if (c != 0)
430 {
431 p->err_msg = "extra characters";
432 json_remove_node(n);
433 return 0;
434 }
435 return n;
436 }
437
json_parse2(const char * json_str,const char ** errmsg,size_t * pos)438 struct json_node *json_parse2(const char *json_str, const char **errmsg,
439 size_t *pos)
440 {
441 json_parser_t p = json_parser_create();
442 struct json_node *n = 0;
443 if (!p)
444 {
445 if (errmsg)
446 *errmsg = "could not create parser";
447 }
448 else
449 {
450 n = json_parser_parse(p, json_str);
451 if (!n && errmsg)
452 *errmsg = json_parser_get_errmsg(p);
453 if (pos)
454 *pos = json_parser_get_position(p);
455 json_parser_destroy(p);
456 }
457 return n;
458 }
459
json_parse(const char * json_str,const char ** errmsg)460 struct json_node *json_parse(const char *json_str, const char **errmsg)
461 {
462 return json_parse2(json_str, errmsg, 0);
463 }
464
wrbuf_json_write(WRBUF b,const char * cp,size_t sz)465 static void wrbuf_json_write(WRBUF b, const char *cp, size_t sz)
466 {
467 size_t i;
468 for (i = 0; i < sz; i++)
469 {
470 if (cp[i] > 0 && cp[i] < 32)
471 {
472 wrbuf_putc(b, '\\');
473 switch (cp[i])
474 {
475 case '\b': wrbuf_putc(b, 'b'); break;
476 case '\f': wrbuf_putc(b, 'f'); break;
477 case '\n': wrbuf_putc(b, 'n'); break;
478 case '\r': wrbuf_putc(b, 'r'); break;
479 case '\t': wrbuf_putc(b, 't'); break;
480 default:
481 wrbuf_printf(b, "u%04x", cp[i]);
482 }
483 }
484 else if (cp[i] == '"')
485 {
486 wrbuf_putc(b, '\\'); wrbuf_putc(b, '"');
487 }
488 else if (cp[i] == '\\')
489 {
490 wrbuf_putc(b, '\\'); wrbuf_putc(b, '\\');
491 }
492 else
493 { /* leave encoding as raw UTF-8 */
494 wrbuf_putc(b, cp[i]);
495 }
496 }
497
498 }
499
wrbuf_json_puts(WRBUF b,const char * str)500 void wrbuf_json_puts(WRBUF b, const char *str)
501 {
502 wrbuf_json_write(b, str, strlen(str));
503 }
504
json_write_wrbuf(struct json_node * node,WRBUF result)505 void json_write_wrbuf(struct json_node *node, WRBUF result)
506 {
507 switch (node->type)
508 {
509 case json_node_object:
510 wrbuf_puts(result, "{");
511 if (node->u.link[0])
512 json_write_wrbuf(node->u.link[0], result);
513 wrbuf_puts(result, "}");
514 break;
515 case json_node_array:
516 wrbuf_puts(result, "[");
517 if (node->u.link[0])
518 json_write_wrbuf(node->u.link[0], result);
519 wrbuf_puts(result, "]");
520 break;
521 case json_node_list:
522 json_write_wrbuf(node->u.link[0], result);
523 if (node->u.link[1])
524 {
525 wrbuf_puts(result, ",");
526 json_write_wrbuf(node->u.link[1], result);
527 }
528 break;
529 case json_node_pair:
530 json_write_wrbuf(node->u.link[0], result);
531 wrbuf_puts(result, ":");
532 json_write_wrbuf(node->u.link[1], result);
533 break;
534 case json_node_string:
535 wrbuf_puts(result, "\"");
536 wrbuf_json_puts(result, node->u.string);
537 wrbuf_puts(result, "\"");
538 break;
539 case json_node_number:
540 wrbuf_printf(result, "%lg", node->u.number);
541 break;
542 case json_node_true:
543 wrbuf_puts(result, "true");
544 break;
545 case json_node_false:
546 wrbuf_puts(result, "false");
547 break;
548 case json_node_null:
549 wrbuf_puts(result, "null");
550 break;
551 }
552 }
553
json_get_objectp(struct json_node * n,const char * name)554 static struct json_node **json_get_objectp(struct json_node *n,
555 const char *name)
556 {
557 if (n && n->type == json_node_object)
558 {
559 for (n = n->u.link[0]; n; n = n->u.link[1])
560 {
561 struct json_node *c = n->u.link[0];
562 if (c && c->type == json_node_pair &&
563 c->u.link[0] && c->u.link[0]->type == json_node_string)
564 if (!strcmp(name, c->u.link[0]->u.string))
565 return &c->u.link[1];
566 }
567 }
568 return 0;
569 }
570
json_get_object(struct json_node * n,const char * name)571 struct json_node *json_get_object(struct json_node *n, const char *name)
572 {
573 struct json_node **np = json_get_objectp(n, name);
574
575 if (np)
576 return *np;
577 return 0;
578 }
579
json_detach_object(struct json_node * n,const char * name)580 struct json_node *json_detach_object(struct json_node *n, const char *name)
581 {
582 struct json_node **np = json_get_objectp(n, name);
583
584 if (np)
585 {
586 struct json_node *n = *np;
587 *np = 0;
588 return n;
589 }
590 return 0;
591 }
592
json_get_elem(struct json_node * n,int idx)593 struct json_node *json_get_elem(struct json_node *n, int idx)
594 {
595 if (n && n->type == json_node_array)
596 {
597 for (n = n->u.link[0]; n; n = n->u.link[1])
598 {
599 if (--idx < 0)
600 return n->u.link[0];
601 }
602 }
603 return 0;
604 }
605
json_count_children(struct json_node * n)606 int json_count_children(struct json_node *n)
607 {
608 int i = 0;
609
610 if (n && (n->type == json_node_array || n->type == json_node_object))
611 {
612 for (n = n->u.link[0]; n; n = n->u.link[1])
613 i++;
614 }
615 return i;
616 }
617
json_append_array(struct json_node * dst,struct json_node * src)618 int json_append_array(struct json_node *dst, struct json_node *src)
619 {
620 if (dst && src &&
621 dst->type == json_node_array && src->type == json_node_array)
622 {
623 struct json_node **np = &dst->u.link[0];
624 while (*np)
625 np = &(*np)->u.link[1];
626 *np = src->u.link[0];
627 src->u.link[0] = 0;
628 json_remove_node(src);
629 return 0;
630 }
631 return -1;
632 }
633
json_parser_get_errmsg(json_parser_t p)634 const char *json_parser_get_errmsg(json_parser_t p)
635 {
636 return p->err_msg;
637 }
638
json_parser_get_position(json_parser_t p)639 size_t json_parser_get_position(json_parser_t p)
640 {
641 return p->cp - p->buf;
642 }
643
644 /*
645 * Local variables:
646 * c-basic-offset: 4
647 * c-file-style: "Stroustrup"
648 * indent-tabs-mode: nil
649 * End:
650 * vim: shiftwidth=4 tabstop=8 expandtab
651 */
652