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