VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/posix/utf8-posix.cpp@ 95512

Last change on this file since 95512 was 93640, checked in by vboxsync, 3 years ago

Runtime: bugref:9955: Added conversion from console codepage to UTF-8 in Windows needed for proper handling the password containing national characters from console.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 22.9 KB
Line 
1/* $Id: utf8-posix.cpp 93640 2022-02-07 14:02:44Z vboxsync $ */
2/** @file
3 * IPRT - UTF-8 helpers, POSIX.
4 */
5
6/*
7 * Copyright (C) 2006-2022 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include <iprt/string.h>
32#include "internal/iprt.h"
33
34#include <iprt/alloc.h>
35#include <iprt/assert.h>
36#include <iprt/ctype.h>
37#include <iprt/err.h>
38#include <iprt/string.h>
39
40#include <errno.h>
41#include <locale.h>
42#ifdef RT_OS_DARWIN
43# include <stdlib.h>
44#endif
45
46/* iconv prototype changed with 165+ (thanks to PSARC/2010/160 Bugster 7037400) */
47#if defined(RT_OS_SOLARIS)
48# if !defined(_XPG6)
49# define IPRT_XPG6_TMP_DEF
50# define _XPG6
51# endif
52# if defined(__USE_LEGACY_PROTOTYPES__)
53# define IPRT_LEGACY_PROTO_TMP_DEF
54# undef __USE_LEGACY_PROTOTYPES__
55# endif
56#endif /* RT_OS_SOLARIS */
57
58# include <iconv.h>
59
60#if defined(RT_OS_SOLARIS)
61# if defined(IPRT_XPG6_TMP_DEF)
62# undef _XPG6
63# undef IPRT_XPG6_TMP_DEF
64# endif
65# if defined(IPRT_LEGACY_PROTO_TMP_DEF)
66# define __USE_LEGACY_PROTOTYPES__
67# undef IPRT_LEGACY_PROTO_TMP_DEF
68# endif
69#endif /* RT_OS_SOLARIS */
70
71#include <wctype.h>
72
73#include <langinfo.h>
74
75#include "internal/alignmentchecks.h"
76#include "internal/string.h"
77#ifdef RT_WITH_ICONV_CACHE
78# include "internal/thread.h"
79AssertCompile(sizeof(iconv_t) <= sizeof(void *));
80#endif
81
82
83/* There are different opinions about the constness of the input buffer. */
84#if defined(RT_OS_LINUX) || defined(RT_OS_HAIKU) || defined(RT_OS_SOLARIS) \
85 || (defined(RT_OS_DARWIN) && defined(_DARWIN_FEATURE_UNIX_CONFORMANCE))
86# define NON_CONST_ICONV_INPUT
87#endif
88#ifdef RT_OS_FREEBSD
89# include <sys/param.h>
90# if __FreeBSD_version >= 1002000 /* Changed around 10.2.2 (https://svnweb.freebsd.org/base?view=revision&revision=281550) */
91# define NON_CONST_ICONV_INPUT
92# else
93# error __FreeBSD_version__
94# endif
95#endif
96#ifdef RT_OS_NETBSD
97/* iconv constness was changed on 2019-10-24, shortly after 9.99.17 */
98# include <sys/param.h>
99# if __NetBSD_Prereq__(9,99,18)
100# define NON_CONST_ICONV_INPUT
101# endif
102#endif
103
104
105/**
106 * Gets the codeset of the current locale (LC_CTYPE).
107 *
108 * @returns Pointer to read-only string with the codeset name.
109 */
110DECLHIDDEN(const char *) rtStrGetLocaleCodeset(void)
111{
112#ifdef RT_OS_DARWIN
113 /*
114 * @bugref{10153}: If no locale specified in the environment (typically the
115 * case when launched via Finder, LaunchPad or similar) default to UTF-8.
116 */
117 static int8_t volatile s_fIsUtf8 = -1;
118 int8_t fIsUtf8 = s_fIsUtf8;
119 if (fIsUtf8)
120 {
121 if (fIsUtf8 == true)
122 return "UTF-8";
123
124 /* Initialize: */
125 fIsUtf8 = true;
126 static const char * const s_papszVariables[] = { "LC_ALL", "LC_CTYPE", "LANG" };
127 for (size_t i = 0; i < RT_ELEMENTS(s_papszVariables); i++)
128 {
129 const char *pszValue = getenv(s_papszVariables[i]);
130 if (pszValue && *pszValue)
131 {
132 fIsUtf8 = false;
133 break;
134 }
135 }
136 s_fIsUtf8 = fIsUtf8;
137 if (fIsUtf8 == true)
138 return "UTF-8";
139 }
140#endif
141 return nl_langinfo(CODESET);
142}
143
144
145/**
146 * Checks if the codeset specified by current locale (LC_CTYPE) is UTF-8.
147 *
148 * @returns true if UTF-8, false if not.
149 */
150DECLHIDDEN(bool) rtStrIsLocaleCodesetUtf8(void)
151{
152 return rtStrIsCodesetUtf8(rtStrGetLocaleCodeset());
153}
154
155
156/**
157 * Checks if @a pszCodeset specified UTF-8.
158 *
159 * @returns true if UTF-8, false if not.
160 * @param pszCodeset Codeset to test.
161 */
162DECLHIDDEN(bool) rtStrIsCodesetUtf8(const char *pszCodeset)
163{
164 if (pszCodeset)
165 {
166 /* Skip leading spaces just in case: */
167 while (RT_C_IS_SPACE(*pszCodeset))
168 pszCodeset++;
169
170 /* If prefixed by 'ISO-10646/' skip that (iconv access this, dunno about
171 LC_CTYPE et al., but play it safe): */
172 if ( strncmp(pszCodeset, RT_STR_TUPLE("ISO-10646/")) == 0
173 || strncmp(pszCodeset, RT_STR_TUPLE("iso-10646/")) == 0)
174 pszCodeset += sizeof("ISO-10646/") - 1;
175
176 /* Match 'utf': */
177 if ( (pszCodeset[0] == 'u' || pszCodeset[0] == 'U')
178 && (pszCodeset[1] == 't' || pszCodeset[1] == 'T')
179 && (pszCodeset[2] == 'f' || pszCodeset[2] == 'F'))
180 {
181 pszCodeset += 3;
182
183 /* Treat the dash as optional: */
184 if (*pszCodeset == '-')
185 pszCodeset++;
186
187 /* Match '8': */
188 if (*pszCodeset == '8')
189 {
190 do
191 pszCodeset++;
192 while (RT_C_IS_SPACE(*pszCodeset));
193
194 /* We ignore modifiers here (e.g. "[be_BY.]utf8@latin"). */
195 if (!*pszCodeset || *pszCodeset == '@')
196 return true;
197 }
198 }
199 }
200 return false;
201}
202
203
204
205#ifdef RT_WITH_ICONV_CACHE
206
207/**
208 * Initializes the iconv handle cache associated with a thread.
209 *
210 * @param pThread The thread in question.
211 */
212DECLHIDDEN(void) rtStrIconvCacheInit(PRTTHREADINT pThread)
213{
214 for (size_t i = 0; i < RT_ELEMENTS(pThread->ahIconvs); i++)
215 pThread->ahIconvs[i] = (iconv_t)-1;
216}
217
218/**
219 * Destroys the iconv handle cache associated with a thread.
220 *
221 * @param pThread The thread in question.
222 */
223DECLHIDDEN(void) rtStrIconvCacheDestroy(PRTTHREADINT pThread)
224{
225 for (size_t i = 0; i < RT_ELEMENTS(pThread->ahIconvs); i++)
226 {
227 iconv_t hIconv = (iconv_t)pThread->ahIconvs[i];
228 pThread->ahIconvs[i] = (iconv_t)-1;
229 if (hIconv != (iconv_t)-1)
230 iconv_close(hIconv);
231 }
232}
233
234
235/**
236 * Converts a string from one charset to another.
237 *
238 * @returns iprt status code.
239 * @param pvInput Pointer to intput string.
240 * @param cbInput Size (in bytes) of input string. Excludes any terminators.
241 * @param pszInputCS Codeset of the input string.
242 * @param ppvOutput Pointer to pointer to output buffer if cbOutput > 0.
243 * If cbOutput is 0 this is where the pointer to the allocated
244 * buffer is stored.
245 * @param cbOutput Size of the passed in buffer.
246 * @param pszOutputCS Codeset of the input string.
247 * @param cFactor Input vs. output size factor.
248 * @param phIconv Pointer to the cache entry.
249 */
250static int rtstrConvertCached(const void *pvInput, size_t cbInput, const char *pszInputCS,
251 void **ppvOutput, size_t cbOutput, const char *pszOutputCS,
252 unsigned cFactor, iconv_t *phIconv)
253{
254 /*
255 * Allocate buffer
256 */
257 bool fUcs2Term;
258 void *pvOutput;
259 size_t cbOutput2;
260 if (!cbOutput)
261 {
262 cbOutput2 = cbInput * cFactor;
263 pvOutput = RTMemTmpAlloc(cbOutput2 + sizeof(RTUTF16));
264 if (!pvOutput)
265 return VERR_NO_TMP_MEMORY;
266 fUcs2Term = true;
267 }
268 else
269 {
270 pvOutput = *ppvOutput;
271 fUcs2Term = !strcmp(pszOutputCS, "UCS-2")
272 || !strcmp(pszOutputCS, "UTF-16")
273 || !strcmp(pszOutputCS, "ucs-2")
274 || !strcmp(pszOutputCS, "utf-16");
275 cbOutput2 = cbOutput - (fUcs2Term ? sizeof(RTUTF16) : 1);
276 if (cbOutput2 > cbOutput)
277 return VERR_BUFFER_OVERFLOW;
278 }
279
280 /*
281 * Use a loop here to retry with bigger buffers.
282 */
283 for (unsigned cTries = 10; cTries > 0; cTries--)
284 {
285 /*
286 * Create conversion object if necessary.
287 */
288 iconv_t hIconv = (iconv_t)*phIconv;
289 if (hIconv == (iconv_t)-1)
290 {
291#if defined(RT_OS_SOLARIS) || defined(RT_OS_NETBSD) || /* @bugref{10153}: Default to UTF-8: */ defined(RT_OS_DARWIN)
292 /* Some systems don't grok empty codeset strings, so help them find the current codeset. */
293 if (!*pszInputCS)
294 pszInputCS = rtStrGetLocaleCodeset();
295 if (!*pszOutputCS)
296 pszOutputCS = rtStrGetLocaleCodeset();
297#endif
298 IPRT_ALIGNMENT_CHECKS_DISABLE(); /* glibc causes trouble */
299 *phIconv = hIconv = iconv_open(pszOutputCS, pszInputCS);
300 IPRT_ALIGNMENT_CHECKS_ENABLE();
301 }
302 if (hIconv != (iconv_t)-1)
303 {
304 /*
305 * Do the conversion.
306 */
307 size_t cbInLeft = cbInput;
308 size_t cbOutLeft = cbOutput2;
309 const void *pvInputLeft = pvInput;
310 void *pvOutputLeft = pvOutput;
311 size_t cchNonRev;
312#ifdef NON_CONST_ICONV_INPUT
313 cchNonRev = iconv(hIconv, (char **)&pvInputLeft, &cbInLeft, (char **)&pvOutputLeft, &cbOutLeft);
314#else
315 cchNonRev = iconv(hIconv, (const char **)&pvInputLeft, &cbInLeft, (char **)&pvOutputLeft, &cbOutLeft);
316#endif
317 if (cchNonRev != (size_t)-1)
318 {
319 if (!cbInLeft)
320 {
321 /*
322 * We're done, just add the terminator and return.
323 * (Two terminators to support UCS-2 output, too.)
324 */
325 ((char *)pvOutputLeft)[0] = '\0';
326 if (fUcs2Term)
327 ((char *)pvOutputLeft)[1] = '\0';
328 *ppvOutput = pvOutput;
329 if (cchNonRev == 0)
330 return VINF_SUCCESS;
331 return VWRN_NO_TRANSLATION;
332 }
333 errno = E2BIG;
334 }
335
336 /*
337 * If we failed because of output buffer space we'll
338 * increase the output buffer size and retry.
339 */
340 if (errno == E2BIG)
341 {
342 if (!cbOutput)
343 {
344 RTMemTmpFree(pvOutput);
345 cbOutput2 *= 2;
346 pvOutput = RTMemTmpAlloc(cbOutput2 + sizeof(RTUTF16));
347 if (!pvOutput)
348 return VERR_NO_TMP_MEMORY;
349 continue;
350 }
351 return VERR_BUFFER_OVERFLOW;
352 }
353
354 /*
355 * Close the handle on all other errors to make sure we won't carry
356 * any bad state with us.
357 */
358 *phIconv = (iconv_t)-1;
359 iconv_close(hIconv);
360 }
361 break;
362 }
363
364 /* failure */
365 if (!cbOutput)
366 RTMemTmpFree(pvOutput);
367 return VERR_NO_TRANSLATION;
368}
369
370#endif /* RT_WITH_ICONV_CACHE */
371
372/**
373 * Converts a string from one charset to another without using the handle cache.
374 *
375 * @returns IPRT status code.
376 *
377 * @param pvInput Pointer to intput string.
378 * @param cbInput Size (in bytes) of input string. Excludes any terminators.
379 * @param pszInputCS Codeset of the input string.
380 * @param ppvOutput Pointer to pointer to output buffer if cbOutput > 0.
381 * If cbOutput is 0 this is where the pointer to the allocated
382 * buffer is stored.
383 * @param cbOutput Size of the passed in buffer.
384 * @param pszOutputCS Codeset of the input string.
385 * @param cFactor Input vs. output size factor.
386 */
387static int rtStrConvertUncached(const void *pvInput, size_t cbInput, const char *pszInputCS,
388 void **ppvOutput, size_t cbOutput, const char *pszOutputCS,
389 unsigned cFactor)
390{
391 /*
392 * Allocate buffer
393 */
394 bool fUcs2Term;
395 void *pvOutput;
396 size_t cbOutput2;
397 if (!cbOutput)
398 {
399 cbOutput2 = cbInput * cFactor;
400 pvOutput = RTMemTmpAlloc(cbOutput2 + sizeof(RTUTF16));
401 if (!pvOutput)
402 return VERR_NO_TMP_MEMORY;
403 fUcs2Term = true;
404 }
405 else
406 {
407 pvOutput = *ppvOutput;
408 fUcs2Term = !strcmp(pszOutputCS, "UCS-2");
409 cbOutput2 = cbOutput - (fUcs2Term ? sizeof(RTUTF16) : 1);
410 if (cbOutput2 > cbOutput)
411 return VERR_BUFFER_OVERFLOW;
412 }
413
414 /*
415 * Use a loop here to retry with bigger buffers.
416 */
417 for (unsigned cTries = 10; cTries > 0; cTries--)
418 {
419 /*
420 * Create conversion object.
421 */
422#if defined(RT_OS_SOLARIS) || defined(RT_OS_NETBSD) || /* @bugref{10153}: Default to UTF-8: */ defined(RT_OS_DARWIN)
423 /* Some systems don't grok empty codeset strings, so help them find the current codeset. */
424 if (!*pszInputCS)
425 pszInputCS = rtStrGetLocaleCodeset();
426 if (!*pszOutputCS)
427 pszOutputCS = rtStrGetLocaleCodeset();
428#endif
429 IPRT_ALIGNMENT_CHECKS_DISABLE(); /* glibc causes trouble */
430 iconv_t icHandle = iconv_open(pszOutputCS, pszInputCS);
431 IPRT_ALIGNMENT_CHECKS_ENABLE();
432 if (icHandle != (iconv_t)-1)
433 {
434 /*
435 * Do the conversion.
436 */
437 size_t cbInLeft = cbInput;
438 size_t cbOutLeft = cbOutput2;
439 const void *pvInputLeft = pvInput;
440 void *pvOutputLeft = pvOutput;
441 size_t cchNonRev;
442#ifdef NON_CONST_ICONV_INPUT
443 cchNonRev = iconv(icHandle, (char **)&pvInputLeft, &cbInLeft, (char **)&pvOutputLeft, &cbOutLeft);
444#else
445 cchNonRev = iconv(icHandle, (const char **)&pvInputLeft, &cbInLeft, (char **)&pvOutputLeft, &cbOutLeft);
446#endif
447 if (cchNonRev != (size_t)-1)
448 {
449 if (!cbInLeft)
450 {
451 /*
452 * We're done, just add the terminator and return.
453 * (Two terminators to support UCS-2 output, too.)
454 */
455 iconv_close(icHandle);
456 ((char *)pvOutputLeft)[0] = '\0';
457 if (fUcs2Term)
458 ((char *)pvOutputLeft)[1] = '\0';
459 *ppvOutput = pvOutput;
460 if (cchNonRev == 0)
461 return VINF_SUCCESS;
462 return VWRN_NO_TRANSLATION;
463 }
464 errno = E2BIG;
465 }
466 iconv_close(icHandle);
467
468 /*
469 * If we failed because of output buffer space we'll
470 * increase the output buffer size and retry.
471 */
472 if (errno == E2BIG)
473 {
474 if (!cbOutput)
475 {
476 RTMemTmpFree(pvOutput);
477 cbOutput2 *= 2;
478 pvOutput = RTMemTmpAlloc(cbOutput2 + sizeof(RTUTF16));
479 if (!pvOutput)
480 return VERR_NO_TMP_MEMORY;
481 continue;
482 }
483 return VERR_BUFFER_OVERFLOW;
484 }
485 }
486 break;
487 }
488
489 /* failure */
490 if (!cbOutput)
491 RTMemTmpFree(pvOutput);
492 return VERR_NO_TRANSLATION;
493}
494
495
496/**
497 * Wrapper that selects rtStrConvertCached or rtStrConvertUncached.
498 *
499 * @returns IPRT status code.
500 *
501 * @param pszInput Pointer to intput string.
502 * @param cchInput Size (in bytes) of input string. Excludes any
503 * terminators.
504 * @param pszInputCS Codeset of the input string.
505 * @param ppszOutput Pointer to pointer to output buffer if cbOutput > 0.
506 * If cbOutput is 0 this is where the pointer to the
507 * allocated buffer is stored.
508 * @param cbOutput Size of the passed in buffer.
509 * @param pszOutputCS Codeset of the input string.
510 * @param cFactor Input vs. output size factor.
511 * @param enmCacheIdx The iconv cache index.
512 */
513DECLINLINE(int) rtStrConvertWrapper(const char *pchInput, size_t cchInput, const char *pszInputCS,
514 char **ppszOutput, size_t cbOutput, const char *pszOutputCS,
515 unsigned cFactor, RTSTRICONV enmCacheIdx)
516{
517#ifdef RT_WITH_ICONV_CACHE
518 RTTHREAD hSelf = RTThreadSelf();
519 if (hSelf != NIL_RTTHREAD)
520 {
521 PRTTHREADINT pThread = rtThreadGet(hSelf);
522 if (pThread)
523 {
524 if ((pThread->fIntFlags & (RTTHREADINT_FLAGS_ALIEN | RTTHREADINT_FLAGS_MAIN)) != RTTHREADINT_FLAGS_ALIEN)
525 {
526 int rc = rtstrConvertCached(pchInput, cchInput, pszInputCS,
527 (void **)ppszOutput, cbOutput, pszOutputCS,
528 cFactor, (iconv_t *)&pThread->ahIconvs[enmCacheIdx]);
529 rtThreadRelease(pThread);
530 return rc;
531 }
532 rtThreadRelease(pThread);
533 }
534 }
535#endif
536 return rtStrConvertUncached(pchInput, cchInput, pszInputCS,
537 (void **)ppszOutput, cbOutput, pszOutputCS,
538 cFactor);
539}
540
541
542/**
543 * Internal API for use by the path conversion code.
544 *
545 * @returns IPRT status code.
546 *
547 * @param pszInput Pointer to intput string.
548 * @param cchInput Size (in bytes) of input string. Excludes any
549 * terminators.
550 * @param pszInputCS Codeset of the input string.
551 * @param ppszOutput Pointer to pointer to output buffer if cbOutput > 0.
552 * If cbOutput is 0 this is where the pointer to the
553 * allocated buffer is stored.
554 * @param cbOutput Size of the passed in buffer.
555 * @param pszOutputCS Codeset of the input string.
556 * @param cFactor Input vs. output size factor.
557 * @param enmCacheIdx The iconv cache index.
558 */
559DECLHIDDEN(int) rtStrConvert(const char *pchInput, size_t cchInput, const char *pszInputCS,
560 char **ppszOutput, size_t cbOutput, const char *pszOutputCS,
561 unsigned cFactor, RTSTRICONV enmCacheIdx)
562{
563 Assert(enmCacheIdx >= 0 && enmCacheIdx < RTSTRICONV_END);
564 return rtStrConvertWrapper(pchInput, cchInput, pszInputCS,
565 ppszOutput, cbOutput, pszOutputCS,
566 cFactor, enmCacheIdx);
567}
568
569
570/**
571 * Initializes a local conversion cache for use with rtStrLocalCacheConvert.
572 *
573 * Call rtStrLocalCacheDelete when done.
574 */
575DECLHIDDEN(void) rtStrLocalCacheInit(void **ppvTmpCache)
576{
577 *ppvTmpCache = (iconv_t)-1;
578}
579
580
581/**
582 * Cleans up a local conversion cache.
583 */
584DECLHIDDEN(void) rtStrLocalCacheDelete(void **ppvTmpCache)
585{
586#ifdef RT_WITH_ICONV_CACHE
587 iconv_t icHandle = (iconv_t)*ppvTmpCache;
588 if (icHandle != (iconv_t)-1)
589 iconv_close(icHandle);
590#endif
591 *ppvTmpCache = (iconv_t)-1;
592}
593
594
595/**
596 * Internal API for use by the process creation conversion code.
597 *
598 * @returns IPRT status code.
599 *
600 * @param pszInput Pointer to intput string.
601 * @param cchInput Size (in bytes) of input string. Excludes any
602 * terminators.
603 * @param pszInputCS Codeset of the input string.
604 * @param ppszOutput Pointer to pointer to output buffer if cbOutput > 0.
605 * If cbOutput is 0 this is where the pointer to the
606 * allocated buffer is stored.
607 * @param cbOutput Size of the passed in buffer.
608 * @param pszOutputCS Codeset of the input string.
609 * @param ppvTmpCache Pointer to local temporary cache. Must be
610 * initialized by calling rtStrLocalCacheInit and
611 * cleaned up afterwards by rtStrLocalCacheDelete.
612 * Optional.
613 */
614DECLHIDDEN(int) rtStrLocalCacheConvert(const char *pchInput, size_t cchInput, const char *pszInputCS,
615 char **ppszOutput, size_t cbOutput, const char *pszOutputCS,
616 void **ppvTmpCache)
617{
618#ifdef RT_WITH_ICONV_CACHE
619 if (ppvTmpCache)
620 return rtstrConvertCached(pchInput, cchInput, pszInputCS, (void **)ppszOutput, cbOutput, pszOutputCS,
621 1 /*cFactor*/, (iconv_t *)ppvTmpCache);
622#else
623 RT_NOREF(ppvTmpCache);
624#endif
625
626 return rtStrConvertUncached(pchInput, cchInput, pszInputCS, (void **)ppszOutput, cbOutput, pszOutputCS, 1 /*cFactor*/);
627}
628
629
630RTR3DECL(int) RTStrUtf8ToCurrentCPTag(char **ppszString, const char *pszString, const char *pszTag)
631{
632 Assert(ppszString);
633 Assert(pszString);
634 *ppszString = NULL;
635
636 /*
637 * Assume result string length is not longer than UTF-8 string.
638 */
639 size_t cch = strlen(pszString);
640 if (cch <= 0)
641 {
642 /* zero length string passed. */
643 *ppszString = (char *)RTMemTmpAllocZTag(sizeof(char), pszTag);
644 if (*ppszString)
645 return VINF_SUCCESS;
646 return VERR_NO_TMP_MEMORY;
647 }
648 return rtStrConvertWrapper(pszString, cch, "UTF-8", ppszString, 0, "", 1, RTSTRICONV_UTF8_TO_LOCALE);
649}
650
651
652RTR3DECL(int) RTStrUtf8ToCurrentCPExTag(char **ppszString, const char *pszString, size_t cchString, const char *pszTag)
653{
654 Assert(ppszString);
655 Assert(pszString);
656 *ppszString = NULL;
657
658 /*
659 * Assume result string length is not longer than UTF-8 string.
660 */
661 cchString = RTStrNLen(pszString, cchString);
662 if (cchString < 1)
663 {
664 /* zero length string passed. */
665 *ppszString = (char *)RTMemTmpAllocZTag(sizeof(char), pszTag);
666 if (*ppszString)
667 return VINF_SUCCESS;
668 return VERR_NO_TMP_MEMORY;
669 }
670 return rtStrConvertWrapper(pszString, cchString, "UTF-8", ppszString, 0, "", 1, RTSTRICONV_UTF8_TO_LOCALE);
671}
672
673
674RTR3DECL(int) RTStrCurrentCPToUtf8Tag(char **ppszString, const char *pszString, const char *pszTag)
675{
676 Assert(ppszString);
677 Assert(pszString);
678 *ppszString = NULL;
679
680 /*
681 * Attempt with UTF-8 length of 2x the native length.
682 */
683 size_t cch = strlen(pszString);
684 if (cch <= 0)
685 {
686 /* zero length string passed. */
687 *ppszString = (char *)RTMemTmpAllocZTag(sizeof(char), pszTag);
688 if (*ppszString)
689 return VINF_SUCCESS;
690 return VERR_NO_TMP_MEMORY;
691 }
692 return rtStrConvertWrapper(pszString, cch, "", ppszString, 0, "UTF-8", 2, RTSTRICONV_LOCALE_TO_UTF8);
693}
694
695
696RTR3DECL(int) RTStrConsoleCPToUtf8Tag(char **ppszString, const char *pszString, const char *pszTag)
697{
698 return RTStrCurrentCPToUtf8Tag(ppszString, pszString, pszTag);
699}
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