Imported Upstream version 0.7.27
[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 (r == 0)
140     return -1;          /* no embedded NULs for now */
141   if (!surrogate && r >= 0xd800 && r < 0xdc00)
142     {
143       /* utf16 surrogate pair encodes 0x10000 - 0x10ffff */
144       int r2;
145       if (nextc(jp) != '\\' || nextc(jp) != 'u' || (r2 = parseutf8(jp, 1)) < 0xdc00 || r2 >= 0xe000)
146         return -1;
147       r = 0x10000 + ((r & 0x3ff) << 10 | (r2 & 0x3ff));
148     }
149   return r;
150 }
151
152 static int
153 parsestring(struct solv_jsonparser *jp)
154 {
155   int c;
156   for (;;)
157     {
158       if ((c = nextc(jp)) < 32)
159         return JP_ERROR;
160       if (c == '"')
161         break;
162       if (c == '\\')
163         {
164           switch (c = nextc(jp))
165             {
166             case '"':
167             case '\\':
168             case '/':
169             case '\n':
170               break;
171             case 'b':
172               c = '\b';
173               break;
174             case 'f':
175               c = '\f';
176               break;
177             case 'n':
178               c = '\n';
179               break;
180             case 'r':
181               c = '\r';
182               break;
183             case 't':
184               c = '\t';
185               break;
186             case 'u':
187               if ((c = parseutf8(jp, 0)) < 0)
188                 return JP_ERROR;
189               saveutf8(jp, c);
190               continue;
191             default:
192               return JP_ERROR;
193             }
194         }
195       savec(jp, c);
196     }
197   savec(jp, 0);
198   return JP_STRING;
199 }
200
201 static int
202 parsestring_raw(struct solv_jsonparser *jp)
203 {
204   int c;
205   savec(jp, '\"');
206   for (;;)
207     {
208       if ((c = nextc(jp)) < 32)
209         return JP_ERROR;
210       if (c == '"')
211         break;
212       if (c == '\\')
213         {
214           c = nextc(jp);
215           if (!c || !strchr("\"\\/\nbfnrtu", c))
216             return JP_ERROR;
217           savec(jp, '\\');
218           if (c == 'u')
219             {
220               int i;
221               for (i = 0; i < 4; i++)
222                 {
223                   savec(jp, c);
224                   c = nextc(jp);
225                   if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')))
226                     return JP_ERROR;
227                 }
228             }
229         }
230       savec(jp, c);
231     }
232   savec(jp, '\"');
233   savec(jp, 0);
234   return JP_STRING;
235 }
236
237 static int
238 parsevalue(struct solv_jsonparser *jp)
239 {
240   int c = skipspace(jp);
241   if (c == '"')
242     return jp->flags & JP_FLAG_RAWSTRINGS ? parsestring_raw(jp) : parsestring(jp);
243   if ((c >= '0' && c <= '9') || c == '+' || c == '-' || c == '.')
244     return parsenumber(jp, c);
245   if ((c >= 'a' && c <= 'z'))
246     return parseliteral(jp, c);
247   if (c == '[')
248     return JP_ARRAY;
249   if (c == '{')
250     return JP_OBJECT;
251   if (c == ']')
252     return JP_ARRAY_END;
253   if (c == '}')
254     return JP_OBJECT_END;
255   return JP_ERROR;
256 }
257
258 int
259 jsonparser_parse(struct solv_jsonparser *jp)
260 {
261   int type;
262   size_t nspace;
263
264   jp->depth = jp->stateq.count;
265   jp->key = jp->value = 0;
266   jp->keylen = jp->valuelen = 0;
267   nspace = jp->nspace = 0;
268
269   if (jp->state == JP_END)
270     return JP_END;
271   if (jp->state == JP_START)
272     jp->state = JP_END;
273   type = parsevalue(jp);
274   if (type <= 0)
275     return JP_ERROR;
276   if (type == JP_OBJECT_END || type == JP_ARRAY_END)
277     {
278       if (jp->state != type - 1)
279         return JP_ERROR;
280       jp->state = queue_pop(&jp->stateq);
281     }
282   else if (jp->state == JP_OBJECT)
283     {
284       nspace = jp->nspace;
285       if (type != JP_STRING)
286         return JP_ERROR;
287       if (skipspace(jp) != ':')
288         return JP_ERROR;
289       type = parsevalue(jp);
290       if (type == JP_OBJECT_END || type == JP_ARRAY_END)
291         return JP_ERROR;
292       jp->key = jp->space;
293       jp->keylen = nspace - 1;
294     }
295   if (type == JP_STRING || type == JP_NUMBER || type == JP_BOOL || type == JP_NULL)
296     {
297       jp->value = jp->space + nspace;
298       jp->valuelen = jp->nspace - nspace - 1;
299     }
300   if (type == JP_OBJECT || type == JP_ARRAY)
301     {
302       queue_push(&jp->stateq, jp->state);
303       jp->state = type;
304     }
305   else if (jp->state == JP_OBJECT || jp->state == JP_ARRAY)
306     {
307       int c = skipspace(jp);
308       if (c == (jp->state == JP_OBJECT ? '}' : ']'))
309         jp->nextc = c;
310       else if (c != ',')
311         return JP_ERROR;
312     }
313   return type;
314 }
315
316 int
317 jsonparser_skip(struct solv_jsonparser *jp, int type)
318 {
319   if (type == JP_ARRAY || type == JP_OBJECT)
320     {
321       int depth = jp->depth + 1, endtype = type + 1;
322       while (type > 0 && (type != endtype || jp->depth != depth))
323         type = jsonparser_parse(jp);
324     }
325   return type;
326 }
327
328 int
329 jsonparser_collect(struct solv_jsonparser *jp, int type, char **jsonp)
330 {
331   char *buf = 0;
332   size_t nbuf = 0;
333   int depth = jp->depth + 1, endtype = type + 1;
334   int oldflags = jp->flags;
335
336   if (type == JP_NUMBER || type == JP_BOOL || type == JP_NULL)
337     {
338       *jsonp = solv_strdup(jp->value);
339       return type;
340     }
341   if (type != JP_ARRAY && type != JP_OBJECT)
342     {
343       *jsonp = 0;
344       return JP_ERROR;
345     }
346   buf = solv_extend(buf, nbuf, 1, 1, 255);
347   buf[nbuf++] = type == JP_OBJECT ? '{' : '[';
348   jp->flags |= JP_FLAG_RAWSTRINGS;
349   while (type > 0 && (type != endtype || jp->depth != depth))
350     {
351       type = jsonparser_parse(jp);
352       if (type <= 0)
353         break;
354       buf = solv_extend(buf, nbuf, jp->keylen + jp->valuelen + 2, 1, 255);
355       if (type == JP_OBJECT_END || type == JP_ARRAY_END)
356         {
357           if (buf[nbuf - 1] == ',')
358             nbuf--;
359           buf[nbuf++] = type == JP_OBJECT_END ? '}' : ']';
360         }
361       else if (jp->key)
362         {
363           memcpy(buf + nbuf, jp->key, jp->keylen);
364           nbuf += jp->keylen;
365           buf[nbuf++] = ':';
366         }
367       if (jp->valuelen)
368         memcpy(buf + nbuf, jp->value, jp->valuelen);
369       nbuf += jp->valuelen;
370       buf[nbuf++] = type == JP_OBJECT ? '{' : type == JP_ARRAY ? '[' : ',';
371     }
372   jp->flags = oldflags;
373   buf[nbuf - 1] = 0;    /* overwrites trailing ',' */
374   if (type != endtype)
375     buf = solv_free(buf);
376   *jsonp = buf;
377   return type;
378 }