Imported Upstream version 0.7.27
[platform/upstream/libsolv.git] / ext / solv_jsonparser.c
index 053ee6f..b3f25d8 100644 (file)
@@ -15,7 +15,7 @@
 #include "util.h"
 #include "solv_jsonparser.h"
 
-struct solv_jsonparser *
+void
 jsonparser_init(struct solv_jsonparser *jp, FILE *fp)
 {
   memset(jp, 0, sizeof(*jp));
@@ -24,14 +24,13 @@ jsonparser_init(struct solv_jsonparser *jp, FILE *fp)
   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
@@ -73,18 +72,18 @@ static int
 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);
@@ -104,10 +103,9 @@ parseliteral(struct solv_jsonparser *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);
@@ -138,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 */
@@ -194,7 +194,42 @@ parsestring(struct solv_jsonparser *jp)
        }
       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;
 }
@@ -204,12 +239,11 @@ 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);
+    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 == '{')
@@ -252,7 +286,6 @@ jsonparser_parse(struct solv_jsonparser *jp)
        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;
@@ -264,7 +297,7 @@ jsonparser_parse(struct solv_jsonparser *jp)
       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;
@@ -272,9 +305,9 @@ jsonparser_parse(struct solv_jsonparser *jp)
   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;
@@ -292,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;
+}