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