mbsrtowcs.c 2.1 KB

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