diff options
Diffstat (limited to 'src/basic/escape.c')
-rw-r--r-- | src/basic/escape.c | 58 |
1 files changed, 23 insertions, 35 deletions
diff --git a/src/basic/escape.c b/src/basic/escape.c index 42a84c9317..5661f36813 100644 --- a/src/basic/escape.c +++ b/src/basic/escape.c @@ -19,12 +19,15 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <errno.h> +#include <stdlib.h> +#include <string.h> + #include "alloc-util.h" #include "escape.h" #include "hexdecoct.h" -#include "string-util.h" +#include "macro.h" #include "utf8.h" -#include "util.h" size_t cescape_char(char c, char *buf) { char * buf_old = buf; @@ -116,16 +119,18 @@ char *cescape(const char *s) { return cescape_length(s, strlen(s)); } -int cunescape_one(const char *p, size_t length, char *ret, uint32_t *ret_unicode) { +int cunescape_one(const char *p, size_t length, uint32_t *ret, bool *eight_bit) { int r = 1; assert(p); assert(*p); assert(ret); - /* Unescapes C style. Returns the unescaped character in ret, - * unless we encountered a \u sequence in which case the full - * unicode character is returned in ret_unicode, instead. */ + /* Unescapes C style. Returns the unescaped character in ret. + * Sets *eight_bit to true if the escaped sequence either fits in + * one byte in UTF-8 or is a non-unicode literal byte and should + * instead be copied directly. + */ if (length != (size_t) -1 && length < 1) return -EINVAL; @@ -187,7 +192,8 @@ int cunescape_one(const char *p, size_t length, char *ret, uint32_t *ret_unicode if (a == 0 && b == 0) return -EINVAL; - *ret = (char) ((a << 4U) | b); + *ret = (a << 4U) | b; + *eight_bit = true; r = 3; break; } @@ -214,16 +220,7 @@ int cunescape_one(const char *p, size_t length, char *ret, uint32_t *ret_unicode if (c == 0) return -EINVAL; - if (c < 128) - *ret = c; - else { - if (!ret_unicode) - return -EINVAL; - - *ret = 0; - *ret_unicode = c; - } - + *ret = c; r = 5; break; } @@ -255,16 +252,7 @@ int cunescape_one(const char *p, size_t length, char *ret, uint32_t *ret_unicode if (!unichar_is_valid(c)) return -EINVAL; - if (c < 128) - *ret = c; - else { - if (!ret_unicode) - return -EINVAL; - - *ret = 0; - *ret_unicode = c; - } - + *ret = c; r = 9; break; } @@ -306,6 +294,7 @@ int cunescape_one(const char *p, size_t length, char *ret, uint32_t *ret_unicode return -EINVAL; *ret = m; + *eight_bit = true; r = 3; break; } @@ -339,7 +328,7 @@ int cunescape_length_with_prefix(const char *s, size_t length, const char *prefi for (f = s, t = r + pl; f < s + length; f++) { size_t remaining; uint32_t u; - char c; + bool eight_bit = false; int k; remaining = s + length - f; @@ -362,7 +351,7 @@ int cunescape_length_with_prefix(const char *s, size_t length, const char *prefi return -EINVAL; } - k = cunescape_one(f + 1, remaining - 1, &c, &u); + k = cunescape_one(f + 1, remaining - 1, &u, &eight_bit); if (k < 0) { if (flags & UNESCAPE_RELAX) { /* Invalid escape code, let's take it literal then */ @@ -374,14 +363,13 @@ int cunescape_length_with_prefix(const char *s, size_t length, const char *prefi return k; } - if (c != 0) - /* Non-Unicode? Let's encode this directly */ - *(t++) = c; + f += k; + if (eight_bit) + /* One byte? Set directly as specified */ + *(t++) = u; else - /* Unicode? Then let's encode this in UTF-8 */ + /* Otherwise encode as multi-byte UTF-8 */ t += utf8_encode_unichar(t, u); - - f += k; } *t = 0; |