VirtualBox

Changeset 84339 in vbox for trunk


Ignore:
Timestamp:
May 18, 2020 5:35:01 PM (5 years ago)
Author:
vboxsync
Message:

Glue/Bstr: Added base64DecodedLength and base64Decode methods too. Put the implementation in a separate file for extpack and others who don't really need this code. bugref:9224

Location:
trunk
Files:
3 edited
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/include/VBox/com/string.h

    r84287 r84339  
    664664     * @{ */
    665665    /**
    666      * Encodes the give data as BASE64.
     666     * Encodes the given data as BASE64.
    667667     *
    668668     * @returns S_OK or E_OUTOFMEMORY.
     
    671671     * @param   fLineBreaks     Whether to add line breaks (true) or just encode it
    672672     *                          as a continuous string.
     673     * @sa RTBase64EncodeUtf16
    673674     */
    674675    HRESULT base64Encode(const void *pvData, size_t cbData, bool fLineBreaks = false);
     676
     677    /**
     678     * Decodes the string as BASE64.
     679     *
     680     * @returns IPRT status code, see RTBase64DecodeUtf16Ex.
     681     * @param   pvData          Where to return the decoded bytes.
     682     * @param   cbData          Size of the @a pvData return buffer.
     683     * @param   pcbActual       Where to return number of bytes actually decoded.
     684     *                          This is optional and if not specified, the request
     685     *                          will fail unless @a cbData matches the data size
     686     *                          exactly.
     687     * @param   ppwszEnd        Where to return pointer to the first non-base64
     688     *                          character following the encoded data.  This is
     689     *                          optional and if NULL, the request will fail if there
     690     *                          are anything trailing the encoded bytes in the
     691     *                          string.
     692     * @sa base64DecodedSize, RTBase64DecodeUtf16
     693     */
     694    int base64Decode(void *pvData, size_t cbData, size_t *pcbActual = NULL, PRTUTF16 *ppwszEnd = NULL);
     695
     696    /**
     697     * Determins the size of the BASE64 encoded data in the string.
     698     *
     699     * @returns The length in bytes. -1 if the encoding is bad.
     700     *
     701     * @param   pwszString      The Base64 encoded UTF-16 string.
     702     * @param   ppwszEnd        If not NULL, this will point to the first char
     703     *                          following the Base64 encoded text block. If
     704     *                          NULL the entire string is assumed to be Base64.
     705     * @sa      base64Decode, RTBase64DecodedUtf16Size
     706     */
     707    ssize_t base64DecodedSize(PRTUTF16 *ppwszEnd = NULL);
    675708    /** @} */
    676709
  • trunk/src/VBox/Main/Makefile.kmk

    r83820 r84339  
    12061206        glue/initterm.cpp \
    12071207        glue/string.cpp \
     1208        glue/string-base64.cpp \
    12081209        glue/AutoLock.cpp \
    12091210        glue/EventQueue.cpp \
  • trunk/src/VBox/Main/glue/string-base64.cpp

    r84331 r84339  
    11/* $Id$ */
    22/** @file
    3  * MS COM / XPCOM Abstraction Layer - UTF-8 and UTF-16 string classes.
     3 * MS COM / XPCOM Abstraction Layer - UTF-8 and UTF-16 string classes, BASE64 bits.
    44 */
    55
     
    1919
    2020#include <iprt/base64.h>
    21 #include <iprt/err.h>
    22 #include <iprt/log.h>
    23 #include <iprt/path.h>
    24 #include <iprt/string.h>
    25 #include <iprt/uni.h>
     21#include <iprt/errcore.h>
     22
    2623
    2724namespace com
    2825{
    29 
    30 // BSTR representing a null wide char with 32 bits of length prefix (0);
    31 // this will work on Windows as well as other platforms where BSTR does
    32 // not use length prefixes
    33 const OLECHAR g_achEmptyBstr[3] = { 0, 0, 0 };
    34 const BSTR g_bstrEmpty = (BSTR)&g_achEmptyBstr[2];
    35 
    36 /* static */
    37 const Bstr Bstr::Empty; /* default ctor is OK */
    38 
    39 
    40 Bstr &Bstr::printf(const char *pszFormat, ...)
    41 {
    42     va_list va;
    43     va_start(va, pszFormat);
    44     HRESULT hrc = printfVNoThrow(pszFormat, va);
    45     va_end(va);
    46     if (hrc == S_OK)
    47     { /* likely */ }
    48     else
    49         throw std::bad_alloc();
    50     return *this;
    51 }
    52 
    53 HRESULT Bstr::printfNoThrow(const char *pszFormat, ...) RT_NOEXCEPT
    54 {
    55     va_list va;
    56     va_start(va, pszFormat);
    57     HRESULT hrc = printfVNoThrow(pszFormat, va);
    58     va_end(va);
    59     return hrc;
    60 }
    61 
    62 
    63 Bstr &Bstr::printfV(const char *pszFormat, va_list va)
    64 {
    65     HRESULT hrc = printfVNoThrow(pszFormat, va);
    66     if (hrc == S_OK)
    67     { /* likely */ }
    68     else
    69         throw std::bad_alloc();
    70     return *this;
    71 }
    72 
    73 struct BSTRNOTHROW
    74 {
    75     Bstr   *pThis;
    76     size_t  cwcAlloc;
    77     size_t  offDst;
    78     HRESULT hrc;
    79 };
    80 
    81 /**
    82  * Callback used with RTStrFormatV by Bstr::printfVNoThrow.
    83  *
    84  * @returns The number of bytes added (not used).
    85  *
    86  * @param   pvArg           Pointer to a BSTRNOTHROW structure.
    87  * @param   pachChars       The characters to append.
    88  * @param   cbChars         The number of characters.  0 on the final callback.
    89  */
    90 /*static*/ DECLCALLBACK(size_t)
    91 Bstr::printfOutputCallbackNoThrow(void *pvArg, const char *pachChars, size_t cbChars) RT_NOEXCEPT
    92 {
    93     BSTRNOTHROW *pArgs = (BSTRNOTHROW *)pvArg;
    94     if (cbChars)
    95     {
    96         size_t cwcAppend;
    97         int rc = ::RTStrCalcUtf16LenEx(pachChars, cbChars, &cwcAppend);
    98         AssertRCReturnStmt(rc, pArgs->hrc = E_UNEXPECTED, 0);
    99 
    100         /*
    101          * Ensure we've got sufficient memory.
    102          */
    103         Bstr *pThis = pArgs->pThis;
    104         size_t const cwcBoth = pArgs->offDst + cwcAppend;
    105         if (cwcBoth >= pArgs->cwcAlloc)
    106         {
    107             if (pArgs->hrc == S_OK)
    108             {
    109                 /* Double the buffer size, if it's less that _1M. Align sizes like
    110                    for append. */
    111                 size_t cwcAlloc = RT_ALIGN_Z(pArgs->cwcAlloc, 128);
    112                 cwcAlloc += RT_MIN(cwcAlloc, _1M);
    113                 if (cwcAlloc <= cwcBoth)
    114                     cwcAlloc = RT_ALIGN_Z(cwcBoth + 1, 512);
    115                 pArgs->hrc = pThis->reserveNoThrow(cwcAlloc, true /*fForce*/);
    116                 AssertMsgReturn(pArgs->hrc == S_OK, ("cwcAlloc=%#zx\n", cwcAlloc), 0);
    117                 pArgs->cwcAlloc = cwcAlloc;
    118             }
    119             else
    120                 return 0;
    121         }
    122 
    123         /*
    124          * Do the conversion.
    125          */
    126         PRTUTF16 pwszDst = pThis->m_bstr + pArgs->offDst;
    127         Assert(pArgs->cwcAlloc > pArgs->offDst);
    128         rc = ::RTStrToUtf16Ex(pachChars, cbChars, &pwszDst, pArgs->cwcAlloc - pArgs->offDst, &cwcAppend);
    129         AssertRCReturnStmt(rc, pArgs->hrc = E_UNEXPECTED, 0);
    130         pArgs->offDst += cwcAppend;
    131     }
    132     return cbChars;
    133 }
    134 
    135 HRESULT Bstr::printfVNoThrow(const char *pszFormat, va_list va) RT_NOEXCEPT
    136 {
    137     cleanup();
    138 
    139     BSTRNOTHROW Args = { this, 0, 0, S_OK };
    140     RTStrFormatV(printfOutputCallbackNoThrow, &Args, NULL, NULL, pszFormat, va);
    141     if (Args.hrc == S_OK)
    142     {
    143         Args.hrc = joltNoThrow(Args.offDst);
    144         if (Args.hrc == S_OK)
    145             return S_OK;
    146     }
    147 
    148     cleanup();
    149     return Args.hrc;
    150 }
    151 
    152 void Bstr::copyFromN(const char *a_pszSrc, size_t a_cchMax)
    153 {
    154     /*
    155      * Initialize m_bstr first in case of throws further down in the code, then
    156      * check for empty input (m_bstr == NULL means empty, there are no NULL
    157      * strings).
    158      */
    159     m_bstr = NULL;
    160     if (!a_cchMax || !a_pszSrc || !*a_pszSrc)
    161         return;
    162 
    163     /*
    164      * Calculate the length and allocate a BSTR string buffer of the right
    165      * size, i.e. optimize heap usage.
    166      */
    167     size_t cwc;
    168     int vrc = ::RTStrCalcUtf16LenEx(a_pszSrc, a_cchMax, &cwc);
    169     if (RT_SUCCESS(vrc))
    170     {
    171         m_bstr = ::SysAllocStringByteLen(NULL, (unsigned)(cwc * sizeof(OLECHAR)));
    172         if (RT_LIKELY(m_bstr))
    173         {
    174             PRTUTF16 pwsz = (PRTUTF16)m_bstr;
    175             vrc = ::RTStrToUtf16Ex(a_pszSrc, a_cchMax, &pwsz, cwc + 1, NULL);
    176             if (RT_SUCCESS(vrc))
    177                 return;
    178 
    179             /* This should not happen! */
    180             AssertRC(vrc);
    181             cleanup();
    182         }
    183     }
    184     else /* ASSUME: input is valid Utf-8. Fake out of memory error. */
    185         AssertLogRelMsgFailed(("%Rrc %.*Rhxs\n", vrc, RTStrNLen(a_pszSrc, a_cchMax), a_pszSrc));
    186     throw std::bad_alloc();
    187 }
    188 
    189 int Bstr::compareUtf8(const char *a_pszRight, CaseSensitivity a_enmCase /*= CaseSensitive*/) const
    190 {
    191     PCRTUTF16 pwszLeft = m_bstr;
    192 
    193     /*
    194      * Special case for null/empty strings.  Unlike RTUtf16Cmp we
    195      * treat null and empty equally.
    196      */
    197     if (!pwszLeft)
    198         return !a_pszRight || *a_pszRight == '\0' ? 0 : -1;
    199     if (!a_pszRight)
    200         return *pwszLeft == '\0'                  ? 0 :  1;
    201 
    202     /*
    203      * Compare with a UTF-8 string by enumerating them char by char.
    204      */
    205     for (;;)
    206     {
    207         RTUNICP ucLeft;
    208         int rc = RTUtf16GetCpEx(&pwszLeft, &ucLeft);
    209         AssertRCReturn(rc, 1);
    210 
    211         RTUNICP ucRight;
    212         rc = RTStrGetCpEx(&a_pszRight, &ucRight);
    213         AssertRCReturn(rc, -1);
    214         if (ucLeft == ucRight)
    215         {
    216             if (ucLeft)
    217                 continue;
    218             return 0;
    219         }
    220 
    221         if (a_enmCase == CaseInsensitive)
    222         {
    223             if (RTUniCpToUpper(ucLeft) == RTUniCpToUpper(ucRight))
    224                 continue;
    225             if (RTUniCpToLower(ucLeft) == RTUniCpToLower(ucRight))
    226                 continue;
    227         }
    228 
    229         return ucLeft < ucRight ? -1 : 1;
    230     }
    231 }
    23226
    23327HRESULT Bstr::base64Encode(const void *pvData, size_t cbData, bool fLineBreaks /*= false*/)
     
    24539}
    24640
    247 
    248 #ifndef VBOX_WITH_XPCOM
    249 
    250 HRESULT Bstr::joltNoThrow(ssize_t cwcNew /* = -1*/) RT_NOEXCEPT
     41int Bstr::base64Decode(void *pvData, size_t cbData, size_t *pcbActual /*= NULL*/, PRTUTF16 *ppwszEnd /*= NULL*/)
    25142{
    252     if (m_bstr)
    253     {
    254         size_t const cwcAlloc  = ::SysStringLen(m_bstr);
    255         size_t const cwcActual = cwcNew < 0 ? ::RTUtf16Len(m_bstr) : (size_t)cwcNew;
    256         Assert(cwcNew < 0 || cwcActual == ::RTUtf16Len(m_bstr));
    257         if (cwcActual != cwcAlloc)
    258         {
    259             Assert(cwcActual <= cwcAlloc);
    260             Assert((unsigned int)cwcActual == cwcActual);
    261 
    262             /* Official way: Reallocate the string.   We could of course just update the size-prefix if we dared... */
    263             if (!::SysReAllocStringLen(&m_bstr, NULL, (unsigned int)cwcActual))
    264             {
    265                 AssertFailed();
    266                 return E_OUTOFMEMORY;
    267             }
    268         }
    269     }
    270     else
    271         Assert(cwcNew <= 0);
    272     return S_OK;
     43    return RTBase64DecodeUtf16Ex(raw(), RTSTR_MAX, pvData, cbData, pcbActual, ppwszEnd);
    27344}
    27445
    275 
    276 void Bstr::jolt(ssize_t cwcNew /* = -1*/)
     46ssize_t Bstr::base64DecodedSize(PRTUTF16 *ppwszEnd /*= NULL*/)
    27747{
    278     HRESULT hrc = joltNoThrow(cwcNew);
    279     if (hrc != S_OK)
    280         throw std::bad_alloc();
    281 }
    282 
    283 #endif /* !VBOX_WITH_XPCOM */
    284 
    285 
    286 HRESULT Bstr::reserveNoThrow(size_t cwcMin, bool fForce /*= false*/) RT_NOEXCEPT
    287 {
    288     /* If not forcing the string to the cwcMin length, check cwcMin against the
    289        current string length: */
    290     if (!fForce)
    291     {
    292         size_t cwcCur = m_bstr ? ::SysStringLen(m_bstr) : 0;
    293         if (cwcCur >= cwcMin)
    294             return S_OK;
    295     }
    296 
    297     /* The documentation for SysReAllocStringLen hints about it being allergic
    298        to NULL in some way or another, so we call SysAllocStringLen directly
    299        when appropriate: */
    300     if (m_bstr)
    301         AssertReturn(::SysReAllocStringLen(&m_bstr, NULL, (unsigned int)cwcMin) != FALSE, E_OUTOFMEMORY);
    302     else if (cwcMin > 0)
    303     {
    304         m_bstr = ::SysAllocStringLen(NULL, (unsigned int)cwcMin);
    305         AssertReturn(m_bstr, E_OUTOFMEMORY);
    306     }
    307 
    308     return S_OK;
    309 }
    310 
    311 
    312 void Bstr::reserve(size_t cwcMin, bool fForce /*= false*/)
    313 {
    314     HRESULT hrc = reserveNoThrow(cwcMin, fForce);
    315     if (hrc != S_OK)
    316         throw std::bad_alloc();
    317 }
    318 
    319 
    320 Bstr &Bstr::append(const Bstr &rThat)
    321 {
    322     if (rThat.isNotEmpty())
    323         return appendWorkerUtf16(rThat.m_bstr, rThat.length());
    324     return *this;
    325 }
    326 
    327 
    328 HRESULT Bstr::appendNoThrow(const Bstr &rThat) RT_NOEXCEPT
    329 {
    330     if (rThat.isNotEmpty())
    331         return appendWorkerUtf16NoThrow(rThat.m_bstr, rThat.length());
    332     return S_OK;
    333 }
    334 
    335 
    336 Bstr &Bstr::append(const RTCString &rThat)
    337 {
    338     if (rThat.isNotEmpty())
    339         return appendWorkerUtf8(rThat.c_str(), rThat.length());
    340     return *this;
    341 }
    342 
    343 
    344 HRESULT Bstr::appendNoThrow(const RTCString &rThat) RT_NOEXCEPT
    345 {
    346     if (rThat.isNotEmpty())
    347         return appendWorkerUtf8NoThrow(rThat.c_str(), rThat.length());
    348     return S_OK;
    349 }
    350 
    351 
    352 Bstr &Bstr::append(CBSTR pwszSrc)
    353 {
    354     if (pwszSrc && *pwszSrc)
    355         return appendWorkerUtf16(pwszSrc, RTUtf16Len(pwszSrc));
    356     return *this;
    357 }
    358 
    359 
    360 HRESULT Bstr::appendNoThrow(CBSTR pwszSrc) RT_NOEXCEPT
    361 {
    362     if (pwszSrc && *pwszSrc)
    363         return appendWorkerUtf16NoThrow(pwszSrc, RTUtf16Len(pwszSrc));
    364     return S_OK;
    365 }
    366 
    367 
    368 Bstr &Bstr::append(const char *pszSrc)
    369 {
    370     if (pszSrc && *pszSrc)
    371         return appendWorkerUtf8(pszSrc, strlen(pszSrc));
    372     return *this;
    373 }
    374 
    375 
    376 HRESULT Bstr::appendNoThrow(const char *pszSrc) RT_NOEXCEPT
    377 {
    378     if (pszSrc && *pszSrc)
    379         return appendWorkerUtf8NoThrow(pszSrc, strlen(pszSrc));
    380     return S_OK;
    381 }
    382 
    383 
    384 Bstr &Bstr::append(const Bstr &rThat, size_t offStart, size_t cwcMax /*= RTSTR_MAX*/)
    385 {
    386     size_t cwcSrc = rThat.length();
    387     if (offStart < cwcSrc)
    388         return appendWorkerUtf16(rThat.raw() + offStart, RT_MIN(cwcSrc - offStart, cwcMax));
    389     return *this;
    390 }
    391 
    392 
    393 HRESULT Bstr::appendNoThrow(const Bstr &rThat, size_t offStart, size_t cwcMax /*= RTSTR_MAX*/) RT_NOEXCEPT
    394 {
    395     size_t cwcSrc = rThat.length();
    396     if (offStart < cwcSrc)
    397         return appendWorkerUtf16NoThrow(rThat.raw() + offStart, RT_MIN(cwcSrc - offStart, cwcMax));
    398     return S_OK;
    399 }
    400 
    401 
    402 Bstr &Bstr::append(const RTCString &rThat, size_t offStart, size_t cchMax /*= RTSTR_MAX*/)
    403 {
    404     if (offStart < rThat.length())
    405         return appendWorkerUtf8(rThat.c_str() + offStart, RT_MIN(rThat.length() - offStart, cchMax));
    406     return *this;
    407 }
    408 
    409 
    410 HRESULT Bstr::appendNoThrow(const RTCString &rThat, size_t offStart, size_t cchMax /*= RTSTR_MAX*/) RT_NOEXCEPT
    411 {
    412     if (offStart < rThat.length())
    413         return appendWorkerUtf8NoThrow(rThat.c_str() + offStart, RT_MIN(rThat.length() - offStart, cchMax));
    414     return S_OK;
    415 }
    416 
    417 
    418 Bstr &Bstr::append(CBSTR pwszThat, size_t cchMax)
    419 {
    420     return appendWorkerUtf16(pwszThat, RTUtf16NLen(pwszThat, cchMax));
    421 }
    422 
    423 
    424 HRESULT Bstr::appendNoThrow(CBSTR pwszThat, size_t cchMax) RT_NOEXCEPT
    425 {
    426     return appendWorkerUtf16NoThrow(pwszThat, RTUtf16NLen(pwszThat, cchMax));
    427 }
    428 
    429 
    430 Bstr &Bstr::append(const char *pszThat, size_t cchMax)
    431 {
    432     return appendWorkerUtf8(pszThat, RTStrNLen(pszThat, cchMax));
    433 }
    434 
    435 
    436 HRESULT Bstr::appendNoThrow(const char *pszThat, size_t cchMax) RT_NOEXCEPT
    437 {
    438     return appendWorkerUtf8NoThrow(pszThat, RTStrNLen(pszThat, cchMax));
    439 }
    440 
    441 
    442 Bstr &Bstr::append(char ch)
    443 {
    444     AssertMsg(ch > 0 && ch < 127, ("%#x\n", ch));
    445     return appendWorkerUtf8(&ch, 1);
    446 }
    447 
    448 
    449 HRESULT Bstr::appendNoThrow(char ch) RT_NOEXCEPT
    450 {
    451     AssertMsg(ch > 0 && ch < 127, ("%#x\n", ch));
    452     return appendWorkerUtf8NoThrow(&ch, 1);
    453 }
    454 
    455 
    456 Bstr &Bstr::appendCodePoint(RTUNICP uc)
    457 {
    458     RTUTF16 wszTmp[3];
    459     PRTUTF16 pwszEnd = RTUtf16PutCp(wszTmp, uc);
    460     *pwszEnd = '\0';
    461     return appendWorkerUtf16(&wszTmp[0], pwszEnd - &wszTmp[0]);
    462 }
    463 
    464 
    465 HRESULT Bstr::appendCodePointNoThrow(RTUNICP uc) RT_NOEXCEPT
    466 {
    467     RTUTF16 wszTmp[3];
    468     PRTUTF16 pwszEnd = RTUtf16PutCp(wszTmp, uc);
    469     *pwszEnd = '\0';
    470     return appendWorkerUtf16NoThrow(&wszTmp[0], pwszEnd - &wszTmp[0]);
    471 }
    472 
    473 
    474 Bstr &Bstr::appendWorkerUtf16(PCRTUTF16 pwszSrc, size_t cwcSrc)
    475 {
    476     size_t cwcOld = length();
    477     size_t cwcTotal = cwcOld + cwcSrc;
    478     reserve(cwcTotal, true /*fForce*/);
    479     if (cwcSrc)
    480         memcpy(&m_bstr[cwcOld], pwszSrc, cwcSrc * sizeof(RTUTF16));
    481     m_bstr[cwcTotal] = '\0';
    482     return *this;
    483 }
    484 
    485 
    486 HRESULT Bstr::appendWorkerUtf16NoThrow(PCRTUTF16 pwszSrc, size_t cwcSrc) RT_NOEXCEPT
    487 {
    488     size_t cwcOld = length();
    489     size_t cwcTotal = cwcOld + cwcSrc;
    490     HRESULT hrc = reserveNoThrow(cwcTotal, true /*fForce*/);
    491     if (hrc == S_OK)
    492     {
    493         if (cwcSrc)
    494             memcpy(&m_bstr[cwcOld], pwszSrc, cwcSrc * sizeof(RTUTF16));
    495         m_bstr[cwcTotal] = '\0';
    496     }
    497     return hrc;
    498 }
    499 
    500 
    501 Bstr &Bstr::appendWorkerUtf8(const char *pszSrc, size_t cchSrc)
    502 {
    503     size_t cwcSrc;
    504     int rc = RTStrCalcUtf16LenEx(pszSrc, cchSrc, &cwcSrc);
    505     AssertRCStmt(rc, throw std::bad_alloc());
    506 
    507     size_t cwcOld = length();
    508     size_t cwcTotal = cwcOld + cwcSrc;
    509     reserve(cwcTotal, true /*fForce*/);
    510     if (cwcSrc)
    511     {
    512         PRTUTF16 pwszDst = &m_bstr[cwcOld];
    513         rc = RTStrToUtf16Ex(pszSrc, cchSrc, &pwszDst, cwcSrc + 1, NULL);
    514         AssertRCStmt(rc, throw std::bad_alloc());
    515     }
    516     m_bstr[cwcTotal] = '\0';
    517     return *this;
    518 }
    519 
    520 
    521 HRESULT Bstr::appendWorkerUtf8NoThrow(const char *pszSrc, size_t cchSrc) RT_NOEXCEPT
    522 {
    523     size_t cwcSrc;
    524     int rc = RTStrCalcUtf16LenEx(pszSrc, cchSrc, &cwcSrc);
    525     AssertRCStmt(rc, E_INVALIDARG);
    526 
    527     size_t cwcOld = length();
    528     size_t cwcTotal = cwcOld + cwcSrc;
    529     HRESULT hrc = reserveNoThrow(cwcTotal, true /*fForce*/);
    530     AssertReturn(hrc == S_OK, hrc);
    531     if (cwcSrc)
    532     {
    533         PRTUTF16 pwszDst = &m_bstr[cwcOld];
    534         rc = RTStrToUtf16Ex(pszSrc, cchSrc, &pwszDst, cwcSrc + 1, NULL);
    535         AssertRCStmt(rc, E_INVALIDARG);
    536     }
    537     m_bstr[cwcTotal] = '\0';
    538     return S_OK;
    539 }
    540 
    541 
    542 Bstr &Bstr::appendPrintf(const char *pszFormat, ...)
    543 {
    544     va_list va;
    545     va_start(va, pszFormat);
    546     HRESULT hrc = appendPrintfVNoThrow(pszFormat, va);
    547     va_end(va);
    548     if (hrc != S_OK)
    549         throw std::bad_alloc();
    550     return *this;
    551 }
    552 
    553 
    554 HRESULT Bstr::appendPrintfNoThrow(const char *pszFormat, ...) RT_NOEXCEPT
    555 {
    556     va_list va;
    557     va_start(va, pszFormat);
    558     HRESULT hrc = appendPrintfVNoThrow(pszFormat, va);
    559     va_end(va);
    560     return hrc;
    561 }
    562 
    563 
    564 Bstr &Bstr::appendPrintfV(const char *pszFormat, va_list va)
    565 {
    566     HRESULT hrc = appendPrintfVNoThrow(pszFormat, va);
    567     if (hrc != S_OK)
    568         throw std::bad_alloc();
    569     return *this;
    570 }
    571 
    572 
    573 HRESULT Bstr::appendPrintfVNoThrow(const char *pszFormat, va_list va) RT_NOEXCEPT
    574 {
    575     size_t const cwcOld = length();
    576     BSTRNOTHROW Args = { this, cwcOld, cwcOld, S_OK };
    577 
    578     RTStrFormatV(printfOutputCallbackNoThrow, &Args, NULL, NULL, pszFormat, va);
    579     if (Args.hrc == S_OK)
    580     {
    581         Args.hrc = joltNoThrow(Args.offDst);
    582         if (Args.hrc == S_OK)
    583             return S_OK;
    584     }
    585 
    586     if (m_bstr)
    587         m_bstr[cwcOld] = '\0';
    588     return Args.hrc;
    589 }
    590 
    591 
    592 Bstr &Bstr::erase(size_t offStart /*= 0*/, size_t cwcLength /*= RTSTR_MAX*/) RT_NOEXCEPT
    593 {
    594     size_t cwc = length();
    595     if (offStart < cwc)
    596     {
    597         if (cwcLength >= cwc - offStart)
    598         {
    599             if (!offStart)
    600                 cleanup();
    601             else
    602             {
    603                 /* Trail removal, nothing to move.  */
    604                 m_bstr[offStart] = '\0';
    605                 joltNoThrow(offStart); /* not entirely optimal... */
    606             }
    607         }
    608         else if (cwcLength > 0)
    609         {
    610             /* Pull up the tail to offStart. */
    611             size_t cwcAfter = cwc - offStart - cwcLength;
    612             memmove(&m_bstr[offStart], &m_bstr[offStart + cwcLength], cwcAfter * sizeof(*m_bstr));
    613             cwc -= cwcLength;
    614             m_bstr[cwc] = '\0';
    615             joltNoThrow(cwc); /* not entirely optimal... */
    616         }
    617     }
    618     return *this;
    619 }
    620 
    621 
    622 void Bstr::cleanup()
    623 {
    624     if (m_bstr)
    625     {
    626         ::SysFreeString(m_bstr);
    627         m_bstr = NULL;
    628     }
    629 }
    630 
    631 
    632 void Bstr::copyFrom(const OLECHAR *a_bstrSrc)
    633 {
    634     if (a_bstrSrc && *a_bstrSrc)
    635     {
    636         m_bstr = ::SysAllocString(a_bstrSrc);
    637         if (!m_bstr)
    638             throw std::bad_alloc();
    639     }
    640     else
    641         m_bstr = NULL;
    642 }
    643 
    644 
    645 void Bstr::cleanupAndCopyFrom(const OLECHAR *a_bstrSrc)
    646 {
    647     cleanup();
    648     copyFrom(a_bstrSrc);
    649 }
    650 
    651 
    652 
    653 /*********************************************************************************************************************************
    654 *   Utf8Str Implementation                                                                                                       *
    655 *********************************************************************************************************************************/
    656 
    657 /* static */
    658 const Utf8Str Utf8Str::Empty; /* default ctor is OK */
    659 
    660 #if defined(VBOX_WITH_XPCOM)
    661 void Utf8Str::cloneTo(char **pstr) const
    662 {
    663     size_t cb = length() + 1;
    664     *pstr = (char *)nsMemory::Alloc(cb);
    665     if (RT_LIKELY(*pstr))
    666         memcpy(*pstr, c_str(), cb);
    667     else
    668         throw std::bad_alloc();
    669 }
    670 
    671 HRESULT Utf8Str::cloneToEx(char **pstr) const
    672 {
    673     size_t cb = length() + 1;
    674     *pstr = (char *)nsMemory::Alloc(cb);
    675     if (RT_LIKELY(*pstr))
    676     {
    677         memcpy(*pstr, c_str(), cb);
    678         return S_OK;
    679     }
    680     return E_OUTOFMEMORY;
    681 }
    682 #endif
    683 
    684 Utf8Str& Utf8Str::stripTrailingSlash()
    685 {
    686     if (length())
    687     {
    688         ::RTPathStripTrailingSlash(m_psz);
    689         jolt();
    690     }
    691     return *this;
    692 }
    693 
    694 Utf8Str& Utf8Str::stripFilename()
    695 {
    696     if (length())
    697     {
    698         RTPathStripFilename(m_psz);
    699         jolt();
    700     }
    701     return *this;
    702 }
    703 
    704 Utf8Str& Utf8Str::stripPath()
    705 {
    706     if (length())
    707     {
    708         char *pszName = ::RTPathFilename(m_psz);
    709         if (pszName)
    710         {
    711             size_t cchName = length() - (pszName - m_psz);
    712             memmove(m_psz, pszName, cchName + 1);
    713             jolt();
    714         }
    715         else
    716             cleanup();
    717     }
    718     return *this;
    719 }
    720 
    721 Utf8Str& Utf8Str::stripSuffix()
    722 {
    723     if (length())
    724     {
    725         RTPathStripSuffix(m_psz);
    726         jolt();
    727     }
    728     return *this;
    729 }
    730 
    731 size_t Utf8Str::parseKeyValue(Utf8Str &a_rKey, Utf8Str &a_rValue, size_t a_offStart /* = 0*/,
    732                               const Utf8Str &a_rPairSeparator /*= ","*/, const Utf8Str &a_rKeyValueSeparator /*= "="*/) const
    733 {
    734     /* Find the end of the next pair, skipping empty pairs.
    735        Note! The skipping allows us to pass the return value of a parseKeyValue()
    736              call as offStart to the next call. */
    737     size_t offEnd;
    738     while (   a_offStart == (offEnd = find(&a_rPairSeparator, a_offStart))
    739            && offEnd != npos)
    740         a_offStart++;
    741 
    742     /* Look for a key/value separator before the end of the pair.
    743        ASSUMES npos value returned by find when the substring is not found is
    744        really high. */
    745     size_t offKeyValueSep = find(&a_rKeyValueSeparator, a_offStart);
    746     if (offKeyValueSep < offEnd)
    747     {
    748         a_rKey = substr(a_offStart, offKeyValueSep - a_offStart);
    749         if (offEnd == npos)
    750             offEnd = m_cch; /* No confusing npos when returning strings. */
    751         a_rValue = substr(offKeyValueSep + 1, offEnd - offKeyValueSep - 1);
    752     }
    753     else
    754     {
    755         a_rKey.setNull();
    756         a_rValue.setNull();
    757     }
    758 
    759     return offEnd;
    760 }
    761 
    762 /**
    763  * Internal function used in Utf8Str copy constructors and assignment when
    764  * copying from a UTF-16 string.
    765  *
    766  * As with the RTCString::copyFrom() variants, this unconditionally sets the
    767  * members to a copy of the given other strings and makes no assumptions about
    768  * previous contents.  This can therefore be used both in copy constructors,
    769  * when member variables have no defined value, and in assignments after having
    770  * called cleanup().
    771  *
    772  * This variant converts from a UTF-16 string, most probably from
    773  * a Bstr assignment.
    774  *
    775  * @param   a_pbstr         The source string.  The caller guarantees that this
    776  *                          is valid UTF-16.
    777  * @param   a_cwcMax        The number of characters to be copied. If set to RTSTR_MAX,
    778  *                          the entire string will be copied.
    779  *
    780  * @sa      RTCString::copyFromN
    781  */
    782 void Utf8Str::copyFrom(CBSTR a_pbstr, size_t a_cwcMax)
    783 {
    784     if (a_pbstr && *a_pbstr)
    785     {
    786         int vrc = RTUtf16ToUtf8Ex((PCRTUTF16)a_pbstr,
    787                                   a_cwcMax,        // size_t cwcString: translate entire string
    788                                   &m_psz,           // char **ppsz: output buffer
    789                                   0,                // size_t cch: if 0, func allocates buffer in *ppsz
    790                                   &m_cch);          // size_t *pcch: receives the size of the output string, excluding the terminator.
    791         if (RT_SUCCESS(vrc))
    792             m_cbAllocated = m_cch + 1;
    793         else
    794         {
    795             if (   vrc != VERR_NO_STR_MEMORY
    796                 && vrc != VERR_NO_MEMORY)
    797             {
    798                 /* ASSUME: input is valid Utf-16. Fake out of memory error. */
    799                 AssertLogRelMsgFailed(("%Rrc %.*Rhxs\n", vrc, RTUtf16Len(a_pbstr) * sizeof(RTUTF16), a_pbstr));
    800             }
    801 
    802             m_cch = 0;
    803             m_cbAllocated = 0;
    804             m_psz = NULL;
    805 
    806             throw std::bad_alloc();
    807         }
    808     }
    809     else
    810     {
    811         m_cch = 0;
    812         m_cbAllocated = 0;
    813         m_psz = NULL;
    814     }
    815 }
    816 
    817 /**
    818  * A variant of Utf8Str::copyFrom that does not throw any exceptions but returns
    819  * E_OUTOFMEMORY instead.
    820  *
    821  * @param   a_pbstr         The source string.
    822  * @returns S_OK or E_OUTOFMEMORY.
    823  */
    824 HRESULT Utf8Str::copyFromEx(CBSTR a_pbstr)
    825 {
    826     if (a_pbstr && *a_pbstr)
    827     {
    828         int vrc = RTUtf16ToUtf8Ex((PCRTUTF16)a_pbstr,
    829                                   RTSTR_MAX,        // size_t cwcString: translate entire string
    830                                   &m_psz,           // char **ppsz: output buffer
    831                                   0,                // size_t cch: if 0, func allocates buffer in *ppsz
    832                                   &m_cch);          // size_t *pcch: receives the size of the output string, excluding the terminator.
    833         if (RT_SUCCESS(vrc))
    834             m_cbAllocated = m_cch + 1;
    835         else
    836         {
    837             if (   vrc != VERR_NO_STR_MEMORY
    838                 && vrc != VERR_NO_MEMORY)
    839             {
    840                 /* ASSUME: input is valid Utf-16. Fake out of memory error. */
    841                 AssertLogRelMsgFailed(("%Rrc %.*Rhxs\n", vrc, RTUtf16Len(a_pbstr) * sizeof(RTUTF16), a_pbstr));
    842             }
    843 
    844             m_cch = 0;
    845             m_cbAllocated = 0;
    846             m_psz = NULL;
    847 
    848             return E_OUTOFMEMORY;
    849         }
    850     }
    851     else
    852     {
    853         m_cch = 0;
    854         m_cbAllocated = 0;
    855         m_psz = NULL;
    856     }
    857     return S_OK;
    858 }
    859 
    860 
    861 /**
    862  * A variant of Utf8Str::copyFromN that does not throw any exceptions but
    863  * returns E_OUTOFMEMORY instead.
    864  *
    865  * @param   a_pcszSrc   The source string.
    866  * @param   a_offSrc    Start offset to copy from.
    867  * @param   a_cchSrc    How much to copy
    868  * @returns S_OK or E_OUTOFMEMORY.
    869  *
    870  * @remarks This calls cleanup() first, so the caller doesn't have to. (Saves
    871  *          code space.)
    872  */
    873 HRESULT Utf8Str::copyFromExNComRC(const char *a_pcszSrc, size_t a_offSrc, size_t a_cchSrc)
    874 {
    875     Assert(!a_cchSrc || !m_psz || (uintptr_t)&a_pcszSrc[a_offSrc] - (uintptr_t)m_psz >= (uintptr_t)m_cbAllocated);
    876     cleanup();
    877     if (a_cchSrc)
    878     {
    879         m_psz = RTStrAlloc(a_cchSrc + 1);
    880         if (RT_LIKELY(m_psz))
    881         {
    882             m_cch = a_cchSrc;
    883             m_cbAllocated = a_cchSrc + 1;
    884             memcpy(m_psz, a_pcszSrc + a_offSrc, a_cchSrc);
    885             m_psz[a_cchSrc] = '\0';
    886         }
    887         else
    888         {
    889             m_cch = 0;
    890             m_cbAllocated = 0;
    891             return E_OUTOFMEMORY;
    892         }
    893     }
    894     else
    895     {
    896         m_cch = 0;
    897         m_cbAllocated = 0;
    898         m_psz = NULL;
    899     }
    900     return S_OK;
     48    return RTBase64DecodedUtf16SizeEx(raw(), RTSTR_MAX, ppwszEnd);
    90149}
    90250
  • trunk/src/VBox/Main/glue/string.cpp

    r84287 r84339  
    1818#include "VBox/com/string.h"
    1919
    20 #include <iprt/base64.h>
    2120#include <iprt/err.h>
    2221#include <iprt/log.h>
     
    231230}
    232231
    233 HRESULT Bstr::base64Encode(const void *pvData, size_t cbData, bool fLineBreaks /*= false*/)
    234 {
    235     uint32_t const fFlags     = fLineBreaks ? RTBASE64_FLAGS_EOL_LF : RTBASE64_FLAGS_NO_LINE_BREAKS;
    236     size_t         cwcEncoded = RTBase64EncodedUtf16LengthEx(cbData, fFlags);
    237     HRESULT hrc = reserveNoThrow(cwcEncoded + 1);
    238     if (SUCCEEDED(hrc))
    239     {
    240         int vrc = RTBase64EncodeUtf16Ex(pvData, cbData, fFlags, mutableRaw(), cwcEncoded, &cwcEncoded);
    241         AssertRCReturnStmt(vrc, setNull(), E_FAIL);
    242         hrc = joltNoThrow(cwcEncoded);
    243     }
    244     return hrc;
    245 }
    246 
    247232
    248233#ifndef VBOX_WITH_XPCOM
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette