[1/2] ntdll: Implement RtlUnicodeToUTF8N.

Thomas Faber thomas.faber at reactos.org
Thu May 21 18:37:00 CDT 2015


From 32b6d2c64ef3be489ca0d2ab3b380f3565479ffb Mon Sep 17 00:00:00 2001
From: Thomas Faber <thomas.faber at reactos.org>
Date: Thu, 21 May 2015 12:48:41 -0400
Subject: ntdll: Implement RtlUnicodeToUTF8N.

---
 dlls/ntdll/ntdll.spec |    1 +
 dlls/ntdll/rtlstr.c   |  111 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 112 insertions(+), 0 deletions(-)

diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec
index 6d86157..316f875 100644
--- a/dlls/ntdll/ntdll.spec
+++ b/dlls/ntdll/ntdll.spec
@@ -915,6 +915,7 @@
 @ stdcall RtlUnicodeToMultiByteN(ptr long ptr ptr long)
 @ stdcall RtlUnicodeToMultiByteSize(ptr ptr long)
 @ stdcall RtlUnicodeToOemN(ptr long ptr ptr long)
+@ stdcall RtlUnicodeToUTF8N(ptr long ptr ptr long)
 @ stdcall RtlUniform(ptr)
 # @ stub RtlUnlockBootStatusData
 @ stdcall RtlUnlockHeap(long)
diff --git a/dlls/ntdll/rtlstr.c b/dlls/ntdll/rtlstr.c
index 01b4446..5286b81 100644
--- a/dlls/ntdll/rtlstr.c
+++ b/dlls/ntdll/rtlstr.c
@@ -2163,3 +2163,114 @@ NTSTATUS WINAPI RtlHashUnicodeString(PCUNICODE_STRING string, BOOLEAN case_insen
 
     return STATUS_SUCCESS;
 }
+
+/******************************************************************************
+ * RtlUnicodeToUTF8N [NTDLL.@]
+ */
+NTSTATUS WINAPI RtlUnicodeToUTF8N(CHAR *utf8_dest, ULONG utf8_bytes_max,
+                                  ULONG *utf8_bytes_written,
+                                  const WCHAR *uni_src, ULONG uni_bytes)
+{
+    NTSTATUS status;
+    ULONG i;
+    ULONG written;
+    ULONG ch;
+    BYTE utf8_ch[4];
+    ULONG utf8_ch_len;
+
+    if (!uni_src)
+        return STATUS_INVALID_PARAMETER_4;
+    if (!utf8_bytes_written)
+        return STATUS_INVALID_PARAMETER;
+    if (utf8_dest && uni_bytes % sizeof(WCHAR))
+        return STATUS_INVALID_PARAMETER_5;
+
+    written = 0;
+    status = STATUS_SUCCESS;
+
+    for (i = 0; i < uni_bytes / sizeof(WCHAR); i++)
+    {
+        /* decode UTF-16 into ch */
+        ch = uni_src[i];
+        if (ch >= 0xdc00 && ch <= 0xdfff)
+        {
+            ch = 0xfffd;
+            status = STATUS_SOME_NOT_MAPPED;
+        }
+        else if (ch >= 0xd800 && ch <= 0xdbff)
+        {
+            if (i + 1 < uni_bytes / sizeof(WCHAR))
+            {
+                ch -= 0xd800;
+                ch <<= 10;
+                if (uni_src[i + 1] >= 0xdc00 && uni_src[i + 1] <= 0xdfff)
+                {
+                    ch |= uni_src[i + 1] - 0xdc00;
+                    ch += 0x010000;
+                    i++;
+                }
+                else
+                {
+                    ch = 0xfffd;
+                    status = STATUS_SOME_NOT_MAPPED;
+                }
+            }
+            else
+            {
+                ch = 0xfffd;
+                status = STATUS_SOME_NOT_MAPPED;
+            }
+        }
+
+        /* encode ch as UTF-8 */
+        assert(ch <= 0x10ffff);
+        if (ch < 0x80)
+        {
+            utf8_ch[0] = ch & 0x7f;
+            utf8_ch_len = 1;
+        }
+        else if (ch < 0x800)
+        {
+            utf8_ch[0] = 0xc0 | (ch >>  6 & 0x1f);
+            utf8_ch[1] = 0x80 | (ch >>  0 & 0x3f);
+            utf8_ch_len = 2;
+        }
+        else if (ch < 0x10000)
+        {
+            utf8_ch[0] = 0xe0 | (ch >> 12 & 0x0f);
+            utf8_ch[1] = 0x80 | (ch >>  6 & 0x3f);
+            utf8_ch[2] = 0x80 | (ch >>  0 & 0x3f);
+            utf8_ch_len = 3;
+        }
+        else if (ch < 0x200000)
+        {
+            utf8_ch[0] = 0xf0 | (ch >> 18 & 0x07);
+            utf8_ch[1] = 0x80 | (ch >> 12 & 0x3f);
+            utf8_ch[2] = 0x80 | (ch >>  6 & 0x3f);
+            utf8_ch[3] = 0x80 | (ch >>  0 & 0x3f);
+            utf8_ch_len = 4;
+        }
+
+        if (!utf8_dest)
+        {
+            written += utf8_ch_len;
+            continue;
+        }
+
+        if (utf8_bytes_max >= utf8_ch_len)
+        {
+            memcpy(utf8_dest, utf8_ch, utf8_ch_len);
+            utf8_dest += utf8_ch_len;
+            utf8_bytes_max -= utf8_ch_len;
+            written += utf8_ch_len;
+        }
+        else
+        {
+            utf8_bytes_max = 0;
+            status = STATUS_BUFFER_TOO_SMALL;
+        }
+    }
+
+    *utf8_bytes_written = written;
+    return status;
+}
-- 
1.7.1



More information about the wine-patches mailing list