2 * Copyright (c) 2011 Bryan O'Sullivan <bos@serpentine.com>.
4 * Portions copyright (c) 2008-2010 Björn Höhrmann <bjoern@hoehrmann.de>.
6 * See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details.
12#include "text_cbits.h"
14void _hs_text_memcpy(void *dest, size_t doff, const void *src, size_t soff,
17 memcpy(dest + (doff<<1), src + (soff<<1), n<<1);
20int _hs_text_memcmp(const void *a, size_t aoff, const void *b, size_t boff,
23 return memcmp(a + (aoff<<1), b + (boff<<1), n<<1);
29static const uint8_t utf8d[] = {
31 * The first part of the table maps bytes to character classes that
32 * to reduce the size of the transition table and create bitmasks.
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 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,
38 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,
39 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,
40 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,
41 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,
44 * The second part is a transition table that maps a combination of
45 * a state of the automaton and a character class to a state.
47 0,12,24,36,60,96,84,12,12,12,48,72, 12,12,12,12,12,12,12,12,12,12,12,12,
48 12, 0,12,12,12,12,12, 0,12, 0,12,12, 12,24,12,12,12,12,12,24,12,24,12,12,
49 12,12,12,12,12,12,12,24,12,12,12,12, 12,24,12,12,12,12,12,12,12,24,12,12,
50 12,12,12,12,12,12,12,36,12,36,12,12, 12,36,12,12,12,12,12,36,12,36,12,12,
51 12,36,12,12,12,12,12,12,12,12,12,12,
55decode(uint32_t *state, uint32_t* codep, uint32_t byte) {
56 uint32_t type = utf8d[byte];
58 *codep = (*state != UTF8_ACCEPT) ?
59 (byte & 0x3fu) | (*codep << 6) :
60 (0xff >> type) & (byte);
62 return *state = utf8d[256 + *state + type];
66 * The ISO 8859-1 (aka latin-1) code points correspond exactly to the first 256 unicode
67 * code-points, therefore we can trivially convert from a latin-1 encoded bytestring to
71_hs_text_decode_latin1(uint16_t *dest, const uint8_t const *src,
72 const uint8_t const *srcend)
74 const uint8_t *p = src;
76#if defined(__i386__) || defined(__x86_64__)
77 /* This optimization works on a little-endian systems by using
78 (aligned) 32-bit loads instead of 8-bit loads
81 /* consume unaligned prefix */
82 while (p != srcend && (uintptr_t)p & 0x3)
85 /* iterate over 32-bit aligned loads */
86 while (p < srcend - 3) {
87 const uint32_t w = *((const uint32_t *)p);
90 *dest++ = (w >> 8) & 0xff;
91 *dest++ = (w >> 16) & 0xff;
92 *dest++ = (w >> 24) & 0xff;
98 /* handle unaligned suffix */
104 * A best-effort decoder. Runs until it hits either end of input or
105 * the start of an invalid byte sequence.
107 * At exit, we update *destoff with the next offset to write to, *src
108 * with the next source location past the last one successfully
109 * decoded, and return the next source location to read from.
111 * Moreover, we expose the internal decoder state (state0 and
112 * codepoint0), allowing one to restart the decoder after it
113 * terminates (say, due to a partial codepoint).
115 * In particular, there are a few possible outcomes,
117 * 1) We decoded the buffer entirely:
118 * In this case we return srcend
119 * state0 == UTF8_ACCEPT
121 * 2) We met an invalid encoding
122 * In this case we return the address of the first invalid byte
123 * state0 == UTF8_REJECT
125 * 3) We reached the end of the buffer while decoding a codepoint
126 * In this case we return a pointer to the first byte of the partial codepoint
127 * state0 != UTF8_ACCEPT, UTF8_REJECT
131_hs_text_decode_utf8_state(uint16_t *const dest, size_t *destoff,
132 const uint8_t **const src,
133 const uint8_t *const srcend,
134 uint32_t *codepoint0, uint32_t *state0)
136 uint16_t *d = dest + *destoff;
137 const uint8_t *s = *src, *last = *src;
138 uint32_t state = *state0;
139 uint32_t codepoint = *codepoint0;
142#if defined(__i386__) || defined(__x86_64__)
144 * This code will only work on a little-endian system that
145 * supports unaligned loads.
147 * It gives a substantial speed win on data that is purely or
148 * partly ASCII (e.g. HTML), at only a slight cost on purely
152 if (state == UTF8_ACCEPT) {
153 while (s < srcend - 4) {
154 codepoint = *((uint32_t *) s);
155 if ((codepoint & 0x80808080) != 0)
160 * Tried 32-bit stores here, but the extra bit-twiddling
161 * slowed the code down.
164 *d++ = (uint16_t) (codepoint & 0xff);
165 *d++ = (uint16_t) ((codepoint >> 8) & 0xff);
166 *d++ = (uint16_t) ((codepoint >> 16) & 0xff);
167 *d++ = (uint16_t) ((codepoint >> 24) & 0xff);
173 if (decode(&state, &codepoint, *s++) != UTF8_ACCEPT) {
174 if (state != UTF8_REJECT)
179 if (codepoint <= 0xffff)
180 *d++ = (uint16_t) codepoint;
182 *d++ = (uint16_t) (0xD7C0 + (codepoint >> 10));
183 *d++ = (uint16_t) (0xDC00 + (codepoint & 0x3FF));
188 /* Invalid encoding, back up to the errant character */
189 if (state == UTF8_REJECT)
193 *codepoint0 = codepoint;
201 * Helper to decode buffer and discard final decoder state
204_hs_text_decode_utf8(uint16_t *const dest, size_t *destoff,
205 const uint8_t *src, const uint8_t *const srcend)
208 uint32_t state = UTF8_ACCEPT;
209 return _hs_text_decode_utf8_state(dest, destoff, &src, srcend, &codepoint, &state);
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list