Alexandre Julliard : ntdll: Implement RtlUTF8ToUnicodeN.
Alexandre Julliard
julliard at winehq.org
Wed Dec 4 16:13:04 CST 2019
Module: wine
Branch: master
Commit: 27f0426b6f3189ef20a6a2d5ef09688a0dd64c61
URL: https://source.winehq.org/git/wine.git/?a=commit;h=27f0426b6f3189ef20a6a2d5ef09688a0dd64c61
Author: Alexandre Julliard <julliard at winehq.org>
Date: Tue Dec 3 10:10:47 2019 +0100
ntdll: Implement RtlUTF8ToUnicodeN.
Signed-off-by: Alexandre Julliard <julliard at 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);
More information about the wine-cvs
mailing list