Add JSON encoder and decoder
[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_parser_s {
22     const char *buf;
23     const char *cp;
24     const char *err_msg;
25 };
26
27 json_parser_t json_parser_create(void)
28 {
29     json_parser_t p = (json_parser_t) xmalloc(sizeof(*p));
30     
31     p->buf = 0;
32     p->cp = 0;
33     p->err_msg = 0;
34     return p;
35 }
36
37 void json_parser_destroy(json_parser_t p)
38 {
39     xfree(p);
40 }
41
42 static int look_ch(json_parser_t p)
43 {
44     while (*p->cp && strchr(" \t\r\n\f", *p->cp))
45         (p->cp)++;
46     return *p->cp;
47 }
48
49 static void move_ch(json_parser_t p)
50 {
51     if (*p->cp)
52         (p->cp)++;
53 }
54
55 static struct json_node *json_new_node(json_parser_t p, enum json_node_type type)
56 {
57     struct json_node *n = (struct json_node *) xmalloc(sizeof(*n));
58     n->type = type;
59     n->u.link[0] = n->u.link[1] = 0;
60     return n;
61 }
62
63 void json_remove_node(struct json_node *n)
64 {
65     if (!n)
66         return;
67     switch (n->type)
68     {
69     case json_node_object:
70     case json_node_array:
71     case json_node_list:
72     case json_node_pair:
73         json_remove_node(n->u.link[0]);
74         json_remove_node(n->u.link[1]);
75         break;
76     case json_node_string:
77         xfree(n->u.string);
78         break;
79     case json_node_number:
80     case json_node_true:
81     case json_node_false:
82     case json_node_null:
83         break;
84     }
85     xfree(n);
86 }
87
88 static struct json_node *json_parse_object(json_parser_t p);
89 static struct json_node *json_parse_array(json_parser_t p);
90
91 static int json_one_char(const char **p, char *out)
92 {
93     if (**p == '\\' && p[0][1])
94     {
95         (*p)++;
96         switch(**p)
97         {
98         case '"':
99             *out = '"'; break;
100         case '\\':
101             *out = '\\'; break;
102         case '/':
103             *out = '/'; break;
104         case 'b':
105             *out = '\b'; break;
106         case 'f':
107             *out = '\b'; break;
108         case 'n':
109             *out = '\n'; break;
110         case 'r':
111             *out = '\r'; break;
112         case 't':
113             *out = '\t'; break;
114         case 'u':
115             if (p[0][1])
116             {
117                 unsigned code;
118                 char *outp = out;
119                 int error;
120                 size_t outbytesleft = 6;
121                 sscanf(*p + 1, "%4x", &code);
122                 if (!yaz_write_UTF8_char(code, &outp, &outbytesleft, &error))
123                 {
124                     *p += 5;
125                     return outp - out;
126                 }
127             }
128         default:
129             *out = '_'; break;
130             break;
131         }
132         (*p)++;
133         return 1;
134     }
135     else
136     {
137         *out = **p;
138         (*p)++;
139         return 1;
140     }
141 }
142
143 static struct json_node *json_parse_string(json_parser_t p)
144 {
145     struct json_node *n;
146     const char *cp;
147     char *dst;
148     int l = 0;
149     if (look_ch(p) != '\"')
150     {
151         p->err_msg = "string expected";
152         return 0;
153     }
154     move_ch(p);
155
156     cp = p->cp;
157     while (*cp && *cp != '"')
158     {
159         char out[6];
160         l += json_one_char(&cp, out);
161     }
162     if (!*cp)
163     {
164         p->err_msg = "missing \"";
165         return 0;
166     }
167     n = json_new_node(p, json_node_string);
168     dst = n->u.string = (char *) xmalloc(l + 1);
169     
170     cp = p->cp;
171     while (*cp && *cp != '"')
172     {
173         char out[6];
174
175         l = json_one_char(&cp, out);
176         memcpy(dst, out, l);
177         dst += l;
178     }
179     *dst = '\0';
180     p->cp = cp+1;
181     return n;
182 }
183
184 static struct json_node *json_parse_number(json_parser_t p)
185 {
186     struct json_node *n;
187     char *endptr;
188     double v;
189
190     look_ch(p); // skip spaces
191     v = strtod(p->cp, &endptr);
192
193     if (endptr == p->cp)
194     {
195         p->err_msg = "bad number";
196         return 0;
197     }
198     p->cp = endptr;
199     n = json_new_node(p, json_node_number);
200     n->u.number = v;
201     return n;
202 }
203
204 static struct json_node *json_parse_value(json_parser_t p)
205 {
206     int c = look_ch(p);
207     if (c == '\"')
208         return json_parse_string(p);
209     else if (strchr("0123456789-+", c))
210         return json_parse_number(p);
211     else if (c == '{')
212         return json_parse_object(p);
213     else if (c == '[')
214         return json_parse_array(p);
215     else
216     {
217         char tok[8];
218         int i = 0;
219         while (c >= 'a' && c <= 'z' && i < 7)
220         {
221             tok[i++] = c;
222             p->cp++;
223             c = *p->cp;
224         }
225         tok[i] = 0;
226         if (!strcmp(tok, "true"))
227             return json_new_node(p, json_node_true);
228         else if (!strcmp(tok, "false"))
229             return json_new_node(p, json_node_false);
230         else if (!strcmp(tok, "null"))
231             return json_new_node(p, json_node_null);
232         else
233         {
234             p->err_msg = "bad value";
235             return 0;
236         }
237     }
238 }
239
240 static struct json_node *json_parse_elements(json_parser_t p)
241 {
242     struct json_node *n1 = json_parse_value(p);
243     struct json_node *m0, *m1;
244     if (!n1)
245         return 0;
246     m0 = m1 = json_new_node(p, json_node_list);
247     m1->u.link[0] = n1;
248     while (look_ch(p) == ',')
249     {
250         struct json_node *n2, *m2;
251         move_ch(p);
252         n2 = json_parse_value(p);
253         if (!n2)
254         {
255             json_remove_node(m0);
256             return 0;
257         }
258         m2 = json_new_node(p, json_node_list);
259         m2->u.link[0] = n2;
260         
261         m1->u.link[1] = m2;
262         m1 = m2;
263     }
264     return m0;
265 }
266
267 static struct json_node *json_parse_array(json_parser_t p)
268 {
269     struct json_node *n;
270     if (look_ch(p) != '[')
271     {
272         p->err_msg = "expecting [";
273         return 0;
274     }
275     move_ch(p);
276     n = json_new_node(p, json_node_array);
277     if (look_ch(p) != ']')
278         n->u.link[0] = json_parse_elements(p);
279
280     if (look_ch(p) != ']')
281     {
282         p->err_msg = "expecting ]";
283         json_remove_node(n);
284         return 0;
285     }
286     move_ch(p);
287     return n;
288 }
289
290 static struct json_node *json_parse_pair(json_parser_t p)
291 {
292     struct json_node *s = json_parse_string(p);
293     struct json_node *v, *n;
294     if (!s)
295         return 0;
296     if (look_ch(p) != ':')
297     {
298         json_remove_node(s);
299         return 0;
300     }
301     move_ch(p);
302     v = json_parse_value(p);
303     if (!v)
304     {
305         json_remove_node(s);
306         return 0;
307     }
308     n = json_new_node(p, json_node_pair);
309     n->u.link[0] = s;
310     n->u.link[1] = v;
311     return n;
312 }
313
314 static struct json_node *json_parse_members(json_parser_t p)
315 {
316     struct json_node *n1 = json_parse_pair(p);
317     struct json_node *m0, *m1;
318     if (!n1)
319         return 0;
320     m0 = m1 = json_new_node(p, json_node_list);
321     m1->u.link[0] = n1;
322     while (look_ch(p) == ',')
323     {
324         struct json_node *n2, *m2;
325         move_ch(p);
326         n2 = json_parse_pair(p);
327         if (!n2)
328         {
329             json_remove_node(m0);
330             return 0;
331         }
332         m2 = json_new_node(p, json_node_list);
333         m2->u.link[0] = n2;
334         
335         m1->u.link[1] = m2;
336         m1 = m2;
337     }
338     return m0;
339 }
340
341 static struct json_node *json_parse_object(json_parser_t p)
342 {
343     struct json_node *n;
344     if (look_ch(p) != '{')
345     {
346         p->err_msg = "{ expected";
347         return 0;
348     }
349     move_ch(p);
350
351     n = json_new_node(p, json_node_object);
352     if (look_ch(p) != '}')
353     {
354         struct json_node *m = json_parse_members(p);
355         if (!m)
356         {
357             json_remove_node(n);
358             return 0;
359         }
360         n->u.link[0] = m;
361     }
362     if (look_ch(p) != '}')
363     {
364         p->err_msg = "Missing }";
365         json_remove_node(n);
366         return 0;
367     }
368     move_ch(p);
369     return n;
370 }
371
372 struct json_node *json_parser_parse(json_parser_t p, const char *json_str)
373 {
374     int c;
375     struct json_node *n;
376     p->buf = json_str;
377     p->cp = p->buf;
378
379     n = json_parse_object(p);
380     c = look_ch(p);
381     if (c != 0)
382     {
383         p->err_msg = "extra characters";
384         json_remove_node(n);
385         return 0;
386     }
387     return n;
388 }
389
390 void json_write_wrbuf(struct json_node *node, WRBUF result)
391 {
392     switch (node->type)
393     {
394     case json_node_object:
395         wrbuf_puts(result, "{");
396         if (node->u.link[0])
397             json_write_wrbuf(node->u.link[0], result);
398         wrbuf_puts(result, "}");
399         break;
400     case json_node_array:
401         wrbuf_puts(result, "[");
402         if (node->u.link[0])
403             json_write_wrbuf(node->u.link[0], result);
404         wrbuf_puts(result, "]");
405         break;
406     case json_node_list:
407         json_write_wrbuf(node->u.link[0], result);
408         if (node->u.link[1])
409         {
410             wrbuf_puts(result, ",");
411             json_write_wrbuf(node->u.link[1], result);
412         }
413         break;
414     case json_node_pair:
415         json_write_wrbuf(node->u.link[0], result);
416         wrbuf_puts(result, ":");
417         json_write_wrbuf(node->u.link[1], result);
418         break;
419     case json_node_string:
420         wrbuf_puts(result, "\"");
421         wrbuf_puts(result, node->u.string);
422         wrbuf_puts(result, "\"");
423         break;
424     case json_node_number:
425         wrbuf_printf(result, "%lg", node->u.number);
426         break;
427     case json_node_true:
428         wrbuf_puts(result, "true");
429         break;
430     case json_node_false:
431         wrbuf_puts(result, "false");
432         break;
433     case json_node_null:
434         wrbuf_puts(result, "null");
435         break;
436     }
437 }
438
439 const char *json_parser_get_errmsg(json_parser_t p)
440 {
441     return p->err_msg;
442 }
443
444 /*
445  * Local variables:
446  * c-basic-offset: 4
447  * c-file-style: "Stroustrup"
448  * indent-tabs-mode: nil
449  * End:
450  * vim: shiftwidth=4 tabstop=8 expandtab
451  */