@@ -1,4 +1,14 @@
1+/*
2+ * Copyright (c) 2011 Bryan O'Sullivan <bos@serpentine.com>.
3+ *
4+ * Portions copyright (c) 2008-2010 Björn Höhrmann <bjoern@hoehrmann.de>.
5+ *
6+ * See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details.
7+ */
8+
19#include <string.h>
10+#include <stdint.h>
11+#include <stdio.h>
212
313void _hs_text_memcpy(void *dest, size_t doff, const void *src, size_t soff,
414 size_t n)
@@ -11,3 +21,113 @@ int _hs_text_memcmp(const void *a, size_t aoff, const void *b, size_t boff,
1121{
1222 return memcmp(a + (aoff<<1), b + (boff<<1), n<<1);
1323}
24+
25+#define UTF8_ACCEPT 0
26+#define UTF8_REJECT 12
27+
28+static const uint8_t utf8d[] = {
29+ /*
30+ * The first part of the table maps bytes to character classes that
31+ * to reduce the size of the transition table and create bitmasks.
32+ */
33+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
34+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
35+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
36+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
37+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
38+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
39+ 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
40+ 10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8,
41+
42+ /*
43+ * The second part is a transition table that maps a combination of
44+ * a state of the automaton and a character class to a state.
45+ */
46+ 0,12,24,36,60,96,84,12,12,12,48,72, 12,12,12,12,12,12,12,12,12,12,12,12,
47+ 12, 0,12,12,12,12,12, 0,12, 0,12,12, 12,24,12,12,12,12,12,24,12,24,12,12,
48+ 12,12,12,12,12,12,12,24,12,12,12,12, 12,24,12,12,12,12,12,12,12,24,12,12,
49+ 12,12,12,12,12,12,12,36,12,36,12,12, 12,36,12,12,12,12,12,36,12,36,12,12,
50+ 12,36,12,12,12,12,12,12,12,12,12,12,
51+};
52+
53+static inline uint32_t
54+decode(uint32_t *state, uint32_t* codep, uint32_t byte) {
55+ uint32_t type = utf8d[byte];
56+
57+ *codep = (*state != UTF8_ACCEPT) ?
58+ (byte & 0x3fu) | (*codep << 6) :
59+ (0xff >> type) & (byte);
60+
61+ return *state = utf8d[256 + *state + type];
62+}
63+
64+/*
65+ * A best-effort decoder. Runs until it hits either end of input or
66+ * the start of an invalid byte sequence.
67+ *
68+ * At exit, updates *destoff with the next offset to write to, and
69+ * returns the next source offset to read from.
70+ */
71+uint8_t const *
72+_hs_text_decode_utf8(uint16_t *dest, size_t *destoff,
73+ const uint8_t const *src, const uint8_t const *srcend)
74+{
75+ uint16_t *d = dest + *destoff;
76+ const uint8_t const *s = src;
77+ uint32_t state = UTF8_ACCEPT;
78+
79+ while (s < srcend) {
80+ uint32_t codepoint;
81+
82+#if defined(__i386__) || defined(__x86_64__)
83+ /*
84+ * This code will only work on a little-endian system that
85+ * supports unaligned loads.
86+ *
87+ * It gives a substantial speed win on data that is purely or
88+ * partly ASCII (e.g. HTML), at only a slight cost on purely
89+ * non-ASCII text.
90+ */
91+
92+ if (state == UTF8_ACCEPT) {
93+ while (s < srcend - 4) {
94+ codepoint = *((uint32_t *) s);
95+ if ((codepoint & 0x80808080) != 0)
96+ break;
97+ s += 4;
98+
99+ /*
100+ * Tried 32-bit stores here, but the extra bit-twiddling
101+ * slowed the code down.
102+ */
103+
104+ *d++ = (uint16_t) (codepoint & 0xff);
105+ *d++ = (uint16_t) ((codepoint >> 8) & 0xff);
106+ *d++ = (uint16_t) ((codepoint >> 16) & 0xff);
107+ *d++ = (uint16_t) ((codepoint >> 24) & 0xff);
108+ }
109+ }
110+#endif
111+
112+ if (decode(&state, &codepoint, *s++) != UTF8_ACCEPT) {
113+ if (state != UTF8_REJECT)
114+ continue;
115+ break;
116+ }
117+
118+ if (codepoint <= 0xffff)
119+ *d++ = (uint16_t) codepoint;
120+ else {
121+ *d++ = (uint16_t) (0xD7C0 + (codepoint >> 10));
122+ *d++ = (uint16_t) (0xDC00 + (codepoint & 0x3FF));
123+ }
124+ }
125+
126+ /* Error recovery - if we're not in a valid finishing state, back up. */
127+ if (state != UTF8_ACCEPT)
128+ s -= 1;
129+
130+ *destoff = d - dest;
131+
132+ return s;
133+}