rpn2solr: reformat (same as "master").
[yaz-moved-to-github.git] / src / json.c
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) 1995-2013 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
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
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
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
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
81 static void move_ch(json_parser_t p)
82 {
83     if (*p->cp)
84         (p->cp)++;
85 }
86
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
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
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
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
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
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
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
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
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
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
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
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
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
460 struct json_node *json_parse(const char *json_str, const char **errmsg)
461 {
462     return json_parse2(json_str, errmsg, 0);
463 }
464
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
500 void wrbuf_json_puts(WRBUF b, const char *str)
501 {
502     wrbuf_json_write(b, str, strlen(str));
503 }
504
505 static void json_indent(WRBUF result, int indent)
506 {
507     size_t l = wrbuf_len(result);
508     if (l == 0 || wrbuf_buf(result)[l-1] == '\n')
509     {
510         int i;
511         for (i = 0; i < indent; i++)
512             wrbuf_putc(result, ' ');
513     }
514 }
515
516 static void json_write_wrbuf_r(struct json_node *node, WRBUF result, int indent)
517 {
518     int sub_indent = -1;
519     if (indent >= 0)
520         sub_indent = indent + 1;
521     switch (node->type)
522     {
523     case json_node_object:
524         json_indent(result, indent);
525         wrbuf_puts(result, "{");
526         if (indent >= 0)
527         {
528             wrbuf_puts(result, "\n");
529             json_indent(result, sub_indent);
530         }
531         if (node->u.link[0])
532             json_write_wrbuf_r(node->u.link[0], result, sub_indent);
533         if (indent >= 0)
534         {
535             wrbuf_puts(result, "\n");
536             json_indent(result, indent);
537         }
538         wrbuf_puts(result, "}");
539         break;
540     case json_node_array:
541         json_indent(result, indent);
542         wrbuf_puts(result, "[");
543         if (indent >= 0)
544         {
545             wrbuf_puts(result, "\n");
546             json_indent(result, sub_indent);
547         }
548         if (node->u.link[0])
549         {
550             json_write_wrbuf_r(node->u.link[0], result, sub_indent);
551         }
552         if (indent >= 0)
553         {
554             wrbuf_puts(result, "\n");
555             json_indent(result, indent);
556         }
557         wrbuf_puts(result, "]");
558         break;
559     case json_node_list:
560         json_write_wrbuf_r(node->u.link[0], result, indent);
561         if (node->u.link[1])
562         {
563             wrbuf_puts(result, ",");
564             if (indent >= 0)
565                 wrbuf_puts(result, " ");
566             json_write_wrbuf_r(node->u.link[1], result, indent);
567         }
568         break;
569     case json_node_pair:
570         json_write_wrbuf_r(node->u.link[0], result, indent);
571         wrbuf_puts(result, ":");
572         if (indent >= 0)
573             wrbuf_puts(result, " ");
574         json_write_wrbuf_r(node->u.link[1], result, indent);
575         break;
576     case json_node_string:
577         wrbuf_puts(result, "\"");
578         wrbuf_json_puts(result, node->u.string);
579         wrbuf_puts(result, "\"");
580         break;
581     case json_node_number:
582         wrbuf_printf(result, "%lg", node->u.number);
583         break;
584     case json_node_true:
585         wrbuf_puts(result, "true");
586         break;
587     case json_node_false:
588         wrbuf_puts(result, "false");
589         break;
590     case json_node_null:
591         wrbuf_puts(result, "null");
592         break;
593     }
594 }
595
596 void json_write_wrbuf_pretty(struct json_node *node, WRBUF result)
597 {
598     json_write_wrbuf_r(node, result, 1);
599 }
600
601 void json_write_wrbuf(struct json_node *node, WRBUF result)
602 {
603     json_write_wrbuf_r(node, result, -1);
604 }
605
606 static struct json_node **json_get_objectp(struct json_node *n,
607                                            const char *name)
608 {
609     if (n && n->type == json_node_object)
610     {
611         for (n = n->u.link[0]; n; n = n->u.link[1])
612         {
613             struct json_node *c = n->u.link[0];
614             if (c && c->type == json_node_pair &&
615                 c->u.link[0] && c->u.link[0]->type == json_node_string)
616                 if (!strcmp(name, c->u.link[0]->u.string))
617                     return &c->u.link[1];
618         }
619     }
620     return 0;
621 }
622
623 struct json_node *json_get_object(struct json_node *n, const char *name)
624 {
625     struct json_node **np = json_get_objectp(n, name);
626
627     if (np)
628         return *np;
629     return 0;
630 }
631
632 struct json_node *json_detach_object(struct json_node *n, const char *name)
633 {
634     struct json_node **np = json_get_objectp(n, name);
635
636     if (np)
637     {
638         struct json_node *n = *np;
639         *np = 0;
640         return n;
641     }
642     return 0;
643 }
644
645 struct json_node *json_get_elem(struct json_node *n, int idx)
646 {
647     if (n && n->type == json_node_array)
648     {
649         for (n = n->u.link[0]; n; n = n->u.link[1])
650         {
651             if (--idx < 0)
652                 return n->u.link[0];
653         }
654     }
655     return 0;
656 }
657
658 int json_count_children(struct json_node *n)
659 {
660     int i = 0;
661
662     if (n && (n->type == json_node_array || n->type == json_node_object))
663     {
664         for (n = n->u.link[0]; n; n = n->u.link[1])
665             i++;
666     }
667     return i;
668 }
669
670 int json_append_array(struct json_node *dst, struct json_node *src)
671 {
672     if (dst && src &&
673         dst->type == json_node_array && src->type == json_node_array)
674     {
675         struct json_node **np = &dst->u.link[0];
676         while (*np)
677             np = &(*np)->u.link[1];
678         *np = src->u.link[0];
679         src->u.link[0] = 0;
680         json_remove_node(src);
681         return 0;
682     }
683     return -1;
684 }
685
686 const char *json_parser_get_errmsg(json_parser_t p)
687 {
688     return p->err_msg;
689 }
690
691 size_t json_parser_get_position(json_parser_t p)
692 {
693     return p->cp - p->buf;
694 }
695
696 /*
697  * Local variables:
698  * c-basic-offset: 4
699  * c-file-style: "Stroustrup"
700  * indent-tabs-mode: nil
701  * End:
702  * vim: shiftwidth=4 tabstop=8 expandtab
703  */