Happy new year
[yaz-moved-to-github.git] / src / json.c
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
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 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
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
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
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
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
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
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
634 const char *json_parser_get_errmsg(json_parser_t p)
635 {
636     return p->err_msg;
637 }
638
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  */