Imported Upstream version 0.7.5
[platform/upstream/libsolv.git] / ext / solv_jsonparser.c
1 /*
2  * solv_jsonparser.c
3  *
4  * Simple JSON stream parser
5  *
6  * Copyright (c) 2018, SUSE LLC
7  *
8  * This program is licensed under the BSD license, read LICENSE.BSD
9  * for further information
10  */
11
12 #include <stdio.h>
13 #include <stdlib.h>
14
15 #include "util.h"
16 #include "solv_jsonparser.h"
17
18 void
19 jsonparser_init(struct solv_jsonparser *jp, FILE *fp)
20 {
21   memset(jp, 0, sizeof(*jp));
22   jp->fp = fp;
23   jp->state = JP_START;
24   jp->line = jp->nextline = 1;
25   jp->nextc = ' ';
26   queue_init(&jp->stateq);
27 }
28
29 void
30 jsonparser_free(struct solv_jsonparser *jp)
31 {
32   solv_free(jp->space);
33   queue_free(&jp->stateq);
34 }
35
36 static void
37 savec(struct solv_jsonparser *jp, char c)
38 {
39   if (jp->nspace == jp->aspace)
40     {
41       jp->aspace += 256;
42       jp->space = solv_realloc(jp->space, jp->aspace);
43     }
44   jp->space[jp->nspace++] = c;
45 }
46
47 static void
48 saveutf8(struct solv_jsonparser *jp, int c)
49 {
50   int i;
51   if (c < 0x80)
52     {
53       savec(jp, c);
54       return;
55     }
56   i = c < 0x800 ? 1 : c < 0x10000 ? 2 : 3;
57   savec(jp, (0x1f80 >> i) | (c >> (6 * i)));
58   while (--i >= 0)
59     savec(jp, 0x80 | ((c >> (6 * i)) & 0x3f));
60 }
61
62 static inline int
63 nextc(struct solv_jsonparser *jp)
64 {
65   int c = getc(jp->fp);
66   if (c == '\n')
67     jp->nextline++;
68   return c;
69 }
70
71 static int
72 skipspace(struct solv_jsonparser *jp)
73 {
74   int c = jp->nextc;
75   jp->nextc = ' ';
76   while (c == ' ' || c == '\t' || c == '\r' || c == '\n')
77     c = nextc(jp);
78   jp->line = jp->nextline;
79   return c;
80 }
81
82 static int
83 parseliteral(struct solv_jsonparser *jp, int c)
84 {
85   size_t nspace = jp->nspace;
86   savec(jp, c);
87   for (;;)
88     {
89       c = nextc(jp);
90       if (c < 'a' || c > 'z')
91         break;
92       savec(jp, c);
93     }
94   jp->nextc = c;
95   savec(jp, 0);
96   if (!strcmp(jp->space + nspace, "true"))
97     return JP_BOOL;
98   if (!strcmp(jp->space + nspace, "false"))
99     return JP_BOOL;
100   if (!strcmp(jp->space + nspace, "null"))
101     return JP_NULL;
102   return JP_ERROR;
103 }
104
105 static int
106 parsenumber(struct solv_jsonparser *jp, int c)
107 {
108   savec(jp, c);
109   for (;;)
110     {
111       c = nextc(jp);
112       if ((c < '0' || c > '9') && c != '+' && c != '-' && c != '.' && c != 'e' && c != 'E')
113         break;
114       savec(jp, c);
115     }
116   jp->nextc = c;
117   savec(jp, 0);
118   return JP_NUMBER;
119 }
120
121 static int
122 parseutf8(struct solv_jsonparser *jp, int surrogate)
123 {
124   int c, i, r = 0;
125   /* parse 4-digit hex */
126   for (i = 0; i < 4; i++)
127     {
128       c = nextc(jp);
129       if (c >= '0' && c <= '9')
130         c -= '0';
131       else if (c >= 'a' && c <= 'f')
132         c -= 'a' - 10;
133       else if (c >= 'A' && c <= 'F')
134         c -= 'A' - 10;
135       else
136         return -1;
137       r = (r << 4) | c;
138     }
139   if (!surrogate && r >= 0xd800 && r < 0xdc00)
140     {
141       /* utf16 surrogate pair encodes 0x10000 - 0x10ffff */
142       int r2;
143       if (nextc(jp) != '\\' || nextc(jp) != 'u' || (r2 = parseutf8(jp, 1)) < 0xdc00 || r2 >= 0xe000)
144         return -1;
145       r = 0x10000 + ((r & 0x3ff) << 10 | (r2 & 0x3ff));
146     }
147   return r;
148 }
149
150 static int
151 parsestring(struct solv_jsonparser *jp)
152 {
153   int c;
154   for (;;)
155     {
156       if ((c = nextc(jp)) < 32)
157         return JP_ERROR;
158       if (c == '"')
159         break;
160       if (c == '\\')
161         {
162           switch (c = nextc(jp))
163             {
164             case '"':
165             case '\\':
166             case '/':
167             case '\n':
168               break;
169             case 'b':
170               c = '\b';
171               break;
172             case 'f':
173               c = '\f';
174               break;
175             case 'n':
176               c = '\n';
177               break;
178             case 'r':
179               c = '\r';
180               break;
181             case 't':
182               c = '\t';
183               break;
184             case 'u':
185               if ((c = parseutf8(jp, 0)) < 0)
186                 return JP_ERROR;
187               saveutf8(jp, c);
188               continue;
189             default:
190               return JP_ERROR;
191             }
192         }
193       savec(jp, c);
194     }
195   savec(jp, 0);
196   return JP_STRING;
197 }
198
199 static int
200 parsevalue(struct solv_jsonparser *jp)
201 {
202   int c = skipspace(jp);
203   if (c == '"')
204     return parsestring(jp);
205   if ((c >= '0' && c <= '9') || c == '+' || c == '-' || c == '.')
206     return parsenumber(jp, c);
207   if ((c >= 'a' && c <= 'z'))
208     return parseliteral(jp, c);
209   if (c == '[')
210     return JP_ARRAY;
211   if (c == '{')
212     return JP_OBJECT;
213   if (c == ']')
214     return JP_ARRAY_END;
215   if (c == '}')
216     return JP_OBJECT_END;
217   return JP_ERROR;
218 }
219
220 int
221 jsonparser_parse(struct solv_jsonparser *jp)
222 {
223   int type;
224   size_t nspace;
225
226   jp->depth = jp->stateq.count;
227   jp->key = jp->value = 0;
228   jp->keylen = jp->valuelen = 0;
229   nspace = jp->nspace = 0;
230
231   if (jp->state == JP_END)
232     return JP_END;
233   if (jp->state == JP_START)
234     jp->state = JP_END;
235   type = parsevalue(jp);
236   if (type <= 0)
237     return JP_ERROR;
238   if (type == JP_OBJECT_END || type == JP_ARRAY_END)
239     {
240       if (jp->state != type - 1)
241         return JP_ERROR;
242       jp->state = queue_pop(&jp->stateq);
243     }
244   else if (jp->state == JP_OBJECT)
245     {
246       nspace = jp->nspace;
247       if (type != JP_STRING)
248         return JP_ERROR;
249       if (skipspace(jp) != ':')
250         return JP_ERROR;
251       type = parsevalue(jp);
252       if (type == JP_OBJECT_END || type == JP_ARRAY_END)
253         return JP_ERROR;
254       jp->key = jp->space;
255       jp->keylen = nspace - 1;
256     }
257   if (type == JP_STRING || type == JP_NUMBER || type == JP_BOOL || type == JP_NULL)
258     {
259       jp->value = jp->space + nspace;
260       jp->valuelen = jp->nspace - nspace - 1;
261     }
262   if (type == JP_OBJECT || type == JP_ARRAY)
263     {
264       queue_push(&jp->stateq, jp->state);
265       jp->state = type;
266     }
267   else if (jp->state == JP_OBJECT || jp->state == JP_ARRAY)
268     {
269       int c = skipspace(jp);
270       if (c == (jp->state == JP_OBJECT ? '}' : ']'))
271         jp->nextc = c;
272       else if (c != ',')
273         return JP_ERROR;
274     }
275   return type;
276 }
277
278 int
279 jsonparser_skip(struct solv_jsonparser *jp, int type)
280 {
281   if (type == JP_ARRAY || type == JP_OBJECT)
282     {
283       int depth = jp->depth + 1, endtype = type + 1;
284       while (type > 0 && (type != endtype || jp->depth != depth))
285         type = jsonparser_parse(jp);
286     }
287   return type;
288 }
289