diff options
Diffstat (limited to 'src/common/utf8.c')
| -rw-r--r-- | src/common/utf8.c | 39 |
1 files changed, 31 insertions, 8 deletions
diff --git a/src/common/utf8.c b/src/common/utf8.c index 089fd89..1d4cf13 100644 --- a/src/common/utf8.c +++ b/src/common/utf8.c @@ -3,30 +3,46 @@ #include <stdbool.h> #include <stdint.h> +#ifndef likely +#define likely(x) __builtin_expect(!!(x), 1) +#endif +#ifndef unlikely +#define unlikely(x) __builtin_expect(!!(x), 0) +#endif + bool yasl_utf8_validate(const char *str, size_t len) { const unsigned char *p = (const unsigned char *)str; const unsigned char *end = p + len; while (p < end) { - if (*p < 0x80) { + while (p + 8 <= end) { + uint64_t v; + memcpy(&v, p, 8); + if (v & 0x8080808080808080ull) + break; + p += 8; + } + if (p >= end) break; + + if (likely(*p < 0x80)) { p++; } else if ((*p & 0xe0) == 0xc0) { - if (p + 1 >= end || (p[1] & 0xc0) != 0x80 || (*p & 0x1e) == 0) + if (unlikely(p + 1 >= end || (p[1] & 0xc0) != 0x80 || (*p & 0x1e) == 0)) return false; p += 2; } else if ((*p & 0xf0) == 0xe0) { - if (p + 2 >= end || (p[1] & 0xc0) != 0x80 || (p[2] & 0xc0) != 0x80) + if (unlikely(p + 2 >= end || (p[1] & 0xc0) != 0x80 || (p[2] & 0xc0) != 0x80)) return false; uint32_t cp = ((p[0] & 0x0f) << 12) | ((p[1] & 0x3f) << 6) | (p[2] & 0x3f); - if (cp < 0x800 || (cp >= 0xd800 && cp <= 0xdfff)) + if (unlikely(cp < 0x800 || (cp >= 0xd800 && cp <= 0xdfff))) return false; p += 3; } else if ((*p & 0xf8) == 0xf0) { - if (p + 3 >= end || (p[1] & 0xc0) != 0x80 || (p[2] & 0xc0) != 0x80 || (p[3] & 0xc0) != 0x80) + if (unlikely(p + 3 >= end || (p[1] & 0xc0) != 0x80 || (p[2] & 0xc0) != 0x80 || (p[3] & 0xc0) != 0x80)) return false; uint32_t cp = ((p[0] & 0x07) << 18) | ((p[1] & 0x3f) << 12) | ((p[2] & 0x3f) << 6) | (p[3] & 0x3f); - if (cp < 0x10000 || cp > 0x10ffff) + if (unlikely(cp < 0x10000 || cp > 0x10ffff)) return false; p += 4; } else { @@ -38,10 +54,17 @@ bool yasl_utf8_validate(const char *str, size_t len) char *yasl_utf8_sanitize_dup(const char *str) { - if (!str) return NULL; + if (unlikely(!str)) return NULL; size_t len = strlen(str); + if (likely(yasl_utf8_validate(str, len))) { + char *out = malloc(len + 1); + if (unlikely(!out)) return NULL; + memcpy(out, str, len + 1); + return out; + } + char *out = malloc(len + 1); - if (!out) return NULL; + if (unlikely(!out)) return NULL; const unsigned char *p = (const unsigned char *)str; size_t o = 0; |
