Index: trunk/src/VBox/Runtime/common/string/utf-16.cpp
===================================================================
--- trunk/src/VBox/Runtime/common/string/utf-16.cpp	(revision 67334)
+++ trunk/src/VBox/Runtime/common/string/utf-16.cpp	(revision 67391)
@@ -375,4 +375,6 @@
  * @param   cwc         The max length of the UTF-16 string to consider.
  * @param   pcch        Where to store the length (excluding '\\0') of the UTF-8 string. (cch == cb, btw)
+ *
+ * @note    rtUtf16BigCalcUtf8Length is a copy of this.
  */
 static int rtUtf16CalcUtf8Length(PCRTUTF16 pwsz, size_t cwc, size_t *pcch)
@@ -385,5 +387,5 @@
         if (!wc)
             break;
-        else if (wc < 0xd800 || wc > 0xdfff)
+        if (wc < 0xd800 || wc > 0xdfff)
         {
             if (wc < 0x80)
@@ -433,4 +435,74 @@
 
 /**
+ * Validate the UTF-16BE encoding and calculates the length of an UTF-8
+ * encoding.
+ *
+ * @returns iprt status code.
+ * @param   pwsz        The UTF-16 string.
+ * @param   cwc         The max length of the UTF-16BE string to consider.
+ * @param   pcch        Where to store the length (excluding '\\0') of the UTF-8 string. (cch == cb, btw)
+ *
+ * @note    Code is a copy of rtUtf16CalcUtf8Length, but with two RT_BE2H_U16
+ *          invocations inserted.
+ */
+static int rtUtf16BigCalcUtf8Length(PCRTUTF16 pwsz, size_t cwc, size_t *pcch)
+{
+    int     rc = VINF_SUCCESS;
+    size_t  cch = 0;
+    while (cwc > 0)
+    {
+        RTUTF16 wc = *pwsz++; cwc--;
+        if (!wc)
+            break;
+        wc = RT_BE2H_U16(wc);
+        if (wc < 0xd800 || wc > 0xdfff)
+        {
+            if (wc < 0x80)
+                cch++;
+            else if (wc < 0x800)
+                cch += 2;
+            else if (wc < 0xfffe)
+                cch += 3;
+            else
+            {
+                RTStrAssertMsgFailed(("endian indicator! wc=%#x\n", wc));
+                rc = VERR_CODE_POINT_ENDIAN_INDICATOR;
+                break;
+            }
+        }
+        else
+        {
+            if (wc >= 0xdc00)
+            {
+                RTStrAssertMsgFailed(("Wrong 1st char in surrogate! wc=%#x\n", wc));
+                rc = VERR_INVALID_UTF16_ENCODING;
+                break;
+            }
+            if (cwc <= 0)
+            {
+                RTStrAssertMsgFailed(("Invalid length! wc=%#x\n", wc));
+                rc = VERR_INVALID_UTF16_ENCODING;
+                break;
+            }
+            wc = *pwsz++; cwc--;
+            wc = RT_BE2H_U16(wc);
+            if (wc < 0xdc00 || wc > 0xdfff)
+            {
+                RTStrAssertMsgFailed(("Wrong 2nd char in surrogate! wc=%#x\n", wc));
+                rc = VERR_INVALID_UTF16_ENCODING;
+                break;
+            }
+            cch += 4;
+        }
+    }
+
+
+    /* done */
+    *pcch = cch;
+    return rc;
+}
+
+
+/**
  * Recodes an valid UTF-16 string as UTF-8.
  *
@@ -442,4 +514,5 @@
  * @param   cch         The size of the UTF-8 buffer, excluding the terminator.
  * @param   pcch        Where to store the number of octets actually encoded.
+ * @note    rtUtf16BigRecodeAsUtf8 is a copy of this.
  */
 static int rtUtf16RecodeAsUtf8(PCRTUTF16 pwsz, size_t cwc, char *psz, size_t cch, size_t *pcch)
@@ -452,5 +525,5 @@
         if (!wc)
             break;
-        else if (wc < 0xd800 || wc > 0xdfff)
+        if (wc < 0xd800 || wc > 0xdfff)
         {
             if (wc < 0x80)
@@ -542,4 +615,119 @@
 
 
+/**
+ * Recodes an valid UTF-16BE string as UTF-8.
+ *
+ * @returns iprt status code.
+ * @param   pwsz        The UTF-16BE string.
+ * @param   cwc         The number of RTUTF16 characters to process from pwsz. The recoding
+ *                      will stop when cwc or '\\0' is reached.
+ * @param   psz         Where to store the UTF-8 string.
+ * @param   cch         The size of the UTF-8 buffer, excluding the terminator.
+ * @param   pcch        Where to store the number of octets actually encoded.
+ *
+ * @note    Copy of rtUtf16RecodeAsUtf8 with a few RT_BE2H_U16 invocations
+ *          insterted.
+ */
+static int rtUtf16BigRecodeAsUtf8(PCRTUTF16 pwsz, size_t cwc, char *psz, size_t cch, size_t *pcch)
+{
+    unsigned char  *pwch = (unsigned char *)psz;
+    int             rc = VINF_SUCCESS;
+    while (cwc > 0)
+    {
+        RTUTF16 wc = *pwsz++; cwc--;
+        if (!wc)
+            break;
+        wc = RT_BE2H_U16(wc);
+        if (wc < 0xd800 || wc > 0xdfff)
+        {
+            if (wc < 0x80)
+            {
+                if (RT_UNLIKELY(cch < 1))
+                {
+                    RTStrAssertMsgFailed(("Buffer overflow! 1\n"));
+                    rc = VERR_BUFFER_OVERFLOW;
+                    break;
+                }
+                cch--;
+                *pwch++ = (unsigned char)wc;
+            }
+            else if (wc < 0x800)
+            {
+                if (RT_UNLIKELY(cch < 2))
+                {
+                    RTStrAssertMsgFailed(("Buffer overflow! 2\n"));
+                    rc = VERR_BUFFER_OVERFLOW;
+                    break;
+                }
+                cch -= 2;
+                *pwch++ = 0xc0 | (wc >> 6);
+                *pwch++ = 0x80 | (wc & 0x3f);
+            }
+            else if (wc < 0xfffe)
+            {
+                if (RT_UNLIKELY(cch < 3))
+                {
+                    RTStrAssertMsgFailed(("Buffer overflow! 3\n"));
+                    rc = VERR_BUFFER_OVERFLOW;
+                    break;
+                }
+                cch -= 3;
+                *pwch++ = 0xe0 | (wc >> 12);
+                *pwch++ = 0x80 | ((wc >> 6) & 0x3f);
+                *pwch++ = 0x80 | (wc & 0x3f);
+            }
+            else
+            {
+                RTStrAssertMsgFailed(("endian indicator! wc=%#x\n", wc));
+                rc = VERR_CODE_POINT_ENDIAN_INDICATOR;
+                break;
+            }
+        }
+        else
+        {
+            if (wc >= 0xdc00)
+            {
+                RTStrAssertMsgFailed(("Wrong 1st char in surrogate! wc=%#x\n", wc));
+                rc = VERR_INVALID_UTF16_ENCODING;
+                break;
+            }
+            if (cwc <= 0)
+            {
+                RTStrAssertMsgFailed(("Invalid length! wc=%#x\n", wc));
+                rc = VERR_INVALID_UTF16_ENCODING;
+                break;
+            }
+            RTUTF16 wc2 = *pwsz++; cwc--;
+            wc2 = RT_BE2H_U16(wc2);
+            if (wc2 < 0xdc00 || wc2 > 0xdfff)
+            {
+                RTStrAssertMsgFailed(("Wrong 2nd char in surrogate! wc=%#x\n", wc));
+                rc = VERR_INVALID_UTF16_ENCODING;
+                break;
+            }
+            uint32_t CodePoint = 0x10000
+                               + (  ((wc & 0x3ff) << 10)
+                                  | (wc2 & 0x3ff));
+            if (RT_UNLIKELY(cch < 4))
+            {
+                RTStrAssertMsgFailed(("Buffer overflow! 4\n"));
+                rc = VERR_BUFFER_OVERFLOW;
+                break;
+            }
+            cch -= 4;
+            *pwch++ = 0xf0 | (CodePoint >> 18);
+            *pwch++ = 0x80 | ((CodePoint >> 12) & 0x3f);
+            *pwch++ = 0x80 | ((CodePoint >>  6) & 0x3f);
+            *pwch++ = 0x80 | (CodePoint & 0x3f);
+        }
+    }
+
+    /* done */
+    *pwch = '\0';
+    *pcch = (char *)pwch - psz;
+    return rc;
+}
+
+
 
 RTDECL(int)  RTUtf16ToUtf8Tag(PCRTUTF16 pwszString, char **ppszString, const char *pszTag)
@@ -582,4 +770,43 @@
 
 
+RTDECL(int)  RTUtf16BigToUtf8Tag(PCRTUTF16 pwszString, char **ppszString, const char *pszTag)
+{
+    /*
+     * Validate input.
+     */
+    Assert(VALID_PTR(ppszString));
+    Assert(VALID_PTR(pwszString));
+    *ppszString = NULL;
+
+    /*
+     * Validate the UTF-16 string and calculate the length of the UTF-8 encoding of it.
+     */
+    size_t cch;
+    int rc = rtUtf16BigCalcUtf8Length(pwszString, RTSTR_MAX, &cch);
+    if (RT_SUCCESS(rc))
+    {
+        /*
+         * Allocate buffer and recode it.
+         */
+        char *pszResult = (char *)RTMemAllocTag(cch + 1, pszTag);
+        if (pszResult)
+        {
+            rc = rtUtf16BigRecodeAsUtf8(pwszString, RTSTR_MAX, pszResult, cch, &cch);
+            if (RT_SUCCESS(rc))
+            {
+                *ppszString = pszResult;
+                return rc;
+            }
+
+            RTMemFree(pszResult);
+        }
+        else
+            rc = VERR_NO_STR_MEMORY;
+    }
+    return rc;
+}
+RT_EXPORT_SYMBOL(RTUtf16BigToUtf8Tag);
+
+
 RTDECL(int)  RTUtf16ToUtf8ExTag(PCRTUTF16 pwszString, size_t cwcString, char **ppsz, size_t cch, size_t *pcch, const char *pszTag)
 {
@@ -587,7 +814,7 @@
      * Validate input.
      */
-    Assert(VALID_PTR(pwszString));
-    Assert(VALID_PTR(ppsz));
-    Assert(!pcch || VALID_PTR(pcch));
+    AssertPtr(pwszString);
+    AssertPtr(ppsz);
+    AssertPtrNull(pcch);
 
     /*
@@ -640,4 +867,62 @@
 
 
+RTDECL(int)  RTUtf16BigToUtf8ExTag(PCRTUTF16 pwszString, size_t cwcString, char **ppsz, size_t cch, size_t *pcch, const char *pszTag)
+{
+    /*
+     * Validate input.
+     */
+    AssertPtr(pwszString);
+    AssertPtr(ppsz);
+    AssertPtrNull(pcch);
+
+    /*
+     * Validate the UTF-16BE string and calculate the length of the UTF-8 encoding of it.
+     */
+    size_t cchResult;
+    int rc = rtUtf16BigCalcUtf8Length(pwszString, cwcString, &cchResult);
+    if (RT_SUCCESS(rc))
+    {
+        if (pcch)
+            *pcch = cchResult;
+
+        /*
+         * Check buffer size / Allocate buffer and recode it.
+         */
+        bool fShouldFree;
+        char *pszResult;
+        if (cch > 0 && *ppsz)
+        {
+            fShouldFree = false;
+            if (RT_UNLIKELY(cch <= cchResult))
+                return VERR_BUFFER_OVERFLOW;
+            pszResult = *ppsz;
+        }
+        else
+        {
+            *ppsz = NULL;
+            fShouldFree = true;
+            cch = RT_MAX(cch, cchResult + 1);
+            pszResult = (char *)RTStrAllocTag(cch, pszTag);
+        }
+        if (pszResult)
+        {
+            rc = rtUtf16BigRecodeAsUtf8(pwszString, cwcString, pszResult, cch - 1, &cch);
+            if (RT_SUCCESS(rc))
+            {
+                *ppsz = pszResult;
+                return rc;
+            }
+
+            if (fShouldFree)
+                RTStrFree(pszResult);
+        }
+        else
+            rc = VERR_NO_STR_MEMORY;
+    }
+    return rc;
+}
+RT_EXPORT_SYMBOL(RTUtf16BigToUtf8ExTag);
+
+
 RTDECL(size_t) RTUtf16CalcUtf8Len(PCRTUTF16 pwsz)
 {
