VirtualBox

Changeset 83837 in vbox for trunk/src/VBox/Runtime/common


Ignore:
Timestamp:
Apr 20, 2020 12:34:06 AM (5 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
137366
Message:

IPRT: Added RTUtf16Printf, RTUtf16PrintfV, RTUtf16PrintfEx and RTUtf16PrintfExV. bugref:8489

File:
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/common/string/utf-16-printf.cpp

    r83836 r83837  
    11/* $Id$ */
    22/** @file
    3  * IPRT - String Formatters, alternative.
     3 * IPRT - String Formatters, Outputting UTF-16.
    44 */
    55
     
    2929*   Header Files                                                                                                                 *
    3030*********************************************************************************************************************************/
     31#include <iprt/utf16.h>
     32#include "internal/iprt.h"
     33
     34#include <iprt/assert.h>
    3135#include <iprt/string.h>
    32 #include "internal/iprt.h"
    33 
    34 #include <iprt/assert.h>
     36#include <iprt/uni.h>
    3537
    3638
     
    3840*   Structures and Typedefs                                                                                                      *
    3941*********************************************************************************************************************************/
    40 /** rtStrPrintf2Output() argument structure. */
    41 typedef struct STRPRINTF2OUTPUTARGS
     42/** rtUtf16PrintfOutput() argument structure. */
     43typedef struct UTF16PRINTFOUTPUTARGS
    4244{
    4345    /** Pointer to current buffer position. */
    44     char   *pszCur;
    45     /** Number of bytes left in the buffer (including the trailing zero). */
    46     size_t  cbLeft;
     46    PRTUTF16    pwszCur;
     47    /** Number of RTUTF16 units left in the buffer (including the trailing zero). */
     48    size_t      cwcLeft;
    4749    /** Set if we overflowed. */
    48     bool    fOverflowed;
    49 } STRPRINTF2OUTPUTARGS;
    50 /** Pointer to a rtStrPrintf2Output() argument structure. */
    51 typedef STRPRINTF2OUTPUTARGS *PSTRPRINTF2OUTPUTARGS;
     50    bool        fOverflowed;
     51} UTF16PRINTFOUTPUTARGS;
     52/** Pointer to a rtUtf16PrintfOutput() argument structure. */
     53typedef UTF16PRINTFOUTPUTARGS *PUTF16PRINTFOUTPUTARGS;
    5254
    5355
     
    5557 * Output callback.
    5658 *
    57  * @returns cbChars
     59 * @returns Number of RTUTF16 units we (would have) outputted.
    5860 *
    5961 * @param   pvArg       Pointer to a STRBUFARG structure.
     
    6163 * @param   cbChars     Number of bytes in the character array pointed to by pachChars.
    6264 */
    63 static DECLCALLBACK(size_t) rtStrPrintf2Output(void *pvArg, const char *pachChars, size_t cbChars)
    64 {
    65     PSTRPRINTF2OUTPUTARGS pArgs = (PSTRPRINTF2OUTPUTARGS)pvArg;
    66     char *pszCur = pArgs->pszCur; /* We actually have to spell this out for VS2010, or it will load it for each case. */
    67 
    68     if (cbChars < pArgs->cbLeft)
     65static DECLCALLBACK(size_t) rtUtf16PrintfOutput(void *pvArg, const char *pachChars, size_t cbChars)
     66{
     67    PUTF16PRINTFOUTPUTARGS pArgs  = (PUTF16PRINTFOUTPUTARGS)pvArg;
     68    size_t                 cwcRet = 0;
     69
     70    size_t cwcLeft = pArgs->cwcLeft;
     71    if (cwcLeft > 1)
    6972    {
    70         pArgs->cbLeft -= cbChars;
    71 
    72         /* Note! For VS2010/64 we need at least 7 case statements before it generates a jump table. */
    73         switch (cbChars)
     73        Assert(!pArgs->fOverflowed);
     74
     75        PRTUTF16 pwszCur = pArgs->pwszCur;
     76        for (;;)
    7477        {
    75             default:
    76                 memcpy(pszCur, pachChars, cbChars);
    77                 break;
    78             case 8: pszCur[7] = pachChars[7]; RT_FALL_THRU();
    79             case 7: pszCur[6] = pachChars[6]; RT_FALL_THRU();
    80             case 6: pszCur[5] = pachChars[5]; RT_FALL_THRU();
    81             case 5: pszCur[4] = pachChars[4]; RT_FALL_THRU();
    82             case 4: pszCur[3] = pachChars[3]; RT_FALL_THRU();
    83             case 3: pszCur[2] = pachChars[2]; RT_FALL_THRU();
    84             case 2: pszCur[1] = pachChars[1]; RT_FALL_THRU();
    85             case 1: pszCur[0] = pachChars[0]; RT_FALL_THRU();
    86             case 0:
    87                 break;
     78            if (cbChars > 0)
     79            {
     80                RTUNICP uc;
     81                int rc = RTStrGetCpNEx(&pachChars, &cbChars, &uc);
     82                AssertRCStmt(rc, uc = 0x7f);
     83
     84                /* Simple: */
     85                if (RTUniCpIsBMP(uc))
     86                {
     87                    cwcRet += 1;
     88                    if (RT_LIKELY(cwcLeft > 1))
     89                        *pwszCur++ = uc;
     90                    else
     91                        break;
     92                    cwcLeft--;
     93                }
     94                /* Surrogate pair: */
     95                else if (uc >= 0x10000 && uc <= 0x0010ffff)
     96                {
     97                    cwcRet += 2;
     98                    if (RT_LIKELY(cwcLeft > 2))
     99                        *pwszCur++ = 0xd800 | (uc >> 10);
     100                    else
     101                    {
     102                        if (cwcLeft > 1)
     103                        {
     104                            cwcLeft = 1;
     105                            pwszCur[1] = '\0';
     106                        }
     107                        break;
     108                    }
     109                    *pwszCur++ = 0xdc00 | (uc & 0x3ff);
     110                    cwcLeft -= 2;
     111                }
     112                else
     113                {
     114                    AssertMsgFailed(("uc=%#x\n", uc));
     115                    cwcRet += 1;
     116                    if (RT_LIKELY(cwcLeft > 1))
     117                        *pwszCur++ = 0x7f;
     118                    else
     119                        break;
     120                    cwcLeft--;
     121                }
     122            }
     123            else
     124            {
     125                *pwszCur = '\0';
     126                pArgs->pwszCur = pwszCur;
     127                pArgs->cwcLeft = cwcLeft;
     128                return cwcRet;
     129            }
    88130        }
    89         pArgs->pszCur = pszCur += cbChars;
    90         *pszCur = '\0';
     131
     132        /*
     133         * We only get here if we run out of buffer space.
     134         */
     135        Assert(cwcLeft == 1);
     136        *pwszCur = '\0';
     137        pArgs->pwszCur = pwszCur;
     138        pArgs->cwcLeft = cwcLeft;
    91139    }
    92     else
     140    /*
     141     * We get a special zero byte call at the end for the formatting operation.
     142     *
     143     * Make sure we don't turn that into an overflow and that we'll terminate
     144     * empty result strings.
     145     */
     146    else if (cbChars == 0 && cwcLeft > 0)
    93147    {
    94         size_t cbLeft = pArgs->cbLeft;
    95         if (cbLeft-- > 1)
     148        *pArgs->pwszCur = '\0';
     149        return 0;
     150    }
     151
     152    /*
     153     * Overflow handling.  Calc needed space.
     154     */
     155    pArgs->fOverflowed = true;
     156
     157    while (cbChars > 0)
     158    {
     159        RTUNICP uc;
     160        int rc = RTStrGetCpNEx(&pachChars, &cbChars, &uc);
     161        AssertRCStmt(rc, uc = 0x7f);
     162
     163        if (RTUniCpIsBMP(uc))
     164            cwcRet += 1;
     165        else if (uc >= 0x10000 && uc <= 0x0010ffff)
     166            cwcRet += 2;
     167        else
    96168        {
    97             memcpy(pszCur, pachChars, cbLeft);
    98             pArgs->pszCur = pszCur += cbLeft;
    99             *pszCur = '\0';
    100             pArgs->cbLeft = 1;
     169            AssertMsgFailed(("uc=%#x\n", uc));
     170            cwcRet += 1;
    101171        }
    102         pArgs->fOverflowed = true;
    103172    }
    104173
    105     return cbChars;
    106 }
    107 
    108 
    109 RTDECL(ssize_t) RTStrPrintf2(char *pszBuffer, size_t cchBuffer, const char *pszFormat, ...)
    110 {
    111     /* Explicitly inline RTStrPrintf2V + RTStrPrintf2ExV here because this is a frequently use API. */
    112     STRPRINTF2OUTPUTARGS Args;
    113     size_t cchRet;
     174    return cwcRet;
     175}
     176
     177
     178RTDECL(ssize_t) RTUtf16Printf(PRTUTF16 pwszBuffer, size_t cwcBuffer, const char *pszFormat, ...)
     179{
     180    /* Explicitly inline RTStrPrintfV + RTStrPrintfExV here because this is a frequently use API. */
     181    UTF16PRINTFOUTPUTARGS Args;
     182    size_t cwcRet;
    114183    va_list args;
    115     AssertMsg(cchBuffer > 0, ("Excellent idea! Format a string with no space for the output!\n"));
    116 
    117     Args.pszCur      = pszBuffer;
    118     Args.cbLeft      = cchBuffer;
     184    AssertMsg(cwcBuffer > 0, ("Excellent idea! Format a string with no space for the output!\n"));
     185
     186    Args.pwszCur     = pwszBuffer;
     187    Args.cwcLeft     = cwcBuffer;
    119188    Args.fOverflowed = false;
    120189
    121190    va_start(args, pszFormat);
    122     cchRet = RTStrFormatV(rtStrPrintf2Output, &Args, NULL, NULL, pszFormat, args);
     191    cwcRet = RTStrFormatV(rtUtf16PrintfOutput, &Args, NULL, NULL, pszFormat, args);
    123192    va_end(args);
    124193
    125     return !Args.fOverflowed ? (ssize_t)cchRet : -(ssize_t)cchRet - 1;
     194    return !Args.fOverflowed ? (ssize_t)cwcRet : -(ssize_t)cwcRet - 1;
    126195}
    127196RT_EXPORT_SYMBOL(RTStrPrintf2);
    128197
    129198
    130 RTDECL(ssize_t) RTStrPrintf2ExV(PFNSTRFORMAT pfnFormat, void *pvArg, char *pszBuffer, size_t cchBuffer,
    131                                 const char *pszFormat,  va_list args)
    132 {
    133     STRPRINTF2OUTPUTARGS Args;
    134     size_t cchRet;
    135     AssertMsg(cchBuffer > 0, ("Excellent idea! Format a string with no space for the output!\n"));
    136 
    137     Args.pszCur      = pszBuffer;
    138     Args.cbLeft      = cchBuffer;
     199RTDECL(ssize_t) RTUtf16PrintfExV(PFNSTRFORMAT pfnFormat, void *pvArg, PRTUTF16 pwszBuffer, size_t cwcBuffer,
     200                                 const char *pszFormat,  va_list args)
     201{
     202    UTF16PRINTFOUTPUTARGS Args;
     203    size_t cwcRet;
     204    AssertMsg(cwcBuffer > 0, ("Excellent idea! Format a string with no space for the output!\n"));
     205
     206    Args.pwszCur     = pwszBuffer;
     207    Args.cwcLeft     = cwcBuffer;
    139208    Args.fOverflowed = false;
    140     cchRet = RTStrFormatV(rtStrPrintf2Output, &Args, pfnFormat, pvArg, pszFormat, args);
    141     return !Args.fOverflowed ? (ssize_t)cchRet : -(ssize_t)cchRet - 1;
    142 }
    143 RT_EXPORT_SYMBOL(RTStrPrintf2ExV);
    144 
    145 
    146 RTDECL(ssize_t) RTStrPrintf2V(char *pszBuffer, size_t cchBuffer, const char *pszFormat, va_list args)
    147 {
    148     return RTStrPrintf2ExV(NULL, NULL, pszBuffer, cchBuffer, pszFormat, args);
    149 }
    150 RT_EXPORT_SYMBOL(RTStrPrintf2V);
    151 
    152 
    153 RTDECL(ssize_t) RTStrPrintf2Ex(PFNSTRFORMAT pfnFormat, void *pvArg, char *pszBuffer, size_t cchBuffer, const char *pszFormat, ...)
     209    cwcRet = RTStrFormatV(rtUtf16PrintfOutput, &Args, pfnFormat, pvArg, pszFormat, args);
     210    return !Args.fOverflowed ? (ssize_t)cwcRet : -(ssize_t)cwcRet - 1;
     211}
     212RT_EXPORT_SYMBOL(RTUtf16PrintfExV);
     213
     214
     215RTDECL(ssize_t) RTUtf16PrintfV(PRTUTF16 pwszBuffer, size_t cwcBuffer, const char *pszFormat, va_list args)
     216{
     217    return RTUtf16PrintfExV(NULL, NULL, pwszBuffer, cwcBuffer, pszFormat, args);
     218}
     219RT_EXPORT_SYMBOL(RTUtf16Printf2V);
     220
     221
     222RTDECL(ssize_t) RTUtf16PrintfEx(PFNSTRFORMAT pfnFormat, void *pvArg, PRTUTF16 pwszBuffer, size_t cwcBuffer,
     223                                const char *pszFormat, ...)
    154224{
    155225    va_list args;
    156226    ssize_t cbRet;
    157227    va_start(args, pszFormat);
    158     cbRet = RTStrPrintf2ExV(pfnFormat, pvArg, pszBuffer, cchBuffer, pszFormat, args);
     228    cbRet = RTUtf16PrintfExV(pfnFormat, pvArg, pwszBuffer, cwcBuffer, pszFormat, args);
    159229    va_end(args);
    160230    return cbRet;
    161231}
    162 RT_EXPORT_SYMBOL(RTStrPrintf2Ex);
    163 
     232RT_EXPORT_SYMBOL(RTUtf16PrintfEx);
     233
Note: See TracChangeset for help on using the changeset viewer.

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