1 /*
2  * This code was written by Rich Felker in 2010; no copyright is claimed.
3  * This code is in the public domain. Attribution is appreciated but
4  * unnecessary.
5  */
6 
7 #include <stdint.h>
8 #include <wchar.h>
9 #include <errno.h>
10 #include "internal.h"
11 
mbsrtowcs(wchar_t * restrict ws,const char ** restrict src,size_t wn,mbstate_t * restrict st)12 size_t mbsrtowcs(wchar_t *restrict ws, const char **restrict src, size_t wn, mbstate_t *restrict st)
13 {
14 	const unsigned char *s = (const void *)*src;
15 	size_t wn0 = wn;
16 	unsigned c = 0;
17 
18 	if (st && (c = *(unsigned *)st)) {
19 		if (ws) {
20 			*(unsigned *)st = 0;
21 			goto resume;
22 		} else {
23 			goto resume0;
24 		}
25 	}
26 
27 	if (!ws) for (;;) {
28 		if (*s-1u < 0x7f && (uintptr_t)s%4 == 0) {
29 			while (!(( *(uint32_t*)s | *(uint32_t*)s-0x01010101) & 0x80808080)) {
30 				s += 4;
31 				wn -= 4;
32 			}
33 		}
34 		if (*s-1u < 0x7f) {
35 			s++;
36 			wn--;
37 			continue;
38 		}
39 		if (*s-SA > SB-SA) break;
40 		c = bittab[*s++-SA];
41 resume0:
42 		if (OOB(c,*s)) { s--; break; }
43 		s++;
44 		if (c&(1U<<25)) {
45 			if (*s-0x80u >= 0x40) { s-=2; break; }
46 			s++;
47 			if (c&(1U<<19)) {
48 				if (*s-0x80u >= 0x40) { s-=3; break; }
49 				s++;
50 			}
51 		}
52 		wn--;
53 		c = 0;
54 	} else for (;;) {
55 		if (!wn) {
56 			*src = (const void *)s;
57 			return wn0;
58 		}
59 		if (*s-1u < 0x7f && (uintptr_t)s%4 == 0) {
60 			while (wn>=5 && !(( *(uint32_t*)s | *(uint32_t*)s-0x01010101) & 0x80808080)) {
61 				*ws++ = *s++;
62 				*ws++ = *s++;
63 				*ws++ = *s++;
64 				*ws++ = *s++;
65 				wn -= 4;
66 			}
67 		}
68 		if (*s-1u < 0x7f) {
69 			*ws++ = *s++;
70 			wn--;
71 			continue;
72 		}
73 		if (*s-SA > SB-SA) break;
74 		c = bittab[*s++-SA];
75 resume:
76 		if (OOB(c,*s)) { s--; break; }
77 		c = (c<<6) | *s++-0x80;
78 		if (c&(1U<<31)) {
79 			if (*s-0x80u >= 0x40) { s-=2; break; }
80 			c = (c<<6) | *s++-0x80;
81 			if (c&(1U<<31)) {
82 				if (*s-0x80u >= 0x40) { s-=3; break; }
83 				c = (c<<6) | *s++-0x80;
84 			}
85 		}
86 		*ws++ = c;
87 		wn--;
88 		c = 0;
89 	}
90 
91 	if (!c && !*s) {
92 		if (ws) {
93 			*ws = 0;
94 			*src = 0;
95 		}
96 		return wn0-wn;
97 	}
98 	errno = EILSEQ;
99 	if (ws) *src = (const void *)s;
100 	return -1;
101 }
102