grub-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH v3 1/2] json: Add function to unescape JSON-encoded strings


From: Patrick Steinhardt
Subject: [PATCH v3 1/2] json: Add function to unescape JSON-encoded strings
Date: Mon, 30 May 2022 18:01:01 +0200

JSON strings require certain characters to be encoded, either by using a
single reverse solidus character "\" for a set of popular characters, or
by using a Unicode representation of "\uXXXXX". The jsmn library doesn't
handle unescaping for us, so we must implement this functionality for
ourselves.

Add a new function `grub_json_unescape ()` that takes a potentially
escaped JSON string as input and returns a new unescaped string.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 grub-core/lib/json/json.c | 98 +++++++++++++++++++++++++++++++++++++++
 grub-core/lib/json/json.h | 12 +++++
 2 files changed, 110 insertions(+)

diff --git a/grub-core/lib/json/json.c b/grub-core/lib/json/json.c
index 1c20c75ea..3e5e25f79 100644
--- a/grub-core/lib/json/json.c
+++ b/grub-core/lib/json/json.c
@@ -262,3 +262,101 @@ grub_json_getint64 (grub_int64_t *out, const grub_json_t 
*parent, const char *ke
 
   return GRUB_ERR_NONE;
 }
+
+grub_err_t
+grub_json_unescape (char **out, size_t *outlen, const char *in, size_t inlen)
+{
+  grub_err_t ret = GRUB_ERR_NONE;
+  size_t inpos, resultpos;
+  char *result;
+
+  result = grub_calloc (1, inlen + 1);
+
+  for (inpos = resultpos = 0; inpos < inlen; inpos++)
+    {
+      if (in[inpos] == '\\')
+       {
+         inpos++;
+         if (inpos >= inlen)
+           {
+             ret = grub_error (GRUB_ERR_BAD_ARGUMENT, "Expected escaped 
character");
+             goto err;
+           }
+
+         switch (in[inpos])
+           {
+             case '"':
+               result[resultpos++] = '"'; break;
+             case '/':
+               result[resultpos++] = '/'; break;
+             case '\\':
+               result[resultpos++] = '\\'; break;
+             case 'b':
+               result[resultpos++] = '\b'; break;
+             case 'f':
+               result[resultpos++] = '\f'; break;
+             case 'r':
+               result[resultpos++] = '\r'; break;
+             case 'n':
+               result[resultpos++] = '\n'; break;
+             case 't':
+               result[resultpos++] = '\t'; break;
+             case 'u':
+               {
+                 unsigned char values[4] = {0};
+                 int i;
+
+                 inpos++;
+                 if (inpos + ARRAY_SIZE(values) > inlen)
+                   {
+                     ret = grub_error (GRUB_ERR_BAD_ARGUMENT, "Unicode 
sequence too short");
+                     goto err;
+                   }
+
+                 for (i = 0; i < 4; i++)
+                   {
+                     char c = in[inpos++];
+
+                     if (c >= '0' && c <= '9')
+                       values[i] = c - '0';
+                     else if (c >= 'A' && c <= 'F')
+                       values[i] = c - 'A' + 10;
+                     else if (c >= 'a' && c <= 'f')
+                       values[i] = c - 'a' + 10;
+                     else
+                       {
+                         ret = grub_error (GRUB_ERR_BAD_ARGUMENT,
+                                           "Unicode sequence with invalid 
character '%c'", c);
+                         goto err;
+                       }
+                   }
+
+                 if (values[0] != 0 || values[1] != 0)
+                   result[resultpos++] = values[0] << 4 | values[1];
+                 result[resultpos++] = values[2] << 4 | values[3];
+
+                 /* Offset the increment that's coming in via the loop 
increment. */
+                 inpos--;
+
+                 break;
+               }
+             default:
+               ret = grub_error (GRUB_ERR_BAD_ARGUMENT, "Unrecognized escaped 
character '%c'", in[inpos]);
+               goto err;
+           }
+       }
+      else
+       {
+         result[resultpos++] = in[inpos];
+       }
+    }
+
+  *out = result;
+  *outlen = resultpos;
+
+err:
+  if (ret != GRUB_ERR_NONE)
+    grub_free (result);
+
+  return GRUB_ERR_NONE;
+}
diff --git a/grub-core/lib/json/json.h b/grub-core/lib/json/json.h
index 4ea2a22d8..37a5a5f57 100644
--- a/grub-core/lib/json/json.h
+++ b/grub-core/lib/json/json.h
@@ -125,4 +125,16 @@ extern grub_err_t EXPORT_FUNC(grub_json_getint64) 
(grub_int64_t *out,
                                                   const grub_json_t *parent,
                                                   const char *key);
 
+/*
+ * Unescape escaped characters and Unicode sequences in the
+ * given JSON-encoded string. Returns a newly allocated string
+ * passed back via the `out` parameter that has a length of
+ * `*outlen`.
+ *
+ * See https://datatracker.ietf.org/doc/html/rfc8259#section-7 for more
+ * information on escaping in JSON.
+ */
+extern grub_err_t EXPORT_FUNC(grub_json_unescape) (char **out, size_t *outlen,
+                                                  const char *in, size_t 
inlen);
+
 #endif
-- 
2.36.1

Attachment: signature.asc
Description: PGP signature


reply via email to

[Prev in Thread] Current Thread [Next in Thread]