X-Git-Url: https://git.ozlabs.org/?a=blobdiff_plain;f=ccan%2Fjson_escape%2Fjson_escape.c;fp=ccan%2Fjson_escape%2Fjson_escape.c;h=d344940de0a5d934da693b959857326da194fb55;hb=45f9ce170fe09bca014d874ffaa13b900c8285ba;hp=0000000000000000000000000000000000000000;hpb=7623d0829a63e7f95ed6f116b7e9f2f4a023e8e7;p=ccan diff --git a/ccan/json_escape/json_escape.c b/ccan/json_escape/json_escape.c new file mode 100644 index 00000000..d344940d --- /dev/null +++ b/ccan/json_escape/json_escape.c @@ -0,0 +1,157 @@ +/* MIT (BSD) license - see LICENSE file for details */ +#include +#include + +struct json_escape *json_escape_string_(const tal_t *ctx, + const void *bytes, size_t len) +{ + struct json_escape *esc; + + esc = (void *)tal_arr_label(ctx, char, len + 1, + TAL_LABEL(struct json_escape, "")); + memcpy(esc->s, bytes, len); + esc->s[len] = '\0'; + return esc; +} + +bool json_escape_eq(const struct json_escape *a, const struct json_escape *b) +{ + return streq(a->s, b->s); +} + +static struct json_escape *escape(const tal_t *ctx, + const char *str TAKES, + size_t len, + bool partial) +{ + struct json_escape *esc; + size_t i, n; + + /* Worst case: all \uXXXX */ + esc = (struct json_escape *)tal_arr(ctx, char, len * 6 + 1); + + for (i = n = 0; i < len; i++, n++) { + char escape = 0; + switch (str[i]) { + case '\n': + escape = 'n'; + break; + case '\b': + escape = 'b'; + break; + case '\f': + escape = 'f'; + break; + case '\t': + escape = 't'; + break; + case '\r': + escape = 'r'; + break; + case '\\': + if (partial) { + /* Don't double-escape standard escapes. */ + if (str[i+1] == 'n' + || str[i+1] == 'b' + || str[i+1] == 'f' + || str[i+1] == 't' + || str[i+1] == 'r' + || str[i+1] == '/' + || str[i+1] == '\\' + || str[i+1] == '"') { + escape = str[i+1]; + i++; + break; + } + if (str[i+1] == 'u' + && cisxdigit(str[i+2]) + && cisxdigit(str[i+3]) + && cisxdigit(str[i+4]) + && cisxdigit(str[i+5])) { + memcpy(esc->s + n, str + i, 6); + n += 5; + i += 5; + continue; + } + } /* fall thru */ + case '"': + escape = str[i]; + break; + default: + if ((unsigned)str[i] < ' ' || str[i] == 127) { + snprintf(esc->s + n, 7, "\\u%04X", str[i]); + n += 5; + continue; + } + } + if (escape) { + esc->s[n++] = '\\'; + esc->s[n] = escape; + } else + esc->s[n] = str[i]; + } + + esc->s[n] = '\0'; + if (taken(str)) + tal_free(str); + return esc; +} + +struct json_escape *json_partial_escape(const tal_t *ctx, const char *str TAKES) +{ + return escape(ctx, str, strlen(str), true); +} + +struct json_escape *json_escape(const tal_t *ctx, const char *str TAKES) +{ + return escape(ctx, str, strlen(str), false); +} + +struct json_escape *json_escape_len(const tal_t *ctx, const char *str TAKES, + size_t len) +{ + return escape(ctx, str, len, false); +} + +/* By policy, we don't handle \u. Use UTF-8. */ +const char *json_escape_unescape(const tal_t *ctx, const struct json_escape *esc) +{ + char *unesc = tal_arr(ctx, char, strlen(esc->s) + 1); + size_t i, n; + + for (i = n = 0; esc->s[i]; i++, n++) { + if (esc->s[i] != '\\') { + unesc[n] = esc->s[i]; + continue; + } + + i++; + switch (esc->s[i]) { + case 'n': + unesc[n] = '\n'; + break; + case 'b': + unesc[n] = '\b'; + break; + case 'f': + unesc[n] = '\f'; + break; + case 't': + unesc[n] = '\t'; + break; + case 'r': + unesc[n] = '\r'; + break; + case '/': + case '\\': + case '"': + unesc[n] = esc->s[i]; + break; + default: + return tal_free(unesc); + } + } + + unesc[n] = '\0'; + return unesc; +}