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