[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [PATCH v4 1/2] json: Add function to unescape JSON-encoded strings
From: |
Glenn Washburn |
Subject: |
Re: [PATCH v4 1/2] json: Add function to unescape JSON-encoded strings |
Date: |
Mon, 6 Jun 2022 12:17:11 -0500 |
On Mon, 6 Jun 2022 07:28:56 +0200
Patrick Steinhardt <ps@pks.im> wrote:
> 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>
Reviewed-by: Glenn Washburn <development@efficientek.com>
Glenn
> ---
> grub-core/lib/json/json.c | 101 ++++++++++++++++++++++++++++++++++++++
> grub-core/lib/json/json.h | 12 +++++
> 2 files changed, 113 insertions(+)
>
> diff --git a/grub-core/lib/json/json.c b/grub-core/lib/json/json.c
> index 1c20c75ea..adb4747a4 100644
> --- a/grub-core/lib/json/json.c
> +++ b/grub-core/lib/json/json.c
> @@ -262,3 +262,104 @@ 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 || !outlen)
> + return grub_error (GRUB_ERR_BAD_ARGUMENT, "Output parameters are not
> set");
> +
> + result = grub_calloc (1, inlen + 1);
> + if (!result)
> + 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, "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 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