4 * Simple JSON stream parser
6 * Copyright (c) 2018, SUSE LLC
8 * This program is licensed under the BSD license, read LICENSE.BSD
9 * for further information
16 #include "solv_jsonparser.h"
19 jsonparser_init(struct solv_jsonparser *jp, FILE *fp)
21 memset(jp, 0, sizeof(*jp));
24 jp->line = jp->nextline = 1;
26 queue_init(&jp->stateq);
30 jsonparser_free(struct solv_jsonparser *jp)
33 queue_free(&jp->stateq);
37 savec(struct solv_jsonparser *jp, char c)
39 if (jp->nspace == jp->aspace)
42 jp->space = solv_realloc(jp->space, jp->aspace);
44 jp->space[jp->nspace++] = c;
48 saveutf8(struct solv_jsonparser *jp, int c)
56 i = c < 0x800 ? 1 : c < 0x10000 ? 2 : 3;
57 savec(jp, (0x1f80 >> i) | (c >> (6 * i)));
59 savec(jp, 0x80 | ((c >> (6 * i)) & 0x3f));
63 nextc(struct solv_jsonparser *jp)
72 skipspace(struct solv_jsonparser *jp)
76 while (c == ' ' || c == '\t' || c == '\r' || c == '\n')
78 jp->line = jp->nextline;
83 parseliteral(struct solv_jsonparser *jp, int c)
85 size_t nspace = jp->nspace;
90 if (c < 'a' || c > 'z')
96 if (!strcmp(jp->space + nspace, "true"))
98 if (!strcmp(jp->space + nspace, "false"))
100 if (!strcmp(jp->space + nspace, "null"))
106 parsenumber(struct solv_jsonparser *jp, int c)
112 if ((c < '0' || c > '9') && c != '+' && c != '-' && c != '.' && c != 'e' && c != 'E')
122 parseutf8(struct solv_jsonparser *jp, int surrogate)
125 /* parse 4-digit hex */
126 for (i = 0; i < 4; i++)
129 if (c >= '0' && c <= '9')
131 else if (c >= 'a' && c <= 'f')
133 else if (c >= 'A' && c <= 'F')
140 return -1; /* no embedded NULs for now */
141 if (!surrogate && r >= 0xd800 && r < 0xdc00)
143 /* utf16 surrogate pair encodes 0x10000 - 0x10ffff */
145 if (nextc(jp) != '\\' || nextc(jp) != 'u' || (r2 = parseutf8(jp, 1)) < 0xdc00 || r2 >= 0xe000)
147 r = 0x10000 + ((r & 0x3ff) << 10 | (r2 & 0x3ff));
153 parsestring(struct solv_jsonparser *jp)
158 if ((c = nextc(jp)) < 32)
164 switch (c = nextc(jp))
187 if ((c = parseutf8(jp, 0)) < 0)
202 parsestring_raw(struct solv_jsonparser *jp)
208 if ((c = nextc(jp)) < 32)
215 if (!c || !strchr("\"\\/\nbfnrtu", c))
221 for (i = 0; i < 4; i++)
225 if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')))
238 parsevalue(struct solv_jsonparser *jp)
240 int c = skipspace(jp);
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);
254 return JP_OBJECT_END;
259 jsonparser_parse(struct solv_jsonparser *jp)
264 jp->depth = jp->stateq.count;
265 jp->key = jp->value = 0;
266 jp->keylen = jp->valuelen = 0;
267 nspace = jp->nspace = 0;
269 if (jp->state == JP_END)
271 if (jp->state == JP_START)
273 type = parsevalue(jp);
276 if (type == JP_OBJECT_END || type == JP_ARRAY_END)
278 if (jp->state != type - 1)
280 jp->state = queue_pop(&jp->stateq);
282 else if (jp->state == JP_OBJECT)
285 if (type != JP_STRING)
287 if (skipspace(jp) != ':')
289 type = parsevalue(jp);
290 if (type == JP_OBJECT_END || type == JP_ARRAY_END)
293 jp->keylen = nspace - 1;
295 if (type == JP_STRING || type == JP_NUMBER || type == JP_BOOL || type == JP_NULL)
297 jp->value = jp->space + nspace;
298 jp->valuelen = jp->nspace - nspace - 1;
300 if (type == JP_OBJECT || type == JP_ARRAY)
302 queue_push(&jp->stateq, jp->state);
305 else if (jp->state == JP_OBJECT || jp->state == JP_ARRAY)
307 int c = skipspace(jp);
308 if (c == (jp->state == JP_OBJECT ? '}' : ']'))
317 jsonparser_skip(struct solv_jsonparser *jp, int type)
319 if (type == JP_ARRAY || type == JP_OBJECT)
321 int depth = jp->depth + 1, endtype = type + 1;
322 while (type > 0 && (type != endtype || jp->depth != depth))
323 type = jsonparser_parse(jp);
329 jsonparser_collect(struct solv_jsonparser *jp, int type, char **jsonp)
333 int depth = jp->depth + 1, endtype = type + 1;
334 int oldflags = jp->flags;
336 if (type == JP_NUMBER || type == JP_BOOL || type == JP_NULL)
338 *jsonp = solv_strdup(jp->value);
341 if (type != JP_ARRAY && type != JP_OBJECT)
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))
351 type = jsonparser_parse(jp);
354 buf = solv_extend(buf, nbuf, jp->keylen + jp->valuelen + 2, 1, 255);
355 if (type == JP_OBJECT_END || type == JP_ARRAY_END)
357 if (buf[nbuf - 1] == ',')
359 buf[nbuf++] = type == JP_OBJECT_END ? '}' : ']';
363 memcpy(buf + nbuf, jp->key, jp->keylen);
368 memcpy(buf + nbuf, jp->value, jp->valuelen);
369 nbuf += jp->valuelen;
370 buf[nbuf++] = type == JP_OBJECT ? '{' : type == JP_ARRAY ? '[' : ',';
372 jp->flags = oldflags;
373 buf[nbuf - 1] = 0; /* overwrites trailing ',' */
375 buf = solv_free(buf);