lib/json/json: Add function to unescape JSON-encoded strings
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: Daniel Kiper <dkiper@net-space.pl>
This commit is contained in:
parent
5730424cb9
commit
b4055ebb8b
@ -262,3 +262,121 @@ grub_json_getint64 (grub_int64_t *out, const grub_json_t *parent, const char *ke
|
|||||||
|
|
||||||
return GRUB_ERR_NONE;
|
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;
|
||||||
|
}
|
||||||
|
|||||||
@ -125,4 +125,16 @@ extern grub_err_t EXPORT_FUNC(grub_json_getint64) (grub_int64_t *out,
|
|||||||
const grub_json_t *parent,
|
const grub_json_t *parent,
|
||||||
const char *key);
|
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
|
#endif
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user