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