| 3051 | } |
| 3052 | |
| 3053 | int xutftowcsn(wchar_t *wcs, const char *utfs, size_t wcslen, int utflen) |
| 3054 | { |
| 3055 | int upos = 0, wpos = 0; |
| 3056 | const unsigned char *utf = (const unsigned char*) utfs; |
| 3057 | if (!utf || !wcs || wcslen < 1) { |
| 3058 | errno = EINVAL; |
| 3059 | return -1; |
| 3060 | } |
| 3061 | /* reserve space for \0 */ |
| 3062 | wcslen--; |
| 3063 | if (utflen < 0) |
| 3064 | utflen = INT_MAX; |
| 3065 | |
| 3066 | while (upos < utflen) { |
| 3067 | int c = utf[upos++] & 0xff; |
| 3068 | if (utflen == INT_MAX && c == 0) |
| 3069 | break; |
| 3070 | |
| 3071 | if (wpos >= wcslen) { |
| 3072 | wcs[wpos] = 0; |
| 3073 | errno = ERANGE; |
| 3074 | return -1; |
| 3075 | } |
| 3076 | |
| 3077 | if (c < 0x80) { |
| 3078 | /* ASCII */ |
| 3079 | wcs[wpos++] = c; |
| 3080 | } else if (c >= 0xc2 && c < 0xe0 && upos < utflen && |
| 3081 | (utf[upos] & 0xc0) == 0x80) { |
| 3082 | /* 2-byte utf-8 */ |
| 3083 | c = ((c & 0x1f) << 6); |
| 3084 | c |= (utf[upos++] & 0x3f); |
| 3085 | wcs[wpos++] = c; |
| 3086 | } else if (c >= 0xe0 && c < 0xf0 && upos + 1 < utflen && |
| 3087 | !(c == 0xe0 && utf[upos] < 0xa0) && /* over-long encoding */ |
| 3088 | (utf[upos] & 0xc0) == 0x80 && |
| 3089 | (utf[upos + 1] & 0xc0) == 0x80) { |
| 3090 | /* 3-byte utf-8 */ |
| 3091 | c = ((c & 0x0f) << 12); |
| 3092 | c |= ((utf[upos++] & 0x3f) << 6); |
| 3093 | c |= (utf[upos++] & 0x3f); |
| 3094 | wcs[wpos++] = c; |
| 3095 | } else if (c >= 0xf0 && c < 0xf5 && upos + 2 < utflen && |
| 3096 | wpos + 1 < wcslen && |
| 3097 | !(c == 0xf0 && utf[upos] < 0x90) && /* over-long encoding */ |
| 3098 | !(c == 0xf4 && utf[upos] >= 0x90) && /* > \u10ffff */ |
| 3099 | (utf[upos] & 0xc0) == 0x80 && |
| 3100 | (utf[upos + 1] & 0xc0) == 0x80 && |
| 3101 | (utf[upos + 2] & 0xc0) == 0x80) { |
| 3102 | /* 4-byte utf-8: convert to \ud8xx \udcxx surrogate pair */ |
| 3103 | c = ((c & 0x07) << 18); |
| 3104 | c |= ((utf[upos++] & 0x3f) << 12); |
| 3105 | c |= ((utf[upos++] & 0x3f) << 6); |
| 3106 | c |= (utf[upos++] & 0x3f); |
| 3107 | c -= 0x10000; |
| 3108 | wcs[wpos++] = 0xd800 | (c >> 10); |
| 3109 | wcs[wpos++] = 0xdc00 | (c & 0x3ff); |
| 3110 | } else if (c >= 0xa0) { |
no outgoing calls
no test coverage detected