VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/string/utf-16-printf.cpp

Last change on this file was 98103, checked in by vboxsync, 17 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 8.0 KB
RevLine 
[1]1/* $Id: utf-16-printf.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
[83837]3 * IPRT - String Formatters, Outputting UTF-16.
[1]4 */
5
6/*
[98103]7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
[1]8 *
[96407]9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
[5999]11 *
[96407]12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
[5999]25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
[96407]27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
[5999]29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
[96407]33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
[1]35 */
36
37
[57358]38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
[83837]41#include <iprt/utf16.h>
[21337]42#include "internal/iprt.h"
43
[1]44#include <iprt/assert.h>
[83837]45#include <iprt/string.h>
46#include <iprt/uni.h>
[1]47
48
[57358]49/*********************************************************************************************************************************
50* Structures and Typedefs *
51*********************************************************************************************************************************/
[83837]52/** rtUtf16PrintfOutput() argument structure. */
53typedef struct UTF16PRINTFOUTPUTARGS
[1]54{
55 /** Pointer to current buffer position. */
[83837]56 PRTUTF16 pwszCur;
57 /** Number of RTUTF16 units left in the buffer (including the trailing zero). */
58 size_t cwcLeft;
[64340]59 /** Set if we overflowed. */
[83837]60 bool fOverflowed;
61} UTF16PRINTFOUTPUTARGS;
62/** Pointer to a rtUtf16PrintfOutput() argument structure. */
63typedef UTF16PRINTFOUTPUTARGS *PUTF16PRINTFOUTPUTARGS;
[1]64
65
66/**
67 * Output callback.
68 *
[83837]69 * @returns Number of RTUTF16 units we (would have) outputted.
[64340]70 *
[1]71 * @param pvArg Pointer to a STRBUFARG structure.
72 * @param pachChars Pointer to an array of utf-8 characters.
73 * @param cbChars Number of bytes in the character array pointed to by pachChars.
74 */
[83837]75static DECLCALLBACK(size_t) rtUtf16PrintfOutput(void *pvArg, const char *pachChars, size_t cbChars)
[1]76{
[83837]77 PUTF16PRINTFOUTPUTARGS pArgs = (PUTF16PRINTFOUTPUTARGS)pvArg;
78 size_t cwcRet = 0;
[1]79
[83837]80 size_t cwcLeft = pArgs->cwcLeft;
81 if (cwcLeft > 1)
[1]82 {
[83837]83 Assert(!pArgs->fOverflowed);
[64340]84
[83837]85 PRTUTF16 pwszCur = pArgs->pwszCur;
86 for (;;)
[64340]87 {
[83837]88 if (cbChars > 0)
89 {
90 RTUNICP uc;
91 int rc = RTStrGetCpNEx(&pachChars, &cbChars, &uc);
[83943]92 AssertRCStmt(rc, uc = 0xfffd /* REPLACEMENT */);
[83837]93
94 /* Simple: */
95 if (RTUniCpIsBMP(uc))
96 {
97 cwcRet += 1;
98 if (RT_LIKELY(cwcLeft > 1))
99 *pwszCur++ = uc;
100 else
101 break;
102 cwcLeft--;
103 }
104 /* Surrogate pair: */
105 else if (uc >= 0x10000 && uc <= 0x0010ffff)
106 {
107 cwcRet += 2;
108 if (RT_LIKELY(cwcLeft > 2))
109 *pwszCur++ = 0xd800 | (uc >> 10);
110 else
111 {
112 if (cwcLeft > 1)
113 {
114 cwcLeft = 1;
115 pwszCur[1] = '\0';
116 }
117 break;
118 }
119 *pwszCur++ = 0xdc00 | (uc & 0x3ff);
120 cwcLeft -= 2;
121 }
122 else
123 {
124 AssertMsgFailed(("uc=%#x\n", uc));
125 cwcRet += 1;
126 if (RT_LIKELY(cwcLeft > 1))
[83943]127 *pwszCur++ = 0xfffd; /* REPLACEMENT */
[83837]128 else
129 break;
130 cwcLeft--;
131 }
132 }
133 else
134 {
135 *pwszCur = '\0';
136 pArgs->pwszCur = pwszCur;
137 pArgs->cwcLeft = cwcLeft;
138 return cwcRet;
139 }
[64340]140 }
[83837]141
142 /*
143 * We only get here if we run out of buffer space.
144 */
145 Assert(cwcLeft == 1);
146 *pwszCur = '\0';
147 pArgs->pwszCur = pwszCur;
148 pArgs->cwcLeft = cwcLeft;
[1]149 }
[83837]150 /*
151 * We get a special zero byte call at the end for the formatting operation.
152 *
153 * Make sure we don't turn that into an overflow and that we'll terminate
154 * empty result strings.
155 */
156 else if (cbChars == 0 && cwcLeft > 0)
[64340]157 {
[83837]158 *pArgs->pwszCur = '\0';
159 return 0;
160 }
161
162 /*
163 * Overflow handling. Calc needed space.
164 */
165 pArgs->fOverflowed = true;
166
167 while (cbChars > 0)
168 {
169 RTUNICP uc;
170 int rc = RTStrGetCpNEx(&pachChars, &cbChars, &uc);
[83943]171 AssertRCStmt(rc, uc = 0xfffd /* REPLACEMENT */);
[83837]172
173 if (RTUniCpIsBMP(uc))
174 cwcRet += 1;
175 else if (uc >= 0x10000 && uc <= 0x0010ffff)
176 cwcRet += 2;
177 else
[64340]178 {
[83837]179 AssertMsgFailed(("uc=%#x\n", uc));
180 cwcRet += 1;
[64340]181 }
182 }
[1]183
[83837]184 return cwcRet;
[1]185}
186
187
[83837]188RTDECL(ssize_t) RTUtf16Printf(PRTUTF16 pwszBuffer, size_t cwcBuffer, const char *pszFormat, ...)
[1]189{
[83837]190 /* Explicitly inline RTStrPrintfV + RTStrPrintfExV here because this is a frequently use API. */
191 UTF16PRINTFOUTPUTARGS Args;
192 size_t cwcRet;
[64340]193 va_list args;
[83837]194 AssertMsg(cwcBuffer > 0, ("Excellent idea! Format a string with no space for the output!\n"));
[7942]195
[83837]196 Args.pwszCur = pwszBuffer;
197 Args.cwcLeft = cwcBuffer;
[64340]198 Args.fOverflowed = false;
[1]199
[64340]200 va_start(args, pszFormat);
[83837]201 cwcRet = RTStrFormatV(rtUtf16PrintfOutput, &Args, NULL, NULL, pszFormat, args);
[64340]202 va_end(args);
203
[83837]204 return !Args.fOverflowed ? (ssize_t)cwcRet : -(ssize_t)cwcRet - 1;
[1]205}
[64340]206RT_EXPORT_SYMBOL(RTStrPrintf2);
[1]207
208
[83837]209RTDECL(ssize_t) RTUtf16PrintfExV(PFNSTRFORMAT pfnFormat, void *pvArg, PRTUTF16 pwszBuffer, size_t cwcBuffer,
210 const char *pszFormat, va_list args)
[1]211{
[83837]212 UTF16PRINTFOUTPUTARGS Args;
213 size_t cwcRet;
214 AssertMsg(cwcBuffer > 0, ("Excellent idea! Format a string with no space for the output!\n"));
[64340]215
[83837]216 Args.pwszCur = pwszBuffer;
217 Args.cwcLeft = cwcBuffer;
[64340]218 Args.fOverflowed = false;
[83837]219 cwcRet = RTStrFormatV(rtUtf16PrintfOutput, &Args, pfnFormat, pvArg, pszFormat, args);
220 return !Args.fOverflowed ? (ssize_t)cwcRet : -(ssize_t)cwcRet - 1;
[1]221}
[83837]222RT_EXPORT_SYMBOL(RTUtf16PrintfExV);
[1]223
[21337]224
[83837]225RTDECL(ssize_t) RTUtf16PrintfV(PRTUTF16 pwszBuffer, size_t cwcBuffer, const char *pszFormat, va_list args)
[1]226{
[83837]227 return RTUtf16PrintfExV(NULL, NULL, pwszBuffer, cwcBuffer, pszFormat, args);
[1]228}
[83837]229RT_EXPORT_SYMBOL(RTUtf16Printf2V);
[1]230
[21337]231
[83837]232RTDECL(ssize_t) RTUtf16PrintfEx(PFNSTRFORMAT pfnFormat, void *pvArg, PRTUTF16 pwszBuffer, size_t cwcBuffer,
233 const char *pszFormat, ...)
[1]234{
235 va_list args;
[64340]236 ssize_t cbRet;
[1]237 va_start(args, pszFormat);
[83837]238 cbRet = RTUtf16PrintfExV(pfnFormat, pvArg, pwszBuffer, cwcBuffer, pszFormat, args);
[1]239 va_end(args);
240 return cbRet;
241}
[83837]242RT_EXPORT_SYMBOL(RTUtf16PrintfEx);
[1]243
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use