summaryrefslogtreecommitdiff
path: root/src/common/utf8.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/utf8.c')
-rw-r--r--src/common/utf8.c39
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;