Module: wine Branch: master Commit: 27f0426b6f3189ef20a6a2d5ef09688a0dd64c61 URL: https://source.winehq.org/git/wine.git/?a=commit;h=27f0426b6f3189ef20a6a2d5e...
Author: Alexandre Julliard julliard@winehq.org Date: Tue Dec 3 10:10:47 2019 +0100
ntdll: Implement RtlUTF8ToUnicodeN.
Signed-off-by: Alexandre Julliard julliard@winehq.org
---
dlls/ntdll/locale.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++ dlls/ntdll/ntdll.spec | 1 + include/winternl.h | 1 + 3 files changed, 116 insertions(+)
diff --git a/dlls/ntdll/locale.c b/dlls/ntdll/locale.c index 09f64b8dad..d7a6401560 100644 --- a/dlls/ntdll/locale.c +++ b/dlls/ntdll/locale.c @@ -1307,6 +1307,120 @@ found: }
+/* helper for the various utf8 mbstowcs functions */ +static unsigned int decode_utf8_char( unsigned char ch, const char **str, const char *strend ) +{ + /* number of following bytes in sequence based on first byte value (for bytes above 0x7f) */ + static const char utf8_length[128] = + { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x80-0x8f */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x90-0x9f */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xa0-0xaf */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xb0-0xbf */ + 0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 0xc0-0xcf */ + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 0xd0-0xdf */ + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, /* 0xe0-0xef */ + 3,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0 /* 0xf0-0xff */ + }; + + /* first byte mask depending on UTF-8 sequence length */ + static const unsigned char utf8_mask[4] = { 0x7f, 0x1f, 0x0f, 0x07 }; + + unsigned int len = utf8_length[ch - 0x80]; + unsigned int res = ch & utf8_mask[len]; + const char *end = *str + len; + + if (end > strend) + { + *str = end; + return ~0; + } + switch (len) + { + case 3: + if ((ch = end[-3] ^ 0x80) >= 0x40) break; + res = (res << 6) | ch; + (*str)++; + if (res < 0x10) break; + case 2: + if ((ch = end[-2] ^ 0x80) >= 0x40) break; + res = (res << 6) | ch; + if (res >= 0x110000 >> 6) break; + (*str)++; + if (res < 0x20) break; + if (res >= 0xd800 >> 6 && res <= 0xdfff >> 6) break; + case 1: + if ((ch = end[-1] ^ 0x80) >= 0x40) break; + res = (res << 6) | ch; + (*str)++; + if (res < 0x80) break; + return res; + } + return ~0; +} + + +/************************************************************************** + * RtlUTF8ToUnicodeN (NTDLL.@) + */ +NTSTATUS WINAPI RtlUTF8ToUnicodeN( WCHAR *dst, DWORD dstlen, DWORD *reslen, const char *src, DWORD srclen ) +{ + unsigned int res, len; + NTSTATUS status = STATUS_SUCCESS; + const char *srcend = src + srclen; + WCHAR *dstend; + + if (!src) return STATUS_INVALID_PARAMETER_4; + if (!reslen) return STATUS_INVALID_PARAMETER; + + dstlen /= sizeof(WCHAR); + dstend = dst + dstlen; + if (!dst) + { + for (len = 0; src < srcend; len++) + { + unsigned char ch = *src++; + if (ch < 0x80) continue; + if ((res = decode_utf8_char( ch, &src, srcend )) > 0x10ffff) + status = STATUS_SOME_NOT_MAPPED; + else + if (res > 0xffff) len++; + } + *reslen = len * sizeof(WCHAR); + return status; + } + + while ((dst < dstend) && (src < srcend)) + { + unsigned char ch = *src++; + if (ch < 0x80) /* special fast case for 7-bit ASCII */ + { + *dst++ = ch; + continue; + } + if ((res = decode_utf8_char( ch, &src, srcend )) <= 0xffff) + { + *dst++ = res; + } + else if (res <= 0x10ffff) /* we need surrogates */ + { + res -= 0x10000; + *dst++ = 0xd800 | (res >> 10); + if (dst == dstend) break; + *dst++ = 0xdc00 | (res & 0x3ff); + } + else + { + *dst++ = 0xfffd; + status = STATUS_SOME_NOT_MAPPED; + } + } + if (src < srcend) status = STATUS_BUFFER_TOO_SMALL; /* overflow */ + *reslen = (dstlen - (dstend - dst)) * sizeof(WCHAR); + return status; +} + + /* get the next char value taking surrogates into account */ static inline unsigned int get_surrogate_value( const WCHAR *src, unsigned int srclen ) { diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index 566f51c8d1..415a43ab53 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -981,6 +981,7 @@ @ stdcall RtlTryAcquireSRWLockExclusive(ptr) @ stdcall RtlTryAcquireSRWLockShared(ptr) @ stdcall RtlTryEnterCriticalSection(ptr) +@ stdcall RtlUTF8ToUnicodeN(ptr long ptr ptr long) @ cdecl -i386 -norelay RtlUlongByteSwap() NTDLL_RtlUlongByteSwap @ cdecl -ret64 RtlUlonglongByteSwap(int64) # @ stub RtlUnhandledExceptionFilter2 diff --git a/include/winternl.h b/include/winternl.h index ea46087aac..9e7e2bad93 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -2902,6 +2902,7 @@ NTSYSAPI BOOLEAN WINAPI RtlTimeToSecondsSince1980(const LARGE_INTEGER *,LPDWOR NTSYSAPI BOOLEAN WINAPI RtlTryAcquireSRWLockExclusive(RTL_SRWLOCK *); NTSYSAPI BOOLEAN WINAPI RtlTryAcquireSRWLockShared(RTL_SRWLOCK *); NTSYSAPI BOOL WINAPI RtlTryEnterCriticalSection(RTL_CRITICAL_SECTION *); +NTSYSAPI NTSTATUS WINAPI RtlUTF8ToUnicodeN(WCHAR*,DWORD,DWORD*,const char*,DWORD); NTSYSAPI ULONGLONG __cdecl RtlUlonglongByteSwap(ULONGLONG); NTSYSAPI DWORD WINAPI RtlUnicodeStringToAnsiSize(const UNICODE_STRING*); NTSYSAPI NTSTATUS WINAPI RtlUnicodeStringToAnsiString(PANSI_STRING,PCUNICODE_STRING,BOOLEAN);