X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fshared%2Futf8.c;h=6e5ba9abf4ad115b9fcc2d3e78fbef6e65664815;hb=0371ca0dac1d70b2e5060a3c4e6fbbc2bdbd8671;hp=1a68394a53cee3d58d06a8dc08f114f9dcb1a1ff;hpb=02a36bc9a1769c744f141f127898dbe076dbfd96;p=elogind.git diff --git a/src/shared/utf8.c b/src/shared/utf8.c index 1a68394a5..6e5ba9abf 100644 --- a/src/shared/utf8.c +++ b/src/shared/utf8.c @@ -3,6 +3,7 @@ /*** This file is part of systemd. + Copyright 2008-2011 Kay Sievers Copyright 2012 Lennart Poettering systemd is free software; you can redistribute it and/or modify it @@ -19,7 +20,7 @@ along with systemd; If not, see . ***/ -/* This file is based on the GLIB utf8 validation functions. The +/* Parts of this file are based on the GLIB utf8 validation functions. The * original license text follows. */ /* gutf8.c - Operations on UTF-8 strings. @@ -51,8 +52,6 @@ #include "utf8.h" #include "util.h" -#define FILTER_CHAR '_' - static inline bool is_unicode_valid(uint32_t ch) { if (ch >= 0x110000) /* End of unicode space */ @@ -67,17 +66,6 @@ static inline bool is_unicode_valid(uint32_t ch) { return true; } -static inline bool is_continuation_char(uint8_t ch) { - if ((ch & 0xc0) != 0x80) /* 10xxxxxx */ - return false; - return true; -} - -static inline void merge_continuation_char(uint32_t *u_ch, uint8_t ch) { - *u_ch <<= 6; - *u_ch |= ch & 0x3f; -} - static bool is_unicode_control(uint32_t ch) { /* @@ -90,163 +78,100 @@ static bool is_unicode_control(uint32_t ch) { (0x7F <= ch && ch <= 0x9F); } -bool utf8_is_printable(const char* str, size_t length) { - uint32_t val = 0; - uint32_t min = 0; - const uint8_t *p; +/* count of characters used to encode one unicode char */ +static int utf8_encoded_expected_len(const char *str) { + unsigned char c = (unsigned char)str[0]; - assert(str); + if (c < 0x80) + return 1; + if ((c & 0xe0) == 0xc0) + return 2; + if ((c & 0xf0) == 0xe0) + return 3; + if ((c & 0xf8) == 0xf0) + return 4; + if ((c & 0xfc) == 0xf8) + return 5; + if ((c & 0xfe) == 0xfc) + return 6; + return 0; +} - for (p = (const uint8_t*) str; length; p++, length--) { - if (*p < 128) { - val = *p; - } else { - if ((*p & 0xe0) == 0xc0) { /* 110xxxxx two-char seq. */ - min = 128; - val = (uint32_t) (*p & 0x1e); - goto ONE_REMAINING; - } else if ((*p & 0xf0) == 0xe0) { /* 1110xxxx three-char seq.*/ - min = (1 << 11); - val = (uint32_t) (*p & 0x0f); - goto TWO_REMAINING; - } else if ((*p & 0xf8) == 0xf0) { /* 11110xxx four-char seq */ - min = (1 << 16); - val = (uint32_t) (*p & 0x07); - } else - return false; - - p++; - length--; - if (!length || !is_continuation_char(*p)) - return false; - merge_continuation_char(&val, *p); - - TWO_REMAINING: - p++; - length--; - if (!is_continuation_char(*p)) - return false; - merge_continuation_char(&val, *p); - - ONE_REMAINING: - p++; - length--; - if (!is_continuation_char(*p)) - return false; - merge_continuation_char(&val, *p); - - if (val < min) - return false; - } +/* decode one unicode char */ +int utf8_encoded_to_unichar(const char *str) { + int unichar; + int len; + int i; - if (is_unicode_control(val)) - return false; + len = utf8_encoded_expected_len(str); + switch (len) { + case 1: + return (int)str[0]; + case 2: + unichar = str[0] & 0x1f; + break; + case 3: + unichar = (int)str[0] & 0x0f; + break; + case 4: + unichar = (int)str[0] & 0x07; + break; + case 5: + unichar = (int)str[0] & 0x03; + break; + case 6: + unichar = (int)str[0] & 0x01; + break; + default: + return -1; } - return true; + for (i = 1; i < len; i++) { + if (((int)str[i] & 0xc0) != 0x80) + return -1; + unichar <<= 6; + unichar |= (int)str[i] & 0x3f; + } + + return unichar; } -static char* utf8_validate(const char *str, char *output) { - uint32_t val = 0; - uint32_t min = 0; - const uint8_t *p, *last; - int size; - uint8_t *o; +bool utf8_is_printable(const char* str, size_t length) { + const uint8_t *p; assert(str); - o = (uint8_t*) output; - for (p = (const uint8_t*) str; *p; p++) { - if (*p < 128) { - if (o) - *o = *p; - } else { - last = p; - - if ((*p & 0xe0) == 0xc0) { /* 110xxxxx two-char seq. */ - size = 2; - min = 128; - val = (uint32_t) (*p & 0x1e); - goto ONE_REMAINING; - } else if ((*p & 0xf0) == 0xe0) { /* 1110xxxx three-char seq.*/ - size = 3; - min = (1 << 11); - val = (uint32_t) (*p & 0x0f); - goto TWO_REMAINING; - } else if ((*p & 0xf8) == 0xf0) { /* 11110xxx four-char seq */ - size = 4; - min = (1 << 16); - val = (uint32_t) (*p & 0x07); - } else - goto error; - - p++; - if (!is_continuation_char(*p)) - goto error; - merge_continuation_char(&val, *p); - - TWO_REMAINING: - p++; - if (!is_continuation_char(*p)) - goto error; - merge_continuation_char(&val, *p); - - ONE_REMAINING: - p++; - if (!is_continuation_char(*p)) - goto error; - merge_continuation_char(&val, *p); - - if (val < min) - goto error; - - if (!is_unicode_valid(val)) - goto error; - - if (o) { - memcpy(o, last, (size_t) size); - o += size; - } - - continue; - - error: - if (o) { - *o = FILTER_CHAR; - p = last; /* We retry at the next character */ - } else - goto failure; - } + for (p = (const uint8_t*) str; length;) { + int encoded_len = utf8_encoded_valid_unichar((const char *)p); + int val = utf8_encoded_to_unichar((const char*)p); - if (o) - o++; - } + if (encoded_len < 0 || val < 0 || is_unicode_control(val)) + return false; - if (o) { - *o = '\0'; - return output; + length -= encoded_len; + p += encoded_len; } - return (char*) str; - -failure: - return NULL; -} - -char* utf8_is_valid (const char *str) { - return utf8_validate(str, NULL); + return true; } -char* utf8_filter (const char *str) { - char *new_str; +const char *utf8_is_valid(const char *str) { + const uint8_t *p; assert(str); - new_str = malloc(strlen(str) + 1); - if (!new_str) - return NULL; + for (p = (const uint8_t*) str; *p; ) { + int len; + + len = utf8_encoded_valid_unichar((const char *)p); + + if (len < 0) + return NULL; + + p += len; + } - return utf8_validate(str, new_str); + return str; } char *ascii_is_valid(const char *str) { @@ -261,27 +186,6 @@ char *ascii_is_valid(const char *str) { return (char*) str; } -char *ascii_filter(const char *str) { - const char *s; - char *r, *d; - size_t l; - - assert(str); - - l = strlen(str); - r = malloc(l + 1); - if (!r) - return NULL; - - for (s = str, d = r; *s; s++) - if ((unsigned char) *s < 128) - *(d++) = *s; - - *d = 0; - - return r; -} - char *utf16_to_utf8(const void *s, size_t length) { char *r; const uint8_t *f; @@ -318,64 +222,6 @@ char *utf16_to_utf8(const void *s, size_t length) { return r; } -/* count of characters used to encode one unicode char */ -static int utf8_encoded_expected_len(const char *str) { - unsigned char c = (unsigned char)str[0]; - - if (c < 0x80) - return 1; - if ((c & 0xe0) == 0xc0) - return 2; - if ((c & 0xf0) == 0xe0) - return 3; - if ((c & 0xf8) == 0xf0) - return 4; - if ((c & 0xfc) == 0xf8) - return 5; - if ((c & 0xfe) == 0xfc) - return 6; - return 0; -} - -/* decode one unicode char */ -static int utf8_encoded_to_unichar(const char *str) { - int unichar; - int len; - int i; - - len = utf8_encoded_expected_len(str); - switch (len) { - case 1: - return (int)str[0]; - case 2: - unichar = str[0] & 0x1f; - break; - case 3: - unichar = (int)str[0] & 0x0f; - break; - case 4: - unichar = (int)str[0] & 0x07; - break; - case 5: - unichar = (int)str[0] & 0x03; - break; - case 6: - unichar = (int)str[0] & 0x01; - break; - default: - return -1; - } - - for (i = 1; i < len; i++) { - if (((int)str[i] & 0xc0) != 0x80) - return -1; - unichar <<= 6; - unichar |= (int)str[i] & 0x3f; - } - - return unichar; -} - /* expected size used to encode one unicode char */ static int utf8_unichar_to_encoded_len(int unichar) { if (unichar < 0x80) @@ -422,49 +268,3 @@ int utf8_encoded_valid_unichar(const char *str) { return len; } - -int is_utf8_encoding_whitelisted(char c, const char *white) { - if ((c >= '0' && c <= '9') || - (c >= 'A' && c <= 'Z') || - (c >= 'a' && c <= 'z') || - strchr("#+-.:=@_", c) != NULL || - (white != NULL && strchr(white, c) != NULL)) - return 1; - return 0; -} - -int udev_encode_string(const char *str, char *str_enc, size_t len) { - size_t i, j; - - if (str == NULL || str_enc == NULL) - return -1; - - for (i = 0, j = 0; str[i] != '\0'; i++) { - int seqlen; - - seqlen = utf8_encoded_valid_unichar(&str[i]); - if (seqlen > 1) { - if (len-j < (size_t)seqlen) - goto err; - memcpy(&str_enc[j], &str[i], seqlen); - j += seqlen; - i += (seqlen-1); - } else if (str[i] == '\\' || !is_utf8_encoding_whitelisted(str[i], NULL)) { - if (len-j < 4) - goto err; - sprintf(&str_enc[j], "\\x%02x", (unsigned char) str[i]); - j += 4; - } else { - if (len-j < 1) - goto err; - str_enc[j] = str[i]; - j++; - } - } - if (len-j < 1) - goto err; - str_enc[j] = '\0'; - return 0; -err: - return -1; -}