Index: /trunk/include/iprt/base64.h
===================================================================
--- /trunk/include/iprt/base64.h	(revision 84292)
+++ /trunk/include/iprt/base64.h	(revision 84293)
@@ -74,4 +74,16 @@
 
 /**
+ * Calculates the decoded data size for a Base64 encoded UTF-16 string.
+ *
+ * @returns The length in bytes. -1 if the encoding is bad.
+ *
+ * @param   pwszString      The Base64 encoded UTF-16 string.
+ * @param   ppwszEnd        If not NULL, this will point to the first char
+ *                          following the Base64 encoded text block. If
+ *                          NULL the entire string is assumed to be Base64.
+ */
+RTDECL(ssize_t) RTBase64DecodedUtf16Size(PCRTUTF16 pwszString, PRTUTF16 *ppwszEnd);
+
+/**
  * Calculates the decoded data size for a Base64 encoded string.
  *
@@ -87,4 +99,19 @@
  */
 RTDECL(ssize_t) RTBase64DecodedSizeEx(const char *pszString, size_t cchStringMax, char **ppszEnd);
+
+/**
+ * Calculates the decoded data size for a Base64 encoded UTF-16 string.
+ *
+ * @returns The length in bytes. -1 if the encoding is bad.
+ *
+ * @param   pwszString      The Base64 encoded UTF-16 string.
+ * @param   cwcStringMax    The max length to decode in RTUTF16 units, use
+ *                          RTSTR_MAX if the length of @a pwszString is not
+ *                          known and it is really zero terminated.
+ * @param   ppwszEnd        If not NULL, this will point to the first char
+ *                          following the Base64 encoded text block. If
+ *                          NULL the entire string is assumed to be Base64.
+ */
+RTDECL(ssize_t) RTBase64DecodedSizeUtf16Ex(PCRTUTF16 pwszString, size_t cwcStringMax, PRTUTF16 *ppwszEnd);
 
 /**
@@ -110,4 +137,28 @@
  */
 RTDECL(int) RTBase64Decode(const char *pszString, void *pvData, size_t cbData, size_t *pcbActual, char **ppszEnd);
+
+/**
+ * Decodes a Base64 encoded UTF-16 string into the buffer supplied by the
+ * caller.
+ *
+ * @returns IPRT status code.
+ * @retval  VERR_BUFFER_OVERFLOW if the buffer is too small. pcbActual will not
+ *          be set, nor will ppszEnd.
+ * @retval  VERR_INVALID_BASE64_ENCODING if the encoding is wrong.
+ *
+ * @param   pwszString      The Base64 UTF-16 string. Whether the entire string
+ *                          or just the start of the string is in Base64 depends
+ *                          on whether ppwszEnd is specified or not.
+ * @param   pvData          Where to store the decoded data.
+ * @param   cbData          The size of the output buffer that pvData points to.
+ * @param   pcbActual       Where to store the actual number of bytes returned.
+ *                          Optional.
+ * @param   ppwszEnd        Indicates that the string may contain other stuff
+ *                          after the Base64 encoded data when not NULL. Will
+ *                          be set to point to the first char that's not part of
+ *                          the encoding. If NULL the entire string must be part
+ *                          of the Base64 encoded data.
+ */
+RTDECL(int) RTBase64DecodeUtf16(PCRTUTF16 pwszString, void *pvData, size_t cbData, size_t *pcbActual, PRTUTF16 *ppwszEnd);
 
 /**
@@ -138,4 +189,32 @@
                              size_t *pcbActual, char **ppszEnd);
 
+/**
+ * Decodes a Base64 encoded UTF-16 string into the buffer supplied by the
+ * caller.
+ *
+ * @returns IPRT status code.
+ * @retval  VERR_BUFFER_OVERFLOW if the buffer is too small. pcbActual will not
+ *          be set, nor will ppszEnd.
+ * @retval  VERR_INVALID_BASE64_ENCODING if the encoding is wrong.
+ *
+ * @param   pwszString      The Base64 UTF-16 string. Whether the entire string
+ *                          or just the start of the string is in Base64 depends
+ *                          on whether ppszEnd is specified or not.
+ * @param   cwcStringMax    The max length to decode in RTUTF16 units, use
+ *                          RTSTR_MAX if the length of @a pwszString is not
+ *                          known and it is really zero terminated.
+ * @param   pvData          Where to store the decoded data.
+ * @param   cbData          The size of the output buffer that pvData points to.
+ * @param   pcbActual       Where to store the actual number of bytes returned.
+ *                          Optional.
+ * @param   ppwszEnd        Indicates that the string may contain other stuff
+ *                          after the Base64 encoded data when not NULL. Will
+ *                          be set to point to the first char that's not part of
+ *                          the encoding. If NULL the entire string must be part
+ *                          of the Base64 encoded data.
+ */
+RTDECL(int) RTBase64DecodeUtf16Ex(PCRTUTF16 pwszString, size_t cwcStringMax, void *pvData, size_t cbData,
+                                  size_t *pcbActual, PRTUTF16 *ppwszEnd);
+
 
 /**
Index: /trunk/include/iprt/mangling.h
===================================================================
--- /trunk/include/iprt/mangling.h	(revision 84292)
+++ /trunk/include/iprt/mangling.h	(revision 84293)
@@ -577,4 +577,8 @@
 # define RTBase64DecodedSize                            RT_MANGLER(RTBase64DecodedSize)
 # define RTBase64DecodedSizeEx                          RT_MANGLER(RTBase64DecodedSizeEx)
+# define RTBase64DecodeUtf16                            RT_MANGLER(RTBase64DecodeUtf16)
+# define RTBase64DecodeUtf16Ex                          RT_MANGLER(RTBase64DecodeUtf16Ex)
+# define RTBase64DecodedUtf16Size                       RT_MANGLER(RTBase64DecodedUtf16Size)
+# define RTBase64DecodedUtf16SizeEx                     RT_MANGLER(RTBase64DecodedUtf16SizeEx)
 # define RTBase64Encode                                 RT_MANGLER(RTBase64Encode)
 # define RTBase64EncodeEx                               RT_MANGLER(RTBase64EncodeEx)
Index: /trunk/src/VBox/Runtime/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Runtime/Makefile.kmk	(revision 84292)
+++ /trunk/src/VBox/Runtime/Makefile.kmk	(revision 84293)
@@ -609,4 +609,5 @@
 	common/string/RTUtf16PrintHexBytes.cpp \
 	common/string/base64.cpp \
+	common/string/base64-utf16.cpp \
 	common/string/simplepattern.cpp \
 	common/string/straprintf.cpp \
Index: /trunk/src/VBox/Runtime/common/string/base64-utf16.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/string/base64-utf16.cpp	(revision 84293)
+++ /trunk/src/VBox/Runtime/common/string/base64-utf16.cpp	(revision 84293)
@@ -0,0 +1,445 @@
+/* $Id$ */
+/** @file
+ * IPRT - Base64, MIME content transfer encoding.
+ *
+ * @note The base64.cpp file must be diffable with this one.
+ *       Fixed typically applies to both files.
+ */
+
+/*
+ * Copyright (C) 2009-2020 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+*   Header Files                                                                                                                 *
+*********************************************************************************************************************************/
+#include <iprt/base64.h>
+#include "internal/iprt.h"
+
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/string.h>
+#include <iprt/uni.h>
+#ifdef RT_STRICT
+# include <iprt/asm.h>
+#endif
+
+#include "base64.h"
+
+
+/** Translates the given character. */
+DECL_FORCE_INLINE(uint8_t) rtBase64TranslateUtf16(RTUTF16 wc)
+{
+    if (wc < RT_ELEMENTS(g_au8RTBase64CharToVal))
+        return g_au8RTBase64CharToVal[wc];
+    if (RTUniCpIsSpace(wc))
+        return BASE64_SPACE;
+    return BASE64_INVALID;
+}
+
+
+/** Fetched the next character in the string and translates it. */
+DECL_FORCE_INLINE(uint8_t) rtBase64TranslateNextUtf16(PCRTUTF16 pwszString, size_t cwcStringMax)
+{
+    if (cwcStringMax > 0)
+        return rtBase64TranslateUtf16(*pwszString);
+    return BASE64_INVALID;
+}
+
+
+/*
+ * Mostly the same as RTBase64DecodedSizeEx, except for the wider character
+ * type and therefore more careful handling of g_szRTBase64ValToChar and additional
+ * space characters.  Fixes must be applied to both copies of the code.
+ */
+RTDECL(ssize_t) RTBase64DecodedUtf16SizeEx(PCRTUTF16 pwszString, size_t cwcStringMax, PRTUTF16 *ppwszEnd)
+{
+#ifdef RT_STRICT
+    rtBase64Sanity();
+#endif
+
+    /*
+     * Walk the string until a non-encoded or non-space character is encountered.
+     */
+    uint32_t    c6Bits = 0;
+    uint8_t     u8     = BASE64_INVALID;
+    RTUTF16     wc     = 0;
+
+    while (cwcStringMax > 0 && (wc = *pwszString))
+    {
+        u8 = rtBase64TranslateUtf16(wc);
+        if (u8 < 64)
+            c6Bits++;
+        else if (RT_UNLIKELY(u8 != BASE64_SPACE))
+            break;
+
+        /* advance */
+        pwszString++;
+        cwcStringMax--;
+    }
+
+    /*
+     * Padding can only be found at the end and there is
+     * only 1 or 2 padding chars. Deal with it first.
+     */
+    unsigned    cbPad = 0;
+    if (u8 == BASE64_PAD)
+    {
+        cbPad = 1;
+        c6Bits++;
+        pwszString++;
+        cwcStringMax--;
+        while (cwcStringMax > 0 && (wc = *pwszString))
+        {
+            u8 = rtBase64TranslateUtf16(wc);
+            if (u8 != BASE64_SPACE)
+            {
+                if (u8 != BASE64_PAD)
+                    break;
+                c6Bits++;
+                cbPad++;
+            }
+            pwszString++;
+            cwcStringMax--;
+        }
+        if (cbPad >= 3)
+            return -1;
+    }
+
+    /*
+     * Invalid char and no where to indicate where the
+     * Base64 text ends? Return failure.
+     */
+    if (    u8 == BASE64_INVALID
+        &&  !ppwszEnd
+        &&  wc)
+        return -1;
+
+    /*
+     * Recalc 6-bit to 8-bit and adjust for padding.
+     */
+    if (ppwszEnd)
+        *ppwszEnd = (PRTUTF16)pwszString;
+    return rtBase64DecodedSizeRecalc(c6Bits, cbPad);
+}
+RT_EXPORT_SYMBOL(RTBase64DecodedUtf16SizeEx);
+
+
+RTDECL(ssize_t) RTBase64DecodedUtf16Size(PCRTUTF16 pwszString, PRTUTF16 *ppwszEnd)
+{
+    return RTBase64DecodedUtf16SizeEx(pwszString, RTSTR_MAX, ppwszEnd);
+}
+RT_EXPORT_SYMBOL(RTBase64DecodedUtf16Size);
+
+
+RTDECL(int) RTBase64DecodeUtf16Ex(PCRTUTF16 pwszString, size_t cwcStringMax, void *pvData, size_t cbData,
+                                  size_t *pcbActual, PRTUTF16 *ppwszEnd)
+{
+#ifdef RT_STRICT
+    rtBase64Sanity();
+#endif
+
+    /*
+     * Process input in groups of 4 input / 3 output chars.
+     */
+    uint8_t     u8Trio[3] = { 0, 0, 0 }; /* shuts up gcc */
+    uint8_t    *pbData    = (uint8_t *)pvData;
+    uint8_t     u8;
+    unsigned    c6Bits    = 0;
+    AssertCompile(sizeof(char) == sizeof(uint8_t));
+
+    for (;;)
+    {
+        /* The first 6-bit group. */
+        while ((u8 = rtBase64TranslateNextUtf16(pwszString, cwcStringMax)) == BASE64_SPACE)
+            pwszString++, cwcStringMax--;
+        if (u8 >= 64)
+        {
+            c6Bits = 0;
+            break;
+        }
+        u8Trio[0] = u8 << 2;
+        pwszString++;
+        cwcStringMax--;
+
+        /* The second 6-bit group. */
+        while ((u8 = rtBase64TranslateNextUtf16(pwszString, cwcStringMax)) == BASE64_SPACE)
+            pwszString++, cwcStringMax--;
+        if (u8 >= 64)
+        {
+            c6Bits = 1;
+            break;
+        }
+        u8Trio[0] |= u8 >> 4;
+        u8Trio[1]  = u8 << 4;
+        pwszString++;
+        cwcStringMax--;
+
+        /* The third 6-bit group. */
+        u8 = BASE64_INVALID;
+        while ((u8 = rtBase64TranslateNextUtf16(pwszString, cwcStringMax)) == BASE64_SPACE)
+            pwszString++, cwcStringMax--;
+        if (u8 >= 64)
+        {
+            c6Bits = 2;
+            break;
+        }
+        u8Trio[1] |= u8 >> 2;
+        u8Trio[2]  = u8 << 6;
+        pwszString++;
+        cwcStringMax--;
+
+        /* The fourth 6-bit group. */
+        u8 = BASE64_INVALID;
+        while ((u8 = rtBase64TranslateNextUtf16(pwszString, cwcStringMax)) == BASE64_SPACE)
+            pwszString++, cwcStringMax--;
+        if (u8 >= 64)
+        {
+            c6Bits = 3;
+            break;
+        }
+        u8Trio[2] |= u8;
+        pwszString++;
+        cwcStringMax--;
+
+        /* flush the trio */
+        if (cbData < 3)
+            return VERR_BUFFER_OVERFLOW;
+        cbData -= 3;
+        pbData[0] = u8Trio[0];
+        pbData[1] = u8Trio[1];
+        pbData[2] = u8Trio[2];
+        pbData += 3;
+    }
+
+    /*
+     * Padding can only be found at the end and there is
+     * only 1 or 2 padding chars. Deal with it first.
+     */
+    unsigned cbPad = 0;
+    if (u8 == BASE64_PAD)
+    {
+        cbPad = 1;
+        pwszString++;
+        cwcStringMax--;
+        RTUTF16 wc;
+        while (cwcStringMax > 0 && (wc = *pwszString))
+        {
+            u8 = rtBase64TranslateUtf16(wc);
+            if (u8 != BASE64_SPACE)
+            {
+                if (u8 != BASE64_PAD)
+                    break;
+                cbPad++;
+            }
+            pwszString++;
+            cwcStringMax--;
+        }
+        if (cbPad >= 3)
+            return VERR_INVALID_BASE64_ENCODING;
+    }
+
+    /*
+     * Invalid char and no where to indicate where the
+     * Base64 text ends? Return failure.
+     */
+    if (    u8 == BASE64_INVALID
+        &&  !ppwszEnd
+        &&  cwcStringMax != 0
+        &&  *pwszString != '\0')
+        return VERR_INVALID_BASE64_ENCODING;
+
+    /*
+     * Check padding vs. pending sextets, if anything left to do finish it off.
+     */
+    if (c6Bits || cbPad)
+    {
+        if (c6Bits + cbPad != 4)
+            return VERR_INVALID_BASE64_ENCODING;
+
+        switch (c6Bits)
+        {
+            case 1:
+                u8Trio[1] = u8Trio[2] = 0;
+                break;
+            case 2:
+                u8Trio[2] = 0;
+                break;
+            case 3:
+            default:
+                break;
+        }
+        switch (3 - cbPad)
+        {
+            case 1:
+                if (cbData < 1)
+                    return VERR_BUFFER_OVERFLOW;
+                cbData--;
+                pbData[0] = u8Trio[0];
+                pbData++;
+                break;
+
+            case 2:
+                if (cbData < 2)
+                    return VERR_BUFFER_OVERFLOW;
+                cbData -= 2;
+                pbData[0] = u8Trio[0];
+                pbData[1] = u8Trio[1];
+                pbData += 2;
+                break;
+
+            default:
+                break;
+        }
+    }
+
+    /*
+     * Set optional return values and return successfully.
+     */
+    if (ppwszEnd)
+        *ppwszEnd = (PRTUTF16)pwszString;
+    if (pcbActual)
+        *pcbActual = pbData - (uint8_t *)pvData;
+    return VINF_SUCCESS;
+}
+RT_EXPORT_SYMBOL(RTBase64DecodeUtf16Ex);
+
+
+RTDECL(int) RTBase64DecodeUtf16(PCRTUTF16 pwszString, void *pvData, size_t cbData, size_t *pcbActual, PRTUTF16 *ppwszEnd)
+{
+    return RTBase64DecodeUtf16Ex(pwszString, RTSTR_MAX, pvData, cbData, pcbActual, ppwszEnd);
+}
+RT_EXPORT_SYMBOL(RTBase64DecodeUtf16);
+
+
+RTDECL(size_t) RTBase64EncodedUtf16Length(size_t cbData)
+{
+    return RTBase64EncodedLengthEx(cbData, 0);
+}
+RT_EXPORT_SYMBOL(RTBase64EncodedUtf16Length);
+
+
+RTDECL(size_t) RTBase64EncodedUtf16LengthEx(size_t cbData, uint32_t fFlags)
+{
+    return RTBase64EncodedLengthEx(cbData, fFlags);
+}
+RT_EXPORT_SYMBOL(RTBase64EncodedUtf16LengthEx);
+
+
+RTDECL(int) RTBase64EncodeUtf16(const void *pvData, size_t cbData, PRTUTF16 pwszBuf, size_t cwcBuf, size_t *pcwcActual)
+{
+    return RTBase64EncodeUtf16Ex(pvData, cbData, 0, pwszBuf, cwcBuf, pcwcActual);
+}
+RT_EXPORT_SYMBOL(RTBase64EncodeUtf16);
+
+
+/*
+ * Please note that RTBase64EncodeEx contains an almost exact copy of
+ * this code, just using different output character type and variable prefixes.
+ * So, all fixes must be applied to both versions of the code.
+ */
+RTDECL(int) RTBase64EncodeUtf16Ex(const void *pvData, size_t cbData, uint32_t fFlags,
+                                  PRTUTF16 pwszBuf, size_t cwcBuf, size_t *pcwcActual)
+{
+    /* Expand the EOL style flags: */
+    size_t const    cchEol = g_acchRTBase64EolStyles[fFlags & RTBASE64_FLAGS_EOL_STYLE_MASK];
+    char const      chEol0 = g_aachRTBase64EolStyles[fFlags & RTBASE64_FLAGS_EOL_STYLE_MASK][0];
+    char const      chEol1 = g_aachRTBase64EolStyles[fFlags & RTBASE64_FLAGS_EOL_STYLE_MASK][1];
+    Assert(cchEol == (chEol0 != '\0' ? 1U : 0U) + (chEol1 != '\0' ? 1U : 0U));
+
+    /*
+     * Process whole "trios" of input data.
+     */
+    uint8_t         u8A;
+    uint8_t         u8B;
+    uint8_t         u8C;
+    size_t          cwcLineFeed = cchEol ? cwcBuf - RTBASE64_LINE_LEN : ~(size_t)0;
+    const uint8_t  *pbSrc       = (const uint8_t *)pvData;
+    PRTUTF16        pwcDst      = pwszBuf;
+    while (cbData >= 3)
+    {
+        if (cwcBuf < 4 + 1)
+            return VERR_BUFFER_OVERFLOW;
+
+        /* encode */
+        u8A = pbSrc[0];
+        pwcDst[0] = g_szRTBase64ValToChar[u8A >> 2];
+        u8B = pbSrc[1];
+        pwcDst[1] = g_szRTBase64ValToChar[((u8A << 4) & 0x3f) | (u8B >> 4)];
+        u8C = pbSrc[2];
+        pwcDst[2] = g_szRTBase64ValToChar[((u8B << 2) & 0x3f) | (u8C >> 6)];
+        pwcDst[3] = g_szRTBase64ValToChar[u8C & 0x3f];
+
+        /* advance */
+        cwcBuf -= 4;
+        pwcDst += 4;
+        cbData -= 3;
+        pbSrc  += 3;
+
+        /* deal out end-of-line */
+        if (cwcBuf == cwcLineFeed && cbData && cchEol)
+        {
+            if (cwcBuf < cchEol + 1)
+                return VERR_BUFFER_OVERFLOW;
+            cwcBuf -= cchEol;
+            *pwcDst++ = chEol0;
+            if (chEol1)
+                *pwcDst++ = chEol1;
+            cwcLineFeed = cwcBuf - RTBASE64_LINE_LEN;
+        }
+    }
+
+    /*
+     * Deal with the odd bytes and string termination.
+     */
+    if (cbData)
+    {
+        if (cwcBuf < 4 + 1)
+            return VERR_BUFFER_OVERFLOW;
+        switch (cbData)
+        {
+            case 1:
+                u8A = pbSrc[0];
+                pwcDst[0] = g_szRTBase64ValToChar[u8A >> 2];
+                pwcDst[1] = g_szRTBase64ValToChar[(u8A << 4) & 0x3f];
+                pwcDst[2] = '=';
+                pwcDst[3] = '=';
+                break;
+            case 2:
+                u8A = pbSrc[0];
+                pwcDst[0] = g_szRTBase64ValToChar[u8A >> 2];
+                u8B = pbSrc[1];
+                pwcDst[1] = g_szRTBase64ValToChar[((u8A << 4) & 0x3f) | (u8B >> 4)];
+                pwcDst[2] = g_szRTBase64ValToChar[(u8B << 2) & 0x3f];
+                pwcDst[3] = '=';
+                break;
+        }
+        pwcDst += 4;
+    }
+
+    *pwcDst = '\0';
+
+    if (pcwcActual)
+        *pcwcActual = pwcDst - pwszBuf;
+    return VINF_SUCCESS;
+}
+RT_EXPORT_SYMBOL(RTBase64EncodeUtf16Ex);
+
Index: /trunk/src/VBox/Runtime/common/string/base64.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/string/base64.cpp	(revision 84292)
+++ /trunk/src/VBox/Runtime/common/string/base64.cpp	(revision 84293)
@@ -2,4 +2,7 @@
 /** @file
  * IPRT - Base64, MIME content transfer encoding.
+ *
+ * @note The base64-utf16.cpp file must be diffable with this one.
+ *       Fixed typically applies to both files.
  */
 
@@ -40,17 +43,5 @@
 #endif
 
-
-/*********************************************************************************************************************************
-*   Defined Constants And Macros                                                                                                 *
-*********************************************************************************************************************************/
-/** The line length used for encoding. */
-#define RTBASE64_LINE_LEN   64
-
-/** @name Special g_au8CharToVal values
- * @{ */
-#define BASE64_SPACE        0xc0
-#define BASE64_PAD          0xe0
-#define BASE64_INVALID      0xff
-/** @} */
+#include "base64.h"
 
 
@@ -60,5 +51,5 @@
 /** Base64 character to value. (RFC 2045)
  * ASSUMES ASCII / UTF-8. */
-static const uint8_t    g_au8CharToVal[256] =
+DECL_HIDDEN_CONST(const uint8_t)    g_au8RTBase64CharToVal[256] =
 {
     0xff, 0xff, 0xff, 0xff,   0xff, 0xff, 0xff, 0xff,   0xff, 0xc0, 0xc0, 0xc0,   0xc0, 0xc0, 0xff, 0xff, /* 0x00..0x0f */
@@ -81,8 +72,8 @@
 
 /** Value to Base64 character. (RFC 2045) */
-static const char       g_szValToChar[64+1] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+DECL_HIDDEN_CONST(const char)   g_szRTBase64ValToChar[64+1] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
 
 /** The end-of-line lengths (indexed by style flag value). */
-static const size_t     g_acchEolStyles[RTBASE64_FLAGS_EOL_STYLE_MASK + 1] =
+DECL_HIDDEN_CONST(const size_t) g_acchRTBase64EolStyles[RTBASE64_FLAGS_EOL_STYLE_MASK + 1] =
 {
     /*[RTBASE64_FLAGS_EOL_NATIVE    ]:*/ RTBASE64_EOL_SIZE,
@@ -93,5 +84,5 @@
 
 /** The end-of-line characters (zero, one or two). */
-static const char       g_aachEolStyles[RTBASE64_FLAGS_EOL_STYLE_MASK + 1][2] =
+DECL_HIDDEN_CONST(const char)   g_aachRTBase64EolStyles[RTBASE64_FLAGS_EOL_STYLE_MASK + 1][2] =
 {
     /*[RTBASE64_FLAGS_EOL_NATIVE    ]:*/ { RTBASE64_EOL_SIZE == 1 ? '\n' : '\r', RTBASE64_EOL_SIZE == 1 ? '\0' : '\n', },
@@ -107,5 +98,5 @@
  * Perform table sanity checks on the first call.
  */
-static void rtBase64Sanity(void)
+DECLHIDDEN(void) rtBase64Sanity(void)
 {
     static bool s_fSane = false;
@@ -114,12 +105,12 @@
         for (unsigned i = 0; i < 64; i++)
         {
-            unsigned ch = g_szValToChar[i];
+            unsigned ch = g_szRTBase64ValToChar[i];
             Assert(ch);
-            Assert(g_au8CharToVal[ch] == i);
+            Assert(g_au8RTBase64CharToVal[ch] == i);
         }
 
         for (unsigned i = 0; i < 256; i++)
         {
-            uint8_t u8 = g_au8CharToVal[i];
+            uint8_t u8 = g_au8RTBase64CharToVal[i];
             Assert(   (     u8 == BASE64_INVALID
                        &&   !RT_C_IS_ALNUM(i)
@@ -130,5 +121,5 @@
                        &&   RT_C_IS_SPACE(i))
                    || (     u8 < 64
-                       &&   (unsigned)g_szValToChar[u8] == i));
+                       &&   (unsigned)g_szRTBase64ValToChar[u8] == i));
         }
         ASMAtomicWriteBool(&s_fSane, true);
@@ -138,4 +129,8 @@
 
 
+/*
+ * Mostly the same as RTBase64DecodedUtf16SizeEx, except for the simpler
+ * character type.  Fixes must be applied to both copies of the code.
+ */
 RTDECL(ssize_t) RTBase64DecodedSizeEx(const char *pszString, size_t cchStringMax, char **ppszEnd)
 {
@@ -154,5 +149,5 @@
     while (cchStringMax > 0 && (ch = *pszString))
     {
-        u8 = g_au8CharToVal[ch];
+        u8 = g_au8RTBase64CharToVal[ch];
         if (u8 < 64)
             c6Bits++;
@@ -178,5 +173,5 @@
         while (cchStringMax > 0 && (ch = *pszString))
         {
-            u8 = g_au8CharToVal[ch];
+            u8 = g_au8RTBase64CharToVal[ch];
             if (u8 != BASE64_SPACE)
             {
@@ -205,25 +200,7 @@
      * Recalc 6-bit to 8-bit and adjust for padding.
      */
-    size_t cb;
-    if (c6Bits * 3 / 3 == c6Bits)
-    {
-        if ((c6Bits * 3 % 4) != 0)
-            return -1;
-        cb = c6Bits * 3 / 4;
-    }
-    else
-    {
-        if ((c6Bits * (uint64_t)3 % 4) != 0)
-            return -1;
-        cb = c6Bits * (uint64_t)3 / 4;
-    }
-
-    if (cb < cbPad)
-        return -1;
-    cb -= cbPad;
-
     if (ppszEnd)
         *ppszEnd = (char *)pszString;
-    return cb;
+    return rtBase64DecodedSizeRecalc(c6Bits, cbPad);
 }
 RT_EXPORT_SYMBOL(RTBase64DecodedSizeEx);
@@ -257,5 +234,5 @@
     {
         /* The first 6-bit group. */
-        while ((u8 = g_au8CharToVal[ch = cchStringMax > 0 ? (uint8_t)*pszString : 0]) == BASE64_SPACE)
+        while ((u8 = g_au8RTBase64CharToVal[ch = cchStringMax > 0 ? (uint8_t)*pszString : 0]) == BASE64_SPACE)
             pszString++, cchStringMax--;
         if (u8 >= 64)
@@ -269,5 +246,5 @@
 
         /* The second 6-bit group. */
-        while ((u8 = g_au8CharToVal[ch = cchStringMax > 0 ? (uint8_t)*pszString : 0]) == BASE64_SPACE)
+        while ((u8 = g_au8RTBase64CharToVal[ch = cchStringMax > 0 ? (uint8_t)*pszString : 0]) == BASE64_SPACE)
             pszString++, cchStringMax--;
         if (u8 >= 64)
@@ -283,5 +260,5 @@
         /* The third 6-bit group. */
         u8 = BASE64_INVALID;
-        while ((u8 = g_au8CharToVal[ch = cchStringMax > 0 ? (uint8_t)*pszString : 0]) == BASE64_SPACE)
+        while ((u8 = g_au8RTBase64CharToVal[ch = cchStringMax > 0 ? (uint8_t)*pszString : 0]) == BASE64_SPACE)
             pszString++, cchStringMax--;
         if (u8 >= 64)
@@ -297,5 +274,5 @@
         /* The fourth 6-bit group. */
         u8 = BASE64_INVALID;
-        while ((u8 = g_au8CharToVal[ch = cchStringMax > 0 ? (uint8_t)*pszString : 0]) == BASE64_SPACE)
+        while ((u8 = g_au8RTBase64CharToVal[ch = cchStringMax > 0 ? (uint8_t)*pszString : 0]) == BASE64_SPACE)
             pszString++, cchStringMax--;
         if (u8 >= 64)
@@ -330,5 +307,5 @@
         while (cchStringMax > 0 && (ch = (uint8_t)*pszString))
         {
-            u8 = g_au8CharToVal[ch];
+            u8 = g_au8RTBase64CharToVal[ch];
             if (u8 != BASE64_SPACE)
             {
@@ -425,5 +402,5 @@
 RTDECL(size_t) RTBase64EncodedLengthEx(size_t cbData, uint32_t fFlags)
 {
-    size_t const cchEol = g_acchEolStyles[fFlags & RTBASE64_FLAGS_EOL_STYLE_MASK];
+    size_t const cchEol = g_acchRTBase64EolStyles[fFlags & RTBASE64_FLAGS_EOL_STYLE_MASK];
 
     if (cbData * 8 / 8 != cbData)
@@ -464,7 +441,7 @@
 {
     /* Expand the EOL style flags: */
-    size_t const    cchEol = g_acchEolStyles[fFlags & RTBASE64_FLAGS_EOL_STYLE_MASK];
-    char const      chEol0 = g_aachEolStyles[fFlags & RTBASE64_FLAGS_EOL_STYLE_MASK][0];
-    char const      chEol1 = g_aachEolStyles[fFlags & RTBASE64_FLAGS_EOL_STYLE_MASK][1];
+    size_t const    cchEol = g_acchRTBase64EolStyles[fFlags & RTBASE64_FLAGS_EOL_STYLE_MASK];
+    char const      chEol0 = g_aachRTBase64EolStyles[fFlags & RTBASE64_FLAGS_EOL_STYLE_MASK][0];
+    char const      chEol1 = g_aachRTBase64EolStyles[fFlags & RTBASE64_FLAGS_EOL_STYLE_MASK][1];
     Assert(cchEol == (chEol0 != '\0' ? 1U : 0U) + (chEol1 != '\0' ? 1U : 0U));
 
@@ -485,10 +462,10 @@
         /* encode */
         u8A = pbSrc[0];
-        pchDst[0] = g_szValToChar[u8A >> 2];
+        pchDst[0] = g_szRTBase64ValToChar[u8A >> 2];
         u8B = pbSrc[1];
-        pchDst[1] = g_szValToChar[((u8A << 4) & 0x3f) | (u8B >> 4)];
+        pchDst[1] = g_szRTBase64ValToChar[((u8A << 4) & 0x3f) | (u8B >> 4)];
         u8C = pbSrc[2];
-        pchDst[2] = g_szValToChar[((u8B << 2) & 0x3f) | (u8C >> 6)];
-        pchDst[3] = g_szValToChar[u8C & 0x3f];
+        pchDst[2] = g_szRTBase64ValToChar[((u8B << 2) & 0x3f) | (u8C >> 6)];
+        pchDst[3] = g_szRTBase64ValToChar[u8C & 0x3f];
 
         /* advance */
@@ -522,6 +499,6 @@
             case 1:
                 u8A = pbSrc[0];
-                pchDst[0] = g_szValToChar[u8A >> 2];
-                pchDst[1] = g_szValToChar[(u8A << 4) & 0x3f];
+                pchDst[0] = g_szRTBase64ValToChar[u8A >> 2];
+                pchDst[1] = g_szRTBase64ValToChar[(u8A << 4) & 0x3f];
                 pchDst[2] = '=';
                 pchDst[3] = '=';
@@ -529,8 +506,8 @@
             case 2:
                 u8A = pbSrc[0];
-                pchDst[0] = g_szValToChar[u8A >> 2];
+                pchDst[0] = g_szRTBase64ValToChar[u8A >> 2];
                 u8B = pbSrc[1];
-                pchDst[1] = g_szValToChar[((u8A << 4) & 0x3f) | (u8B >> 4)];
-                pchDst[2] = g_szValToChar[(u8B << 2) & 0x3f];
+                pchDst[1] = g_szRTBase64ValToChar[((u8A << 4) & 0x3f) | (u8B >> 4)];
+                pchDst[2] = g_szRTBase64ValToChar[(u8B << 2) & 0x3f];
                 pchDst[3] = '=';
                 break;
@@ -547,116 +524,2 @@
 RT_EXPORT_SYMBOL(RTBase64EncodeEx);
 
-
-/*
- * Please note that RTBase64EncodeEx contains an almost exact copy of
- * this code, just using different output character type and variable prefixes.
- * So, all fixes must be applied to both versions of the code.
- */
-RTDECL(int) RTBase64EncodeUtf16Ex(const void *pvData, size_t cbData, uint32_t fFlags,
-                                  PRTUTF16 pwszBuf, size_t cwcBuf, size_t *pcwcActual)
-{
-    /* Expand the EOL style flags: */
-    size_t const    cchEol = g_acchEolStyles[fFlags & RTBASE64_FLAGS_EOL_STYLE_MASK];
-    char const      chEol0 = g_aachEolStyles[fFlags & RTBASE64_FLAGS_EOL_STYLE_MASK][0];
-    char const      chEol1 = g_aachEolStyles[fFlags & RTBASE64_FLAGS_EOL_STYLE_MASK][1];
-    Assert(cchEol == (chEol0 != '\0' ? 1U : 0U) + (chEol1 != '\0' ? 1U : 0U));
-
-    /*
-     * Process whole "trios" of input data.
-     */
-    uint8_t         u8A;
-    uint8_t         u8B;
-    uint8_t         u8C;
-    size_t          cwcLineFeed = cchEol ? cwcBuf - RTBASE64_LINE_LEN : ~(size_t)0;
-    const uint8_t  *pbSrc       = (const uint8_t *)pvData;
-    PRTUTF16        pwcDst      = pwszBuf;
-    while (cbData >= 3)
-    {
-        if (cwcBuf < 4 + 1)
-            return VERR_BUFFER_OVERFLOW;
-
-        /* encode */
-        u8A = pbSrc[0];
-        pwcDst[0] = g_szValToChar[u8A >> 2];
-        u8B = pbSrc[1];
-        pwcDst[1] = g_szValToChar[((u8A << 4) & 0x3f) | (u8B >> 4)];
-        u8C = pbSrc[2];
-        pwcDst[2] = g_szValToChar[((u8B << 2) & 0x3f) | (u8C >> 6)];
-        pwcDst[3] = g_szValToChar[u8C & 0x3f];
-
-        /* advance */
-        cwcBuf -= 4;
-        pwcDst += 4;
-        cbData -= 3;
-        pbSrc  += 3;
-
-        /* deal out end-of-line */
-        if (cwcBuf == cwcLineFeed && cbData && cchEol)
-        {
-            if (cwcBuf < cchEol + 1)
-                return VERR_BUFFER_OVERFLOW;
-            cwcBuf -= cchEol;
-            *pwcDst++ = chEol0;
-            if (chEol1)
-                *pwcDst++ = chEol1;
-            cwcLineFeed = cwcBuf - RTBASE64_LINE_LEN;
-        }
-    }
-
-    /*
-     * Deal with the odd bytes and string termination.
-     */
-    if (cbData)
-    {
-        if (cwcBuf < 4 + 1)
-            return VERR_BUFFER_OVERFLOW;
-        switch (cbData)
-        {
-            case 1:
-                u8A = pbSrc[0];
-                pwcDst[0] = g_szValToChar[u8A >> 2];
-                pwcDst[1] = g_szValToChar[(u8A << 4) & 0x3f];
-                pwcDst[2] = '=';
-                pwcDst[3] = '=';
-                break;
-            case 2:
-                u8A = pbSrc[0];
-                pwcDst[0] = g_szValToChar[u8A >> 2];
-                u8B = pbSrc[1];
-                pwcDst[1] = g_szValToChar[((u8A << 4) & 0x3f) | (u8B >> 4)];
-                pwcDst[2] = g_szValToChar[(u8B << 2) & 0x3f];
-                pwcDst[3] = '=';
-                break;
-        }
-        pwcDst += 4;
-    }
-
-    *pwcDst = '\0';
-
-    if (pcwcActual)
-        *pcwcActual = pwcDst - pwszBuf;
-    return VINF_SUCCESS;
-}
-RT_EXPORT_SYMBOL(RTBase64EncodeUtf16Ex);
-
-
-RTDECL(int) RTBase64EncodeUtf16(const void *pvData, size_t cbData, PRTUTF16 pwszBuf, size_t cwcBuf, size_t *pcwcActual)
-{
-    return RTBase64EncodeUtf16Ex(pvData, cbData, 0, pwszBuf, cwcBuf, pcwcActual);
-}
-RT_EXPORT_SYMBOL(RTBase64EncodeUtf16);
-
-
-RTDECL(size_t) RTBase64EncodedUtf16Length(size_t cbData)
-{
-    return RTBase64EncodedLengthEx(cbData, 0);
-}
-RT_EXPORT_SYMBOL(RTBase64EncodedUtf16Length);
-
-
-RTDECL(size_t) RTBase64EncodedUtf16LengthEx(size_t cbData, uint32_t fFlags)
-{
-    return RTBase64EncodedLengthEx(cbData, fFlags);
-}
-RT_EXPORT_SYMBOL(RTBase64EncodedUtf16LengthEx);
-
Index: /trunk/src/VBox/Runtime/testcase/tstRTBase64.cpp
===================================================================
--- /trunk/src/VBox/Runtime/testcase/tstRTBase64.cpp	(revision 84292)
+++ /trunk/src/VBox/Runtime/testcase/tstRTBase64.cpp	(revision 84293)
@@ -113,6 +113,4 @@
      */
 
-    /* Decoding: later */
-
     /* Encoding UTF-16: */
     memset(wszOut, 0xaa, sizeof(wszOut));
@@ -130,4 +128,27 @@
     if (cwcOut != cwcOut2)
         RTTestIFailed("RTBase64EncodedLength returned %zu RTUTF16 units, expected %zu.\n", cwcOut2, cwcOut);
+
+    /* Decoding UTF-16: */
+    PRTUTF16 pwszEnc = NULL;
+    RTTESTI_CHECK_RC_OK_RETV(RTStrToUtf16(pszEnc, &pwszEnc));
+
+    rc = RTBase64DecodeUtf16(pwszEnc, szOut, cbData, &cchOut, NULL);
+    if (RT_FAILURE(rc))
+        RTTestIFailed("RTBase64DecodeUtf16 -> %Rrc", rc);
+    else if (cchOut != cbData)
+        RTTestIFailed("RTBase64DecodeUtf16 returned %zu bytes, expected %zu.", cchOut, cbData);
+    else if (memcmp(szOut, pvData, cchOut))
+    {
+        if (fTextData)
+            RTTestIFailed("RTBase64Decode returned:\n%.*s\nexpected:\n%s\n", (int)cchOut, szOut, pvData);
+        else
+            RTTestIFailed("RTBase64Decode return mismatching output\n");
+    }
+
+    cchOut = RTBase64DecodedUtf16Size(pwszEnc, NULL);
+    if (cchOut != cbData)
+        RTTestIFailed("RTBase64DecodedUtf16Size returned %zu bytes, expected %zu.\n", cchOut, cbData);
+
+    RTUtf16Free(pwszEnc);
 }
 
