Changeset 83837 in vbox for trunk/src/VBox/Runtime/common
- Timestamp:
- Apr 20, 2020 12:34:06 AM (5 years ago)
- svn:sync-xref-src-repo-rev:
- 137366
- File:
-
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/common/string/utf-16-printf.cpp
r83836 r83837 1 1 /* $Id$ */ 2 2 /** @file 3 * IPRT - String Formatters, alternative.3 * IPRT - String Formatters, Outputting UTF-16. 4 4 */ 5 5 … … 29 29 * Header Files * 30 30 *********************************************************************************************************************************/ 31 #include <iprt/utf16.h> 32 #include "internal/iprt.h" 33 34 #include <iprt/assert.h> 31 35 #include <iprt/string.h> 32 #include "internal/iprt.h" 33 34 #include <iprt/assert.h> 36 #include <iprt/uni.h> 35 37 36 38 … … 38 40 * Structures and Typedefs * 39 41 *********************************************************************************************************************************/ 40 /** rt StrPrintf2Output() argument structure. */41 typedef struct STRPRINTF2OUTPUTARGS42 /** rtUtf16PrintfOutput() argument structure. */ 43 typedef struct UTF16PRINTFOUTPUTARGS 42 44 { 43 45 /** 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; 47 49 /** Set if we overflowed. */ 48 bool fOverflowed;49 } STRPRINTF2OUTPUTARGS;50 /** Pointer to a rt StrPrintf2Output() argument structure. */51 typedef STRPRINTF2OUTPUTARGS *PSTRPRINTF2OUTPUTARGS;50 bool fOverflowed; 51 } UTF16PRINTFOUTPUTARGS; 52 /** Pointer to a rtUtf16PrintfOutput() argument structure. */ 53 typedef UTF16PRINTFOUTPUTARGS *PUTF16PRINTFOUTPUTARGS; 52 54 53 55 … … 55 57 * Output callback. 56 58 * 57 * @returns cbChars59 * @returns Number of RTUTF16 units we (would have) outputted. 58 60 * 59 61 * @param pvArg Pointer to a STRBUFARG structure. … … 61 63 * @param cbChars Number of bytes in the character array pointed to by pachChars. 62 64 */ 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) 65 static 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) 69 72 { 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 (;;) 74 77 { 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 } 88 130 } 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; 91 139 } 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) 93 147 { 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 96 168 { 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; 101 171 } 102 pArgs->fOverflowed = true;103 172 } 104 173 105 return c bChars;106 } 107 108 109 RTDECL(ssize_t) RT StrPrintf2(char *pszBuffer, size_t cchBuffer, const char *pszFormat, ...)110 { 111 /* Explicitly inline RTStrPrintf 2V + RTStrPrintf2ExV here because this is a frequently use API. */112 STRPRINTF2OUTPUTARGS Args;113 size_t c chRet;174 return cwcRet; 175 } 176 177 178 RTDECL(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; 114 183 va_list args; 115 AssertMsg(c chBuffer > 0, ("Excellent idea! Format a string with no space for the output!\n"));116 117 Args.p szCur = pszBuffer;118 Args.c bLeft = 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; 119 188 Args.fOverflowed = false; 120 189 121 190 va_start(args, pszFormat); 122 c chRet = RTStrFormatV(rtStrPrintf2Output, &Args, NULL, NULL, pszFormat, args);191 cwcRet = RTStrFormatV(rtUtf16PrintfOutput, &Args, NULL, NULL, pszFormat, args); 123 192 va_end(args); 124 193 125 return !Args.fOverflowed ? (ssize_t)c chRet : -(ssize_t)cchRet - 1;194 return !Args.fOverflowed ? (ssize_t)cwcRet : -(ssize_t)cwcRet - 1; 126 195 } 127 196 RT_EXPORT_SYMBOL(RTStrPrintf2); 128 197 129 198 130 RTDECL(ssize_t) RT StrPrintf2ExV(PFNSTRFORMAT pfnFormat, void *pvArg, char *pszBuffer, size_t cchBuffer,131 const char *pszFormat, va_list args)132 { 133 STRPRINTF2OUTPUTARGS Args;134 size_t c chRet;135 AssertMsg(c chBuffer > 0, ("Excellent idea! Format a string with no space for the output!\n"));136 137 Args.p szCur = pszBuffer;138 Args.c bLeft = cchBuffer;199 RTDECL(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; 139 208 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 } 212 RT_EXPORT_SYMBOL(RTUtf16PrintfExV); 213 214 215 RTDECL(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 } 219 RT_EXPORT_SYMBOL(RTUtf16Printf2V); 220 221 222 RTDECL(ssize_t) RTUtf16PrintfEx(PFNSTRFORMAT pfnFormat, void *pvArg, PRTUTF16 pwszBuffer, size_t cwcBuffer, 223 const char *pszFormat, ...) 154 224 { 155 225 va_list args; 156 226 ssize_t cbRet; 157 227 va_start(args, pszFormat); 158 cbRet = RT StrPrintf2ExV(pfnFormat, pvArg, pszBuffer, cchBuffer, pszFormat, args);228 cbRet = RTUtf16PrintfExV(pfnFormat, pvArg, pwszBuffer, cwcBuffer, pszFormat, args); 159 229 va_end(args); 160 230 return cbRet; 161 231 } 162 RT_EXPORT_SYMBOL(RT StrPrintf2Ex);163 232 RT_EXPORT_SYMBOL(RTUtf16PrintfEx); 233
Note:
See TracChangeset
for help on using the changeset viewer.