X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fshared%2Fjson.c;h=45c8ecedb31e3107df24cecf5432c139ee489d9c;hb=6600b726b8d077a430fcca0698040892f9aa979c;hp=f1495e99c8f551ea52d22c8feae7d98bfdb3826a;hpb=e7eebcfc42f00aa481ef31abc8e7e243c16f5b2c;p=elogind.git diff --git a/src/shared/json.c b/src/shared/json.c index f1495e99c..45c8ecedb 100644 --- a/src/shared/json.c +++ b/src/shared/json.c @@ -23,7 +23,6 @@ #include #include "macro.h" -#include "log.h" #include "util.h" #include "utf8.h" #include "json.h" @@ -53,6 +52,42 @@ static void inc_lines(unsigned *line, const char *s, size_t n) { } } +static int unhex_ucs2(const char *c, uint16_t *ret) { + int aa, bb, cc, dd; + uint16_t x; + + assert(c); + assert(ret); + + aa = unhexchar(c[0]); + if (aa < 0) + return -EINVAL; + + bb = unhexchar(c[1]); + if (bb < 0) + return -EINVAL; + + cc = unhexchar(c[2]); + if (cc < 0) + return -EINVAL; + + dd = unhexchar(c[3]); + if (dd < 0) + return -EINVAL; + + x = ((uint16_t) aa << 12) | + ((uint16_t) bb << 8) | + ((uint16_t) cc << 4) | + ((uint16_t) dd); + + if (x <= 0) + return -EINVAL; + + *ret = x; + + return 0; +} + static int json_parse_string(const char **p, char **ret) { _cleanup_free_ char *s = NULL; size_t n = 0, allocated = 0; @@ -119,39 +154,40 @@ static int json_parse_string(const char **p, char **ret) { else if (*c == 't') ch = '\t'; else if (*c == 'u') { - int aa, bb, cc, dd; uint16_t x; + int r; - aa = unhexchar(c[1]); - if (aa < 0) - return -EINVAL; + r = unhex_ucs2(c + 1, &x); + if (r < 0) + return r; - bb = unhexchar(c[2]); - if (bb < 0) - return -EINVAL; + c += 5; - cc = unhexchar(c[3]); - if (cc < 0) - return -EINVAL; + if (!GREEDY_REALLOC(s, allocated, n + 4)) + return -ENOMEM; - dd = unhexchar(c[4]); - if (dd < 0) + if (!utf16_is_surrogate(x)) + n += utf8_encode_unichar(s + n, x); + else if (utf16_is_trailing_surrogate(x)) return -EINVAL; + else { + uint16_t y; + if (c[0] != '\\' || c[1] != 'u') + return -EINVAL; - x = ((uint16_t) aa << 12) | - ((uint16_t) bb << 8) | - ((uint16_t) cc << 4) | - ((uint16_t) dd); + r = unhex_ucs2(c + 2, &y); + if (r < 0) + return r; - if (x <= 0) - return -EINVAL; + c += 6; - if (!GREEDY_REALLOC(s, allocated, n + 4)) - return -ENOMEM; + if (!utf16_is_trailing_surrogate(y)) + return -EINVAL; + + n += utf8_encode_unichar(s + n, utf16_surrogate_pair_to_unichar(x, y)); + } - n += utf8_encode_unichar(x, s + n); - c += 5; continue; } else return -EINVAL;