[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH v5 1/2] json: Add function to unescape JSON-encoded strings
From: |
Patrick Steinhardt |
Subject: |
[PATCH v5 1/2] json: Add function to unescape JSON-encoded strings |
Date: |
Mon, 11 Jul 2022 12:44:54 +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 | 118 ++++++++++++++++++++++++++++++++++++++
grub-core/lib/json/json.h | 12 ++++
2 files changed, 130 insertions(+)
diff --git a/grub-core/lib/json/json.c b/grub-core/lib/json/json.c
index 1c20c75ea..1eadd1ce9 100644
--- a/grub-core/lib/json/json.c
+++ b/grub-core/lib/json/json.c
@@ -262,3 +262,121 @@ 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, grub_size_t *outlen, const char *in,
grub_size_t inlen)
+{
+ grub_err_t ret = GRUB_ERR_NONE;
+ grub_size_t inpos, resultpos;
+ char *result;
+
+ if (out == NULL || outlen == NULL)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("output parameters are not
set"));
+
+ result = grub_calloc (1, inlen + 1);
+ if (result == NULL)
+ return GRUB_ERR_OUT_OF_MEMORY;
+
+ for (inpos = resultpos = 0; inpos < inlen; inpos++)
+ {
+ if (in[inpos] == '\\')
+ {
+ inpos++;
+ if (inpos >= inlen)
+ {
+ ret = grub_error (GRUB_ERR_BAD_ARGUMENT, N_("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':
+ {
+ char values[4] = {0};
+ unsigned i;
+
+ inpos++;
+ if (inpos + ARRAY_SIZE(values) > inlen)
+ {
+ ret = grub_error (GRUB_ERR_BAD_ARGUMENT, N_("unicode
sequence too short"));
+ goto err;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(values); 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,
+ N_("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, N_("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 ret;
+}
diff --git a/grub-core/lib/json/json.h b/grub-core/lib/json/json.h
index 4ea2a22d8..626074c35 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, grub_size_t
*outlen,
+ const char *in, grub_size_t
inlen);
+
#endif
--
2.37.0
signature.asc
Description: PGP signature