VirtualBox

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

Last change on this file since 106455 was 106061, checked in by vboxsync, 3 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
Line 
1/* $Id: utf-16-printf.cpp 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * IPRT - String Formatters, Outputting UTF-16.
4 */
5
6/*
7 * Copyright (C) 2006-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
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 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
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
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.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#include <iprt/utf16.h>
42#include "internal/iprt.h"
43
44#include <iprt/assert.h>
45#include <iprt/string.h>
46#include <iprt/uni.h>
47
48
49/*********************************************************************************************************************************
50* Structures and Typedefs *
51*********************************************************************************************************************************/
52/** rtUtf16PrintfOutput() argument structure. */
53typedef struct UTF16PRINTFOUTPUTARGS
54{
55 /** Pointer to current buffer position. */
56 PRTUTF16 pwszCur;
57 /** Number of RTUTF16 units left in the buffer (including the trailing zero). */
58 size_t cwcLeft;
59 /** Set if we overflowed. */
60 bool fOverflowed;
61} UTF16PRINTFOUTPUTARGS;
62/** Pointer to a rtUtf16PrintfOutput() argument structure. */
63typedef UTF16PRINTFOUTPUTARGS *PUTF16PRINTFOUTPUTARGS;
64
65
66/**
67 * Output callback.
68 *
69 * @returns Number of RTUTF16 units we (would have) outputted.
70 *
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 */
75static DECLCALLBACK(size_t) rtUtf16PrintfOutput(void *pvArg, const char *pachChars, size_t cbChars)
76{
77 PUTF16PRINTFOUTPUTARGS pArgs = (PUTF16PRINTFOUTPUTARGS)pvArg;
78 size_t cwcRet = 0;
79
80 size_t cwcLeft = pArgs->cwcLeft;
81 if (cwcLeft > 1)
82 {
83 Assert(!pArgs->fOverflowed);
84
85 PRTUTF16 pwszCur = pArgs->pwszCur;
86 for (;;)
87 {
88 if (cbChars > 0)
89 {
90 RTUNICP uc;
91 int rc = RTStrGetCpNEx(&pachChars, &cbChars, &uc);
92 AssertRCStmt(rc, uc = 0xfffd /* REPLACEMENT */);
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))
127 *pwszCur++ = 0xfffd; /* REPLACEMENT */
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 }
140 }
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;
149 }
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)
157 {
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);
171 AssertRCStmt(rc, uc = 0xfffd /* REPLACEMENT */);
172
173 if (RTUniCpIsBMP(uc))
174 cwcRet += 1;
175 else if (uc >= 0x10000 && uc <= 0x0010ffff)
176 cwcRet += 2;
177 else
178 {
179 AssertMsgFailed(("uc=%#x\n", uc));
180 cwcRet += 1;
181 }
182 }
183
184 return cwcRet;
185}
186
187
188RTDECL(ssize_t) RTUtf16Printf(PRTUTF16 pwszBuffer, size_t cwcBuffer, const char *pszFormat, ...)
189{
190 /* Explicitly inline RTStrPrintfV + RTStrPrintfExV here because this is a frequently use API. */
191 UTF16PRINTFOUTPUTARGS Args;
192 size_t cwcRet;
193 va_list args;
194 AssertMsg(cwcBuffer > 0, ("Excellent idea! Format a string with no space for the output!\n"));
195
196 Args.pwszCur = pwszBuffer;
197 Args.cwcLeft = cwcBuffer;
198 Args.fOverflowed = false;
199
200 va_start(args, pszFormat);
201 cwcRet = RTStrFormatV(rtUtf16PrintfOutput, &Args, NULL, NULL, pszFormat, args);
202 va_end(args);
203
204 return !Args.fOverflowed ? (ssize_t)cwcRet : -(ssize_t)cwcRet - 1;
205}
206RT_EXPORT_SYMBOL(RTStrPrintf2);
207
208
209RTDECL(ssize_t) RTUtf16PrintfExV(PFNSTRFORMAT pfnFormat, void *pvArg, PRTUTF16 pwszBuffer, size_t cwcBuffer,
210 const char *pszFormat, va_list args)
211{
212 UTF16PRINTFOUTPUTARGS Args;
213 size_t cwcRet;
214 AssertMsg(cwcBuffer > 0, ("Excellent idea! Format a string with no space for the output!\n"));
215
216 Args.pwszCur = pwszBuffer;
217 Args.cwcLeft = cwcBuffer;
218 Args.fOverflowed = false;
219 cwcRet = RTStrFormatV(rtUtf16PrintfOutput, &Args, pfnFormat, pvArg, pszFormat, args);
220 return !Args.fOverflowed ? (ssize_t)cwcRet : -(ssize_t)cwcRet - 1;
221}
222RT_EXPORT_SYMBOL(RTUtf16PrintfExV);
223
224
225RTDECL(ssize_t) RTUtf16PrintfV(PRTUTF16 pwszBuffer, size_t cwcBuffer, const char *pszFormat, va_list args)
226{
227 return RTUtf16PrintfExV(NULL, NULL, pwszBuffer, cwcBuffer, pszFormat, args);
228}
229RT_EXPORT_SYMBOL(RTUtf16Printf2V);
230
231
232RTDECL(ssize_t) RTUtf16PrintfEx(PFNSTRFORMAT pfnFormat, void *pvArg, PRTUTF16 pwszBuffer, size_t cwcBuffer,
233 const char *pszFormat, ...)
234{
235 va_list args;
236 ssize_t cbRet;
237 va_start(args, pszFormat);
238 cbRet = RTUtf16PrintfExV(pfnFormat, pvArg, pwszBuffer, cwcBuffer, pszFormat, args);
239 va_end(args);
240 return cbRet;
241}
242RT_EXPORT_SYMBOL(RTUtf16PrintfEx);
243
Note: See TracBrowser for help on using the repository browser.

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