VirtualBox

Changeset 28903 in vbox for trunk/src/VBox/Runtime/r3


Ignore:
Timestamp:
Apr 29, 2010 2:58:12 PM (15 years ago)
Author:
vboxsync
Message:

IPRT: iconv cache.

Location:
trunk/src/VBox/Runtime/r3
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/r3/init.cpp

    r28800 r28903  
    234234{
    235235    /*
     236     * Init C runtime locale before we do anything that may end up converting
     237     * paths or we'll end up using the "C" locale for path conversion.
     238     */
     239    setlocale(LC_CTYPE, "");
     240
     241    /*
    236242     * The Process ID.
    237243     */
     
    309315     * The remainder cannot easily be undone, so it has to go last.
    310316     */
    311 
    312     /* Init C runtime locale. */
    313     setlocale(LC_CTYPE, "");
    314317
    315318    /* Fork and exit callbacks. */
  • trunk/src/VBox/Runtime/r3/posix/utf8-posix.cpp

    r28800 r28903  
    3030*******************************************************************************/
    3131#include <iprt/string.h>
     32#include "internal/iprt.h"
     33
    3234#include <iprt/alloc.h>
    3335#include <iprt/assert.h>
     
    4042#include <wctype.h>
    4143
    42 #ifdef RT_OS_SOLARIS
    43 # include <langinfo.h>
     44#include <langinfo.h>
     45
     46#include "internal/alignmentchecks.h"
     47#ifdef RT_WITH_ICONV_CACHE
     48# include "internal/thread.h"
     49# include "internal/string.h"
     50AssertCompile(sizeof(iconv_t) <= sizeof(void *));
    4451#endif
    4552
    46 #include "internal/alignmentchecks.h"
    47 
    48 
    49 /*******************************************************************************
    50 *   Internal Functions                                                         *
    51 *******************************************************************************/
    52 static int rtstrConvert(const void *pvInput, size_t cbInput, const char *pszInputCS, void **ppvOutput, size_t cbOutput, const char *pszOutputCS, unsigned cFactor);
     53
     54/**
     55 * Gets the codeset of the current locale (LC_CTYPE).
     56 *
     57 * @returns Pointer to read-only string with the codeset name.
     58 */
     59const char *rtStrGetLocaleCodeset(void)
     60{
     61    return nl_langinfo(CODESET);
     62}
     63
     64
     65#ifdef RT_WITH_ICONV_CACHE
     66
     67/**
     68 * Initializes the iconv handle cache associated with a thread.
     69 *
     70 * @param   pThread             The thread in question.
     71 */
     72void rtStrIconvCacheInit(PRTTHREADINT pThread)
     73{
     74    for (size_t i = 0; i < RT_ELEMENTS(pThread->ahIconvs); i++)
     75        pThread->ahIconvs[i] = (iconv_t)-1;
     76}
     77
     78/**
     79 * Destroys the iconv handle cache associated with a thread.
     80 *
     81 * @param   pThread             The thread in question.
     82 */
     83void rtStrIconvCacheDestroy(PRTTHREADINT pThread)
     84{
     85    for (size_t i = 0; i < RT_ELEMENTS(pThread->ahIconvs); i++)
     86    {
     87        iconv_t hIconv = pThread->ahIconvs[i];
     88        pThread->ahIconvs[i] = NULL;
     89        if (hIconv != (iconv_t)-1)
     90            iconv_close(hIconv);
     91    }
     92}
    5393
    5494
     
    66106 * @param   pszOutputCS     Codeset of the input string.
    67107 * @param   cFactor         Input vs. output size factor.
    68  */
    69 static int rtstrConvert(const void *pvInput, size_t cbInput, const char *pszInputCS, void **ppvOutput, size_t cbOutput, const char *pszOutputCS, unsigned cFactor)
     108 * @param   phIconv         Pointer to the cache entry.
     109 */
     110static int rtstrConvertCached(const void *pvInput, size_t cbInput, const char *pszInputCS,
     111                              void **ppvOutput, size_t cbOutput, const char *pszOutputCS,
     112                              unsigned cFactor, iconv_t *phIconv)
     113{
     114    /*
     115     * Allocate buffer
     116     */
     117    bool    fUcs2Term;
     118    void   *pvOutput;
     119    size_t  cbOutput2;
     120    if (!cbOutput)
     121    {
     122        cbOutput2 = cbInput * cFactor;
     123        pvOutput = RTMemTmpAlloc(cbOutput2 + sizeof(RTUTF16));
     124        if (!pvOutput)
     125            return VERR_NO_TMP_MEMORY;
     126        fUcs2Term = true;
     127    }
     128    else
     129    {
     130        pvOutput = *ppvOutput;
     131        fUcs2Term = !strcmp(pszOutputCS, "UCS-2")
     132                 || !strcmp(pszOutputCS, "UTF-16")
     133                 || !strcmp(pszOutputCS, "ucs-2")
     134                 || !strcmp(pszOutputCS, "utf-16");
     135        cbOutput2 = cbOutput - (fUcs2Term ? sizeof(RTUTF16) : 1);
     136        if (cbOutput2 > cbOutput)
     137            return VERR_BUFFER_OVERFLOW;
     138    }
     139
     140    /*
     141     * Use a loop here to retry with bigger buffers.
     142     */
     143    for (unsigned cTries = 10; cTries > 0; cTries--)
     144    {
     145        /*
     146         * Create conversion object if necessary.
     147         */
     148        iconv_t hIconv = (iconv_t)*phIconv;
     149        if (hIconv == (iconv_t)-1)
     150        {
     151            IPRT_ALIGNMENT_CHECKS_DISABLE(); /* glibc causes trouble */
     152            *phIconv = hIconv = iconv_open(pszOutputCS, pszInputCS);
     153            IPRT_ALIGNMENT_CHECKS_ENABLE();
     154        }
     155        if (hIconv != (iconv_t)-1)
     156        {
     157            /*
     158             * Do the conversion.
     159             */
     160            size_t      cbInLeft = cbInput;
     161            size_t      cbOutLeft = cbOutput2;
     162            const void *pvInputLeft = pvInput;
     163            void       *pvOutputLeft = pvOutput;
     164#if defined(RT_OS_LINUX) || (defined(RT_OS_DARWIN) && defined(_DARWIN_FEATURE_UNIX_CONFORMANCE)) /* there are different opinions about the constness of the input buffer. */
     165            if (iconv(hIconv, (char **)&pvInputLeft, &cbInLeft, (char **)&pvOutputLeft, &cbOutLeft) != (size_t)-1)
     166#else
     167            if (iconv(hIconv, (const char **)&pvInputLeft, &cbInLeft, (char **)&pvOutputLeft, &cbOutLeft) != (size_t)-1)
     168#endif
     169            {
     170                if (!cbInLeft)
     171                {
     172                    /*
     173                     * We're done, just add the terminator and return.
     174                     * (Two terminators to support UCS-2 output, too.)
     175                     */
     176                    ((char *)pvOutputLeft)[0] = '\0';
     177                    if (fUcs2Term)
     178                        ((char *)pvOutputLeft)[1] = '\0';
     179                    *ppvOutput = pvOutput;
     180                    return VINF_SUCCESS;
     181                }
     182                errno = E2BIG;
     183            }
     184
     185            /*
     186             * If we failed because of output buffer space we'll
     187             * increase the output buffer size and retry.
     188             */
     189            if (errno == E2BIG)
     190            {
     191                if (!cbOutput)
     192                {
     193                    RTMemTmpFree(pvOutput);
     194                    cbOutput2 *= 2;
     195                    pvOutput = RTMemTmpAlloc(cbOutput2 + sizeof(RTUTF16));
     196                    if (!pvOutput)
     197                        return VERR_NO_TMP_MEMORY;
     198                    continue;
     199                }
     200                return VERR_BUFFER_OVERFLOW;
     201            }
     202
     203            /*
     204             * Close the handle on all other errors to make sure we won't carry
     205             * any bad state with us.
     206             */
     207            *phIconv = (iconv_t)-1;
     208            iconv_close(hIconv);
     209        }
     210        break;
     211    }
     212
     213    /* failure */
     214    if (!cbOutput)
     215        RTMemTmpFree(pvOutput);
     216    return VERR_NO_TRANSLATION;
     217}
     218
     219#endif /* RT_WITH_ICONV_CACHE */
     220
     221/**
     222 * Converts a string from one charset to another without using the handle cache.
     223 *
     224 * @returns IPRT status code.
     225 *
     226 * @param   pvInput         Pointer to intput string.
     227 * @param   cbInput         Size (in bytes) of input string. Excludes any terminators.
     228 * @param   pszInputCS      Codeset of the input string.
     229 * @param   ppvOutput       Pointer to pointer to output buffer if cbOutput > 0.
     230 *                          If cbOutput is 0 this is where the pointer to the allocated
     231 *                          buffer is stored.
     232 * @param   cbOutput        Size of the passed in buffer.
     233 * @param   pszOutputCS     Codeset of the input string.
     234 * @param   cFactor         Input vs. output size factor.
     235 */
     236static int rtStrConvertUncached(const void *pvInput, size_t cbInput, const char *pszInputCS,
     237                                void **ppvOutput, size_t cbOutput, const char *pszOutputCS,
     238                                unsigned cFactor)
    70239{
    71240    /*
     
    103272        /* Solaris doesn't grok empty codeset strings, so help it find the current codeset. */
    104273        if (!*pszInputCS)
    105             pszInputCS = nl_langinfo(CODESET);
     274            pszInputCS = rtStrGetLocaleCodeset();
    106275        if (!*pszOutputCS)
    107             pszOutputCS = nl_langinfo(CODESET);
     276            pszOutputCS = rtStrGetLocaleCodeset();
    108277#endif
    109278        IPRT_ALIGNMENT_CHECKS_DISABLE(); /* glibc causes trouble */
     
    171340
    172341/**
     342 * Wrapper that selects rtStrConvertCached or rtStrConvertUncached.
     343 *
     344 * @returns IPRT status code.
     345 *
     346 * @param   pszInput        Pointer to intput string.
     347 * @param   cchInput        Size (in bytes) of input string. Excludes any
     348 *                          terminators.
     349 * @param   pszInputCS      Codeset of the input string.
     350 * @param   ppszOutput      Pointer to pointer to output buffer if cbOutput > 0.
     351 *                          If cbOutput is 0 this is where the pointer to the
     352 *                          allocated buffer is stored.
     353 * @param   cbOutput        Size of the passed in buffer.
     354 * @param   pszOutputCS     Codeset of the input string.
     355 * @param   cFactor         Input vs. output size factor.
     356 * @param   enmCacheIdx     The iconv cache index.
     357 */
     358DECLINLINE(int) rtStrConvertWrapper(const char *pchInput, size_t cchInput, const char *pszInputCS,
     359                                    char **ppszOutput, size_t cbOutput, const char *pszOutputCS,
     360                                    unsigned cFactor, RTSTRICONV enmCacheIdx)
     361{
     362#ifdef RT_WITH_ICONV_CACHE
     363    RTTHREAD hSelf = RTThreadSelf();
     364    if (hSelf != NIL_RTTHREAD)
     365    {
     366        PRTTHREADINT pThread = rtThreadGet(hSelf);
     367        if (   pThread
     368            && (pThread->fIntFlags & (RTTHREADINT_FLAGS_ALIEN | RTTHREADINT_FLAGS_MAIN)) != RTTHREADINT_FLAGS_ALIEN)
     369            return rtstrConvertCached(pchInput, cchInput, pszInputCS,
     370                                      (void **)ppszOutput, cbOutput, pszOutputCS,
     371                                      cFactor, &pThread->ahIconvs[enmCacheIdx]);
     372    }
     373#endif
     374    return rtStrConvertUncached(pchInput, cchInput, pszInputCS,
     375                                (void **)ppszOutput, cbOutput, pszOutputCS,
     376                                cFactor);
     377}
     378
     379
     380/**
     381 * Internal API for use by the path conversion code.
     382 *
     383 * @returns IPRT status code.
     384 *
     385 * @param   pszInput        Pointer to intput string.
     386 * @param   cchInput        Size (in bytes) of input string. Excludes any
     387 *                          terminators.
     388 * @param   pszInputCS      Codeset of the input string.
     389 * @param   ppszOutput      Pointer to pointer to output buffer if cbOutput > 0.
     390 *                          If cbOutput is 0 this is where the pointer to the
     391 *                          allocated buffer is stored.
     392 * @param   cbOutput        Size of the passed in buffer.
     393 * @param   pszOutputCS     Codeset of the input string.
     394 * @param   cFactor         Input vs. output size factor.
     395 * @param   enmCacheIdx     The iconv cache index.
     396 */
     397int rtStrConvert(const char *pchInput, size_t cchInput, const char *pszInputCS,
     398                 char **ppszOutput, size_t cbOutput, const char *pszOutputCS,
     399                 unsigned cFactor, RTSTRICONV enmCacheIdx)
     400{
     401    Assert(enmCacheIdx >= 0 && enmCacheIdx < RTSTRICONV_END);
     402    return rtStrConvertWrapper(pchInput, cchInput, pszInputCS,
     403                               ppszOutput, cbOutput, pszOutputCS,
     404                               cFactor, enmCacheIdx);
     405}
     406
     407
     408/**
    173409 * Allocates tmp buffer, translates pszString from UTF8 to current codepage.
    174410 *
     
    196432        return VERR_NO_TMP_MEMORY;
    197433    }
    198     return rtstrConvert(pszString, cch, "UTF-8", (void **)ppszString, 0, "", 1);
     434    return rtStrConvertWrapper(pszString, cch, "UTF-8", ppszString, 0, "", 1, RTSTRICONV_UTF8_TO_LOCALE);
    199435}
    200436
     
    215451
    216452    /*
    217      * Attempt with UTF-8 length of 2x the native lenght.
     453     * Attempt with UTF-8 length of 2x the native length.
    218454     */
    219455    size_t cch = strlen(pszString);
     
    226462        return VERR_NO_TMP_MEMORY;
    227463    }
    228     return rtstrConvert(pszString, cch, "", (void **)ppszString, 0, "UTF-8", 2);
    229 }
    230 
     464    return rtStrConvertWrapper(pszString, cch, "", ppszString, 0, "UTF-8", 2, RTSTRICONV_LOCALE_TO_UTF8);
     465}
     466
Note: See TracChangeset for help on using the changeset viewer.

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