| 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 | |
| 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 | #ifdef __GNUC__ |
| 42 | 		typedef uint32_t __attribute__((__may_alias__)) w32; |
| 43 | 		if (*s-1u < 0x7f && (uintptr_t)s%4 == 0) { |
| 44 | 			while (!(( *(w32*)s | *(w32*)s-0x01010101) & 0x80808080)) { |
| 45 | 				s += 4; |
| 46 | 				wn -= 4; |
| 47 | 			} |
| 48 | 		} |
| 49 | #endif |
| 50 | 		if (*s-1u < 0x7f) { |
| 51 | 			s++; |
| 52 | 			wn--; |
| 53 | 			continue; |
| 54 | 		} |
| 55 | 		if (*s-SA > SB-SA) break; |
| 56 | 		c = bittab[*s++-SA]; |
| 57 | resume0: |
| 58 | 		if (OOB(c,*s)) { s--; break; } |
| 59 | 		s++; |
| 60 | 		if (c&(1U<<25)) { |
| 61 | 			if (*s-0x80u >= 0x40) { s-=2; break; } |
| 62 | 			s++; |
| 63 | 			if (c&(1U<<19)) { |
| 64 | 				if (*s-0x80u >= 0x40) { s-=3; break; } |
| 65 | 				s++; |
| 66 | 			} |
| 67 | 		} |
| 68 | 		wn--; |
| 69 | 		c = 0; |
| 70 | 	} else for (;;) { |
| 71 | 		if (!wn) { |
| 72 | 			*src = (const void *)s; |
| 73 | 			return wn0; |
| 74 | 		} |
| 75 | #ifdef __GNUC__ |
| 76 | 		typedef uint32_t __attribute__((__may_alias__)) w32; |
| 77 | 		if (*s-1u < 0x7f && (uintptr_t)s%4 == 0) { |
| 78 | 			while (wn>=5 && !(( *(w32*)s | *(w32*)s-0x01010101) & 0x80808080)) { |
| 79 | 				*ws++ = *s++; |
| 80 | 				*ws++ = *s++; |
| 81 | 				*ws++ = *s++; |
| 82 | 				*ws++ = *s++; |
| 83 | 				wn -= 4; |
| 84 | 			} |
| 85 | 		} |
| 86 | #endif |
| 87 | 		if (*s-1u < 0x7f) { |
| 88 | 			*ws++ = *s++; |
| 89 | 			wn--; |
| 90 | 			continue; |
| 91 | 		} |
| 92 | 		if (*s-SA > SB-SA) break; |
| 93 | 		c = bittab[*s++-SA]; |
| 94 | resume: |
| 95 | 		if (OOB(c,*s)) { s--; break; } |
| 96 | 		c = (c<<6) | *s++-0x80; |
| 97 | 		if (c&(1U<<31)) { |
| 98 | 			if (*s-0x80u >= 0x40) { s-=2; break; } |
| 99 | 			c = (c<<6) | *s++-0x80; |
| 100 | 			if (c&(1U<<31)) { |
| 101 | 				if (*s-0x80u >= 0x40) { s-=3; break; } |
| 102 | 				c = (c<<6) | *s++-0x80; |
| 103 | 			} |
| 104 | 		} |
| 105 | 		*ws++ = c; |
| 106 | 		wn--; |
| 107 | 		c = 0; |
| 108 | 	} |
| 109 | |
| 110 | 	if (!c && !*s) { |
| 111 | 		if (ws) { |
| 112 | 			*ws = 0; |
| 113 | 			*src = 0; |
| 114 | 		} |
| 115 | 		return wn0-wn; |
| 116 | 	} |
| 117 | 	errno = EILSEQ; |
| 118 | 	if (ws) *src = (const void *)s; |
| 119 | 	return -1; |
| 120 | } |