summaryrefslogtreecommitdiff
path: root/ext/solv_jsonparser.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/solv_jsonparser.c')
-rw-r--r--ext/solv_jsonparser.c91
1 files changed, 90 insertions, 1 deletions
diff --git a/ext/solv_jsonparser.c b/ext/solv_jsonparser.c
index ea31923..b3f25d8 100644
--- a/ext/solv_jsonparser.c
+++ b/ext/solv_jsonparser.c
@@ -136,6 +136,8 @@ parseutf8(struct solv_jsonparser *jp, int surrogate)
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 */
@@ -197,11 +199,47 @@ parsestring(struct solv_jsonparser *jp)
}
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;
+}
+
+static int
parsevalue(struct solv_jsonparser *jp)
{
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, c);
if ((c >= 'a' && c <= 'z'))
@@ -287,3 +325,54 @@ jsonparser_skip(struct solv_jsonparser *jp, int 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;
+}