Index: trunk/src/VBox/Runtime/common/string/utf-16.cpp
===================================================================
--- trunk/src/VBox/Runtime/common/string/utf-16.cpp	(revision 68154)
+++ trunk/src/VBox/Runtime/common/string/utf-16.cpp	(revision 68316)
@@ -369,14 +369,15 @@
 
 /**
- * Validate the UTF-16 encoding and calculates the length of an UTF-8 encoding.
+ * 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-16 string to consider.
+ * @param   pwsz        The UTF-16BE 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    rtUtf16BigCalcUtf8Length is a copy of this.
+ * @note    rtUtf16LittleCalcUtf8Length | s/RT_LE2H_U16/RT_BE2H_U16/g
  */
-static int rtUtf16CalcUtf8Length(PCRTUTF16 pwsz, size_t cwc, size_t *pcch)
+static int rtUtf16BigCalcUtf8Length(PCRTUTF16 pwsz, size_t cwc, size_t *pcch)
 {
     int     rc = VINF_SUCCESS;
@@ -387,4 +388,5 @@
         if (!wc)
             break;
+        wc = RT_BE2H_U16(wc);
         if (wc < 0xd800 || wc > 0xdfff)
         {
@@ -417,4 +419,5 @@
             }
             wc = *pwsz++; cwc--;
+            wc = RT_BE2H_U16(wc);
             if (wc < 0xdc00 || wc > 0xdfff)
             {
@@ -435,16 +438,15 @@
 
 /**
- * Validate the UTF-16BE encoding and calculates the length of an UTF-8
+ * Validate the UTF-16LE 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   pwsz        The UTF-16LE string.
+ * @param   cwc         The max length of the UTF-16LE 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.
+ * @note    rtUtf16BigCalcUtf8Length | s/RT_BE2H_U16/RT_LE2H_U16/g
  */
-static int rtUtf16BigCalcUtf8Length(PCRTUTF16 pwsz, size_t cwc, size_t *pcch)
+static int rtUtf16LittleCalcUtf8Length(PCRTUTF16 pwsz, size_t cwc, size_t *pcch)
 {
     int     rc = VINF_SUCCESS;
@@ -455,5 +457,5 @@
         if (!wc)
             break;
-        wc = RT_BE2H_U16(wc);
+        wc = RT_LE2H_U16(wc);
         if (wc < 0xd800 || wc > 0xdfff)
         {
@@ -486,5 +488,5 @@
             }
             wc = *pwsz++; cwc--;
-            wc = RT_BE2H_U16(wc);
+            wc = RT_LE2H_U16(wc);
             if (wc < 0xdc00 || wc > 0xdfff)
             {
@@ -500,115 +502,4 @@
     /* done */
     *pcch = cch;
-    return rc;
-}
-
-
-/**
- * Recodes an valid UTF-16 string as UTF-8.
- *
- * @returns iprt status code.
- * @param   pwsz        The UTF-16 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    rtUtf16BigRecodeAsUtf8 is a copy of this.
- */
-static int rtUtf16RecodeAsUtf8(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;
-        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--;
-            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;
 }
@@ -626,6 +517,5 @@
  * @param   pcch        Where to store the number of octets actually encoded.
  *
- * @note    Copy of rtUtf16RecodeAsUtf8 with a few RT_BE2H_U16 invocations
- *          insterted.
+ * @note    rtUtf16LittleRecodeAsUtf8 == s/RT_BE2H_U16/RT_LE2H_U16/g
  */
 static int rtUtf16BigRecodeAsUtf8(PCRTUTF16 pwsz, size_t cwc, char *psz, size_t cch, size_t *pcch)
@@ -730,4 +620,118 @@
 
 
+/**
+ * Recodes an valid UTF-16LE string as UTF-8.
+ *
+ * @returns iprt status code.
+ * @param   pwsz        The UTF-16LE 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    rtUtf16LittleRecodeAsUtf8 == s/RT_LE2H_U16/RT_GE2H_U16/g
+ */
+static int rtUtf16LittleRecodeAsUtf8(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_LE2H_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_LE2H_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)
@@ -744,5 +748,9 @@
      */
     size_t cch;
-    int rc = rtUtf16CalcUtf8Length(pwszString, RTSTR_MAX, &cch);
+#ifdef RT_BIG_ENDIAN
+    int rc = rtUtf16BigCalcUtf8Length(pwszString, RTSTR_MAX, &cch);
+#else
+    int rc = rtUtf16LittleCalcUtf8Length(pwszString, RTSTR_MAX, &cch);
+#endif
     if (RT_SUCCESS(rc))
     {
@@ -753,5 +761,9 @@
         if (pszResult)
         {
-            rc = rtUtf16RecodeAsUtf8(pwszString, RTSTR_MAX, pszResult, cch, &cch);
+#ifdef RT_BIG_ENDIAN
+            rc = rtUtf16BigRecodeAsUtf8(pwszString, RTSTR_MAX, pszResult, cch, &cch);
+#else
+            rc = rtUtf16LittleRecodeAsUtf8(pwszString, RTSTR_MAX, pszResult, cch, &cch);
+#endif
             if (RT_SUCCESS(rc))
             {
@@ -809,4 +821,43 @@
 
 
+RTDECL(int)  RTUtf16LittleToUtf8Tag(PCRTUTF16 pwszString, char **ppszString, const char *pszTag)
+{
+    /*
+     * Validate input.
+     */
+    Assert(VALID_PTR(ppszString));
+    Assert(VALID_PTR(pwszString));
+    *ppszString = NULL;
+
+    /*
+     * Validate the UTF-16LE string and calculate the length of the UTF-8 encoding of it.
+     */
+    size_t cch;
+    int rc = rtUtf16LittleCalcUtf8Length(pwszString, RTSTR_MAX, &cch);
+    if (RT_SUCCESS(rc))
+    {
+        /*
+         * Allocate buffer and recode it.
+         */
+        char *pszResult = (char *)RTMemAllocTag(cch + 1, pszTag);
+        if (pszResult)
+        {
+            rc = rtUtf16LittleRecodeAsUtf8(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)
 {
@@ -822,5 +873,9 @@
      */
     size_t cchResult;
-    int rc = rtUtf16CalcUtf8Length(pwszString, cwcString, &cchResult);
+#ifdef RT_BIG_ENDIAN
+    int rc = rtUtf16BigCalcUtf8Length(pwszString, cwcString, &cchResult);
+#else
+    int rc = rtUtf16LittleCalcUtf8Length(pwszString, cwcString, &cchResult);
+#endif
     if (RT_SUCCESS(rc))
     {
@@ -849,5 +904,9 @@
         if (pszResult)
         {
-            rc = rtUtf16RecodeAsUtf8(pwszString, cwcString, pszResult, cch - 1, &cch);
+#ifdef RT_BIG_ENDIAN
+            rc = rtUtf16BigRecodeAsUtf8(pwszString, cwcString, pszResult, cch - 1, &cch);
+#else
+            rc = rtUtf16LittleRecodeAsUtf8(pwszString, cwcString, pszResult, cch - 1, &cch);
+#endif
             if (RT_SUCCESS(rc))
             {
@@ -925,8 +984,71 @@
 
 
+RTDECL(int)  RTUtf16LittleToUtf8ExTag(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-16LE string and calculate the length of the UTF-8 encoding of it.
+     */
+    size_t cchResult;
+    int rc = rtUtf16LittleCalcUtf8Length(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 = rtUtf16LittleRecodeAsUtf8(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)
 {
     size_t cch;
-    int rc = rtUtf16CalcUtf8Length(pwsz, RTSTR_MAX, &cch);
+#ifdef RT_BIG_ENDIAN
+    int rc = rtUtf16BigCalcUtf8Length(pwsz, RTSTR_MAX, &cch);
+#else
+    int rc = rtUtf16LittleCalcUtf8Length(pwsz, RTSTR_MAX, &cch);
+#endif
     return RT_SUCCESS(rc) ? cch : 0;
 }
@@ -934,8 +1056,30 @@
 
 
+RTDECL(size_t) RTUtf16BigCalcUtf8Len(PCRTUTF16 pwsz)
+{
+    size_t cch;
+    int rc = rtUtf16BigCalcUtf8Length(pwsz, RTSTR_MAX, &cch);
+    return RT_SUCCESS(rc) ? cch : 0;
+}
+RT_EXPORT_SYMBOL(RTUtf16BigCalcUtf8Len);
+
+
+RTDECL(size_t) RTUtf16LittleCalcUtf8Len(PCRTUTF16 pwsz)
+{
+    size_t cch;
+    int rc = rtUtf16LittleCalcUtf8Length(pwsz, RTSTR_MAX, &cch);
+    return RT_SUCCESS(rc) ? cch : 0;
+}
+RT_EXPORT_SYMBOL(RTUtf16LittleCalcUtf8Len);
+
+
 RTDECL(int) RTUtf16CalcUtf8LenEx(PCRTUTF16 pwsz, size_t cwc, size_t *pcch)
 {
     size_t cch;
-    int rc = rtUtf16CalcUtf8Length(pwsz, cwc, &cch);
+#ifdef RT_BIG_ENDIAN
+    int rc = rtUtf16BigCalcUtf8Length(pwsz, cwc, &cch);
+#else
+    int rc = rtUtf16LittleCalcUtf8Length(pwsz, cwc, &cch);
+#endif
     if (pcch)
         *pcch = RT_SUCCESS(rc) ? cch : ~(size_t)0;
@@ -943,4 +1087,26 @@
 }
 RT_EXPORT_SYMBOL(RTUtf16CalcUtf8LenEx);
+
+
+RTDECL(int) RTUtf16BigCalcUtf8LenEx(PCRTUTF16 pwsz, size_t cwc, size_t *pcch)
+{
+    size_t cch;
+    int rc = rtUtf16BigCalcUtf8Length(pwsz, cwc, &cch);
+    if (pcch)
+        *pcch = RT_SUCCESS(rc) ? cch : ~(size_t)0;
+    return rc;
+}
+RT_EXPORT_SYMBOL(RTUtf16BigCalcUtf8LenEx);
+
+
+RTDECL(int) RTUtf16LittleCalcUtf8LenEx(PCRTUTF16 pwsz, size_t cwc, size_t *pcch)
+{
+    size_t cch;
+    int rc = rtUtf16LittleCalcUtf8Length(pwsz, cwc, &cch);
+    if (pcch)
+        *pcch = RT_SUCCESS(rc) ? cch : ~(size_t)0;
+    return rc;
+}
+RT_EXPORT_SYMBOL(RTUtf16LittleCalcUtf8LenEx);
 
 
