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