#include "util.h"
#include "solv_jsonparser.h"
-struct solv_jsonparser *
+void
jsonparser_init(struct solv_jsonparser *jp, FILE *fp)
{
memset(jp, 0, sizeof(*jp));
jp->line = jp->nextline = 1;
jp->nextc = ' ';
queue_init(&jp->stateq);
- return jp;
}
-struct solv_jsonparser *
+void
jsonparser_free(struct solv_jsonparser *jp)
{
+ solv_free(jp->space);
queue_free(&jp->stateq);
- return 0;
}
static void
skipspace(struct solv_jsonparser *jp)
{
int c = jp->nextc;
+ jp->nextc = ' ';
while (c == ' ' || c == '\t' || c == '\r' || c == '\n')
c = nextc(jp);
jp->line = jp->nextline;
- return (jp->nextc = c);
+ return c;
}
static int
-parseliteral(struct solv_jsonparser *jp)
+parseliteral(struct solv_jsonparser *jp, int c)
{
size_t nspace = jp->nspace;
- int c;
- savec(jp, jp->nextc);
+ savec(jp, c);
for (;;)
{
c = nextc(jp);
}
static int
-parsenumber(struct solv_jsonparser *jp)
+parsenumber(struct solv_jsonparser *jp, int c)
{
- int c;
- savec(jp, jp->nextc);
+ savec(jp, c);
for (;;)
{
c = nextc(jp);
return -1;
r = (r << 4) | c;
}
+ if (r == 0)
+ return -1; /* no embedded NULs for now */
if (!surrogate && r >= 0xd800 && r < 0xdc00)
{
/* utf16 surrogate pair encodes 0x10000 - 0x10ffff */
}
savec(jp, c);
}
- jp->nextc = ' ';
+ savec(jp, 0);
+ return JP_STRING;
+}
+
+static int
+parsestring_raw(struct solv_jsonparser *jp)
+{
+ int c;
+ savec(jp, '\"');
+ for (;;)
+ {
+ if ((c = nextc(jp)) < 32)
+ return JP_ERROR;
+ if (c == '"')
+ break;
+ if (c == '\\')
+ {
+ c = nextc(jp);
+ if (!c || !strchr("\"\\/\nbfnrtu", c))
+ return JP_ERROR;
+ savec(jp, '\\');
+ if (c == 'u')
+ {
+ int i;
+ for (i = 0; i < 4; i++)
+ {
+ savec(jp, c);
+ c = nextc(jp);
+ if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')))
+ return JP_ERROR;
+ }
+ }
+ }
+ savec(jp, c);
+ }
+ savec(jp, '\"');
savec(jp, 0);
return JP_STRING;
}
{
int c = skipspace(jp);
if (c == '"')
- return parsestring(jp);
+ return jp->flags & JP_FLAG_RAWSTRINGS ? parsestring_raw(jp) : parsestring(jp);
if ((c >= '0' && c <= '9') || c == '+' || c == '-' || c == '.')
- return parsenumber(jp);
+ return parsenumber(jp, c);
if ((c >= 'a' && c <= 'z'))
- return parseliteral(jp);
- jp->nextc = ' ';
+ return parseliteral(jp, c);
if (c == '[')
return JP_ARRAY;
if (c == '{')
return JP_ERROR;
if (skipspace(jp) != ':')
return JP_ERROR;
- jp->nextc = ' ';
type = parsevalue(jp);
if (type == JP_OBJECT_END || type == JP_ARRAY_END)
return JP_ERROR;
jp->value = jp->space + nspace;
jp->valuelen = jp->nspace - nspace - 1;
}
- if (type == JP_ARRAY || type == JP_OBJECT)
+ if (type == JP_OBJECT || type == JP_ARRAY)
{
queue_push(&jp->stateq, jp->state);
jp->state = type;
else if (jp->state == JP_OBJECT || jp->state == JP_ARRAY)
{
int c = skipspace(jp);
- if (c == ',')
- jp->nextc = ' ';
- else if (c != (jp->state == JP_OBJECT ? '}' : ']'))
+ if (c == (jp->state == JP_OBJECT ? '}' : ']'))
+ jp->nextc = c;
+ else if (c != ',')
return JP_ERROR;
}
return type;
return type;
}
+int
+jsonparser_collect(struct solv_jsonparser *jp, int type, char **jsonp)
+{
+ char *buf = 0;
+ size_t nbuf = 0;
+ int depth = jp->depth + 1, endtype = type + 1;
+ int oldflags = jp->flags;
+
+ if (type == JP_NUMBER || type == JP_BOOL || type == JP_NULL)
+ {
+ *jsonp = solv_strdup(jp->value);
+ return type;
+ }
+ if (type != JP_ARRAY && type != JP_OBJECT)
+ {
+ *jsonp = 0;
+ return JP_ERROR;
+ }
+ buf = solv_extend(buf, nbuf, 1, 1, 255);
+ buf[nbuf++] = type == JP_OBJECT ? '{' : '[';
+ jp->flags |= JP_FLAG_RAWSTRINGS;
+ while (type > 0 && (type != endtype || jp->depth != depth))
+ {
+ type = jsonparser_parse(jp);
+ if (type <= 0)
+ break;
+ buf = solv_extend(buf, nbuf, jp->keylen + jp->valuelen + 2, 1, 255);
+ if (type == JP_OBJECT_END || type == JP_ARRAY_END)
+ {
+ if (buf[nbuf - 1] == ',')
+ nbuf--;
+ buf[nbuf++] = type == JP_OBJECT_END ? '}' : ']';
+ }
+ else if (jp->key)
+ {
+ memcpy(buf + nbuf, jp->key, jp->keylen);
+ nbuf += jp->keylen;
+ buf[nbuf++] = ':';
+ }
+ if (jp->valuelen)
+ memcpy(buf + nbuf, jp->value, jp->valuelen);
+ nbuf += jp->valuelen;
+ buf[nbuf++] = type == JP_OBJECT ? '{' : type == JP_ARRAY ? '[' : ',';
+ }
+ jp->flags = oldflags;
+ buf[nbuf - 1] = 0; /* overwrites trailing ',' */
+ if (type != endtype)
+ buf = solv_free(buf);
+ *jsonp = buf;
+ return type;
+}