VirtualBox

Changeset 38658 in vbox


Ignore:
Timestamp:
Sep 6, 2011 2:22:53 PM (13 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
73870
Message:

IPRT: , and are now deprecated, the conversion to local codeset being moved to the streams (RTPrintf / RTStrmPrintf). Adding special detection of the windows console and talk UTF-16 to it in order to avoid lost-in-translation issues when its codepage differs from the active codepage of the process.

Location:
trunk
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/iprt/string.h

    r37964 r38658  
    14511451 *      - \%ls  - Same as \%s except that the input is UTF-16 (output UTF-8).
    14521452 *      - \%Ls  - Same as \%s except that the input is UCS-32 (output UTF-8).
    1453  *      - \%S   - R3: Same as \%s except it is printed in the current codeset
    1454  *                instead of UTF-8 (source is still UTF-8).
    1455  *                Other contexts: Same as \%s.
    1456  *      - \%lS  - Same as \%S except that the input is UTF-16 (output current
    1457  *                codeset).
    1458  *      - \%LS  - Same as \%S except that the input is UCS-32 (output current
    1459  *                codeset).
     1453 *      - \%S   - Same as \%s, used to convert to current codeset but this is
     1454 *                now done by the streams code.  Deprecated, use \%s.
     1455 *      - \%lS  - Ditto. Deprecated, use \%ls.
     1456 *      - \%LS  - Ditto. Deprecated, use \%Ls.
    14601457 *      - \%c   - Takes a char and prints it.
    14611458 *      - \%d   - Takes a signed integer and prints it as decimal. Thousand
  • trunk/src/VBox/Runtime/common/string/strformat.cpp

    r33540 r38658  
    483483                    }
    484484
    485 #ifndef IN_RING3
    486                     case 'S':   /* Unicode string as current code page -> Unicode as UTF-8 in GC/R0. */
    487                         chArgSize = 'l'; /** @todo this is nonsensical, isn't it? */
    488                         /* fall thru */
    489 #endif
    490                     case 's':   /* Unicode string as utf8 */
     485                    case 'S':   /* Legacy, conversion done by streams now. */
     486                    case 's':
    491487                    {
    492488                        if (chArgSize == 'l')
     
    508504                            while (cchStr-- > 0)
    509505                            {
    510 #ifdef IN_RING3
     506#ifndef IN_RC
    511507                                RTUNICP Cp;
    512508                                RTUtf16GetCpEx(&pwszStr, &Cp);
     
    541537                            while (cchStr-- > 0)
    542538                            {
    543 #ifdef IN_RING3
     539#ifndef IN_RC
    544540                                char szUtf8[8]; /* Cp=0x7fffffff -> 6 bytes. */
    545541                                char *pszEnd = RTStrPutCp(szUtf8, *puszStr++);
     
    572568                        break;
    573569                    }
    574 
    575 #ifdef IN_RING3
    576                     case 'S':   /* Unicode string as current code page. */
    577                     {
    578                         if (chArgSize == 'l')
    579                         {
    580                             /* UTF-16 */
    581                             int       cchStr;
    582                             PCRTUTF16 pwsz2Str = va_arg(args, PRTUTF16);
    583                             if (!VALID_PTR(pwsz2Str))
    584                             {
    585                                 static RTUTF16  s_wsz2Null[] = {'<', 'N', 'U', 'L', 'L', '>', '\0' };
    586                                 pwsz2Str = s_wsz2Null;
    587                             }
    588 
    589                             cchStr = _strnlenUtf16(pwsz2Str, (unsigned)cchPrecision);
    590                             if (!(fFlags & RTSTR_F_LEFT))
    591                                 while (--cchWidth >= cchStr)
    592                                     cch += pfnOutput(pvArgOutput, " ", 1);
    593 
    594                             if (cchStr)
    595                             {
    596                                 /* allocate temporary buffer. */
    597                                 PRTUTF16 pwsz2Tmp = (PRTUTF16)RTMemTmpAlloc((cchStr + 1) * sizeof(RTUTF16));
    598                                 memcpy(pwsz2Tmp, pwsz2Str, cchStr * sizeof(RTUTF16));
    599                                 pwsz2Tmp[cchStr] = '\0';
    600 
    601                                 char *pszUtf8;
    602                                 int rc = RTUtf16ToUtf8(pwsz2Tmp, &pszUtf8);
    603                                 if (RT_SUCCESS(rc))
    604                                 {
    605                                     char *pszCurCp;
    606                                     rc = RTStrUtf8ToCurrentCP(&pszCurCp, pszUtf8);
    607                                     if (RT_SUCCESS(rc))
    608                                     {
    609                                         cch += pfnOutput(pvArgOutput, pszCurCp, strlen(pszCurCp));
    610                                         RTStrFree(pszCurCp);
    611                                     }
    612                                     RTStrFree(pszUtf8);
    613                                 }
    614                                 if (RT_FAILURE(rc))
    615                                     while (cchStr-- > 0)
    616                                         cch += pfnOutput(pvArgOutput, "\x7f", 1);
    617                                 RTMemTmpFree(pwsz2Tmp);
    618                             }
    619 
    620                             while (--cchWidth >= cchStr)
    621                                 cch += pfnOutput(pvArgOutput, " ", 1);
    622                         }
    623                         else if (chArgSize == 'L')
    624                         {
    625                             /* UCS-32 */
    626                             AssertMsgFailed(("Not implemented yet\n"));
    627                         }
    628                         else
    629                         {
    630                             /* UTF-8 */
    631                             int   cchStr;
    632                             const char *pszStr = va_arg(args, char *);
    633 
    634                             if (!VALID_PTR(pszStr))
    635                                 pszStr = "<NULL>";
    636                             cchStr = _strnlen(pszStr, (unsigned)cchPrecision);
    637                             if (!(fFlags & RTSTR_F_LEFT))
    638                                 while (--cchWidth >= cchStr)
    639                                     cch += pfnOutput(pvArgOutput, " ", 1);
    640 
    641                             if (cchStr)
    642                             {
    643                                 /* allocate temporary buffer. */
    644                                 char *pszTmp = (char *)RTMemTmpAlloc(cchStr + 1);
    645                                 memcpy(pszTmp, pszStr, cchStr);
    646                                 pszTmp[cchStr] = '\0';
    647 
    648                                 char *pszCurCp;
    649                                 int rc = RTStrUtf8ToCurrentCP(&pszCurCp, pszTmp);
    650                                 if (RT_SUCCESS(rc))
    651                                 {
    652                                     cch += pfnOutput(pvArgOutput, pszCurCp, strlen(pszCurCp));
    653                                     RTStrFree(pszCurCp);
    654                                 }
    655                                 else
    656                                     while (cchStr-- > 0)
    657                                         cch += pfnOutput(pvArgOutput, "\x7f", 1);
    658                                 RTMemTmpFree(pszTmp);
    659                             }
    660 
    661                             while (--cchWidth >= cchStr)
    662                                 cch += pfnOutput(pvArgOutput, " ", 1);
    663                         }
    664                         break;
    665                     }
    666 #endif
    667 
    668570
    669571                    /*-----------------*/
  • trunk/src/VBox/Runtime/r3/init.cpp

    r38639 r38658  
    3434#ifdef RT_OS_WINDOWS
    3535# include <process.h>
    36 # include <Windows.h>
    3736#else
    3837# include <unistd.h>
     
    318317    setlocale(LC_CTYPE, "");
    319318
    320 #ifdef RT_OS_WINDOWS
    321     /*
    322      * On windows, make sure we talk CP_ACP to the console. It frequently uses
    323      * a different code page, which would cause %[lL]S to fail.
    324      */
    325     if (!(fFlags & RTR3INIT_FLAGS_DLL))
    326     {
    327         SetConsoleCP(GetACP());
    328         SetConsoleOutputCP(GetACP());
    329     }
    330 #endif
    331 
    332319    /*
    333320     * The Process ID.
  • trunk/src/VBox/Runtime/r3/stream.cpp

    r32464 r38658  
    5353#include <stdio.h>
    5454#include <errno.h>
     55#ifdef RT_OS_WINDOWS
     56# include <io.h>
     57# include <fcntl.h>
     58# include <Windows.h>
     59#endif
    5560
    5661
     
    6974    /** Pointer to the LIBC file stream. */
    7075    FILE               *pFile;
     76    /** Stream is using the current process code set. */
     77    bool                fCurrentCodeSet;
     78    /** Whether the stream was opened in binary mode. */
     79    bool                fBinary;
     80    /** Whether to recheck the stream mode before writing.. */
     81    bool                fRecheckMode;
    7182#ifndef HAVE_FWRITE_UNLOCKED
    7283    /** Critical section for serializing access to the stream. */
     
    8495    RTSTREAM_MAGIC,
    8596    0,
    86     stdin
     97    stdin,
     98    true,
     99    /*.fBinary = */ false,
     100    /*.fRecheckMode = */ true
    87101#ifndef HAVE_FWRITE_UNLOCKED
    88102    , NULL
     
    95109    RTSTREAM_MAGIC,
    96110    0,
    97     stderr
     111    stderr,
     112    true,
     113    /*.fBinary = */ false,
     114    /*.fRecheckMode = */ true
    98115#ifndef HAVE_FWRITE_UNLOCKED
    99116    , NULL
     
    106123    RTSTREAM_MAGIC,
    107124    0,
    108     stdout
     125    stdout,
     126    true,
     127    /*.fBinary = */ false,
     128    /*.fRecheckMode = */ true
    109129#ifndef HAVE_FWRITE_UNLOCKED
    110130    , NULL
     
    223243    }
    224244    bool fOk = true;
     245    bool fBinary = false;
    225246    switch (*pszMode)
    226247    {
     
    232253                case '\0':
    233254                    break;
     255
    234256                case '+':
    235257                    switch (pszMode[2])
    236258                    {
    237259                        case '\0':
     260                            break;
     261
    238262                        //case 't':
     263                        //    break;
     264
    239265                        case 'b':
     266                            fBinary = true;
    240267                            break;
     268
    241269                        default:
    242270                            fOk = false;
     
    244272                    }
    245273                    break;
     274
    246275                //case 't':
     276                //    break;
     277
    247278                case 'b':
     279                    fBinary = true;
    248280                    break;
     281
    249282                default:
    250283                    fOk = false;
     
    270303        pStream->u32Magic = RTSTREAM_MAGIC;
    271304        pStream->i32Error = VINF_SUCCESS;
     305        pStream->fCurrentCodeSet = false;
     306        pStream->fBinary  = fBinary;
    272307#ifndef HAVE_FWRITE_UNLOCKED
    273308        pStream->pCritSect = NULL;
     
    339374RTR3DECL(int) RTStrmClose(PRTSTREAM pStream)
    340375{
    341     if (pStream && pStream->u32Magic == RTSTREAM_MAGIC)
    342     {
    343         if (!fclose(pStream->pFile))
     376    if (!pStream)
     377        return VINF_SUCCESS;
     378    AssertReturn(RT_VALID_PTR(pStream) && pStream->u32Magic == RTSTREAM_MAGIC, VERR_INVALID_PARAMETER);
     379
     380    if (!fclose(pStream->pFile))
     381    {
     382        pStream->u32Magic = 0xdeaddead;
     383        pStream->pFile = NULL;
     384#ifndef HAVE_FWRITE_UNLOCKED
     385        if (pStream->pCritSect)
    344386        {
    345             pStream->u32Magic = 0xdeaddead;
    346             pStream->pFile = NULL;
    347 #ifndef HAVE_FWRITE_UNLOCKED
    348             if (pStream->pCritSect)
    349             {
    350                 RTCritSectEnter(pStream->pCritSect);
    351                 RTCritSectLeave(pStream->pCritSect);
    352                 RTCritSectDelete(pStream->pCritSect);
    353                 RTMemFree(pStream->pCritSect);
    354                 pStream->pCritSect = NULL;
    355             }
    356 #endif
    357             RTMemFree(pStream);
    358             return VINF_SUCCESS;
     387            RTCritSectEnter(pStream->pCritSect);
     388            RTCritSectLeave(pStream->pCritSect);
     389            RTCritSectDelete(pStream->pCritSect);
     390            RTMemFree(pStream->pCritSect);
     391            pStream->pCritSect = NULL;
    359392        }
    360 
    361         return RTErrConvertFromErrno(errno);
    362     }
    363     else
    364     {
    365         AssertMsgFailed(("Invalid stream!\n"));
    366         return VERR_INVALID_PARAMETER;
    367     }
     393#endif
     394        RTMemFree(pStream);
     395        return VINF_SUCCESS;
     396    }
     397
     398    return RTErrConvertFromErrno(errno);
    368399}
    369400
     
    377408RTR3DECL(int) RTStrmError(PRTSTREAM pStream)
    378409{
    379     int rc;
    380     if (pStream && pStream->u32Magic == RTSTREAM_MAGIC)
    381         rc = pStream->i32Error;
    382     else
    383     {
    384         AssertMsgFailed(("Invalid stream!\n"));
    385         rc = VERR_INVALID_PARAMETER;
    386     }
    387     return rc;
     410    AssertReturn(RT_VALID_PTR(pStream) && pStream->u32Magic == RTSTREAM_MAGIC, VERR_INVALID_PARAMETER);
     411    return pStream->i32Error;
    388412}
    389413
     
    400424RTR3DECL(int) RTStrmClearError(PRTSTREAM pStream)
    401425{
    402     int rc;
    403     if (pStream && pStream->u32Magic == RTSTREAM_MAGIC)
    404     {
    405         clearerr(pStream->pFile);
    406         ASMAtomicXchgS32(&pStream->i32Error, VINF_SUCCESS);
    407         rc = VINF_SUCCESS;
    408     }
    409     else
    410     {
    411         AssertMsgFailed(("Invalid stream!\n"));
    412         rc = VERR_INVALID_PARAMETER;
    413     }
    414     return rc;
     426    AssertReturn(RT_VALID_PTR(pStream) && pStream->u32Magic == RTSTREAM_MAGIC, VERR_INVALID_PARAMETER);
     427
     428    clearerr(pStream->pFile);
     429    ASMAtomicWriteS32(&pStream->i32Error, VINF_SUCCESS);
     430    return VINF_SUCCESS;
    415431}
    416432
     
    438454    if (!fseek(pStream->pFile, 0, SEEK_SET))
    439455    {
    440         ASMAtomicXchgS32(&pStream->i32Error, VINF_SUCCESS);
     456        ASMAtomicWriteS32(&pStream->i32Error, VINF_SUCCESS);
    441457        rc = VINF_SUCCESS;
    442458    }
     
    444460    {
    445461        rc = RTErrConvertFromErrno(errno);
    446         ASMAtomicXchgS32(&pStream->i32Error, rc);
     462        ASMAtomicWriteS32(&pStream->i32Error, rc);
    447463    }
    448464
    449465    return rc;
     466}
     467
     468
     469/**
     470 * Recheck the stream mode.
     471 * 
     472 * @param   pStream             The stream (locked).
     473 */
     474static void rtStreamRecheckMode(PRTSTREAM pStream)
     475{
     476#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
     477    int fh = fileno(pStream->pFile);
     478    if (fh >= 0)
     479    {
     480        int fExpected = pStream->fBinary ? _O_BINARY : _O_TEXT;
     481        int fActual   = _setmode(fh, fExpected);
     482        if (fActual != -1 && fExpected != (fActual & (_O_BINARY | _O_TEXT)))
     483        {
     484            _setmode(fh, fActual & (_O_BINARY | _O_TEXT));
     485            pStream->fBinary = !(fActual & _O_TEXT);
     486        }
     487    }
     488#else
     489    NOREF(pStream);
     490#endif
     491    pStream->fRecheckMode = false;
    450492}
    451493
     
    464506RTR3DECL(int) RTStrmReadEx(PRTSTREAM pStream, void *pvBuf, size_t cbRead, size_t *pcbRead)
    465507{
    466     int rc;
    467     if (pStream && pStream->u32Magic == RTSTREAM_MAGIC)
    468     {
    469         rc = pStream->i32Error;
     508    AssertReturn(RT_VALID_PTR(pStream) && pStream->u32Magic == RTSTREAM_MAGIC, VERR_INVALID_PARAMETER);
     509
     510    int rc = pStream->i32Error;
     511    if (RT_SUCCESS(rc))
     512    {
     513        if (pStream->fRecheckMode)
     514            rtStreamRecheckMode(pStream);
     515
     516        if (pcbRead)
     517        {
     518            /*
     519             * Can do with a partial read.
     520             */
     521            *pcbRead = fread(pvBuf, 1, cbRead, pStream->pFile);
     522            if (    *pcbRead == cbRead
     523                || !ferror(pStream->pFile))
     524                return VINF_SUCCESS;
     525            if (feof(pStream->pFile))
     526            {
     527                if (*pcbRead)
     528                    return VINF_EOF;
     529                rc = VERR_EOF;
     530            }
     531            else if (ferror(pStream->pFile))
     532                rc = VERR_READ_ERROR;
     533            else
     534            {
     535                AssertMsgFailed(("This shouldn't happen\n"));
     536                rc = VERR_INTERNAL_ERROR;
     537            }
     538        }
     539        else
     540        {
     541            /*
     542             * Must read it all!
     543             */
     544            if (fread(pvBuf, cbRead, 1, pStream->pFile) == 1)
     545                return VINF_SUCCESS;
     546
     547            /* possible error/eof. */
     548            if (feof(pStream->pFile))
     549                rc = VERR_EOF;
     550            else if (ferror(pStream->pFile))
     551                rc = VERR_READ_ERROR;
     552            else
     553            {
     554                AssertMsgFailed(("This shouldn't happen\n"));
     555                rc = VERR_INTERNAL_ERROR;
     556            }
     557        }
     558        ASMAtomicWriteS32(&pStream->i32Error, rc);
     559    }
     560    return rc;
     561}
     562
     563
     564/**
     565 * Check if the input text is valid UTF-8.
     566 * 
     567 * @returns true/false.
     568 * @param   pvBuf               Pointer to the buffer.
     569 * @param   cbBuf               Size of the buffer.
     570 */
     571static bool rtStrmIsUtf8Text(const void *pvBuf, size_t cbBuf)
     572{
     573    NOREF(pvBuf);
     574    NOREF(cbBuf);
     575    /** @todo not sure this is a good idea... Better redefine RTStrmWrite. */
     576    return false;
     577}
     578
     579
     580#ifdef RT_OS_WINDOWS
     581/**
     582 * Check if the stream is for a Window console.
     583 * 
     584 * @returns true / false.
     585 * @param   pStream             The stream.
     586 * @param   phCon               Where to return the console handle.
     587 */
     588static bool rtStrmIsConsoleUnlocked(PRTSTREAM pStream, HANDLE *phCon)
     589{
     590    int fh = fileno(pStream->pFile);
     591    if (isatty(fh))
     592    {
     593        DWORD dwMode;
     594        HANDLE hCon = (HANDLE)_get_osfhandle(fh);
     595        if (GetConsoleMode(hCon, &dwMode))
     596        {
     597            *phCon = hCon;
     598            return true;
     599        }
     600    }
     601    return false;
     602}
     603#endif /* RT_OS_WINDOWS */
     604
     605
     606/**
     607 * Internal write API, stream lock already held.
     608 * 
     609 * @returns IPRT status code.
     610 * @param   pStream             The stream.
     611 * @param   pvBuf               What to write.
     612 * @param   cbWrite             How much to write.
     613 * @param   pcbWritten          Where to optionally return the number of bytes
     614 *                              written.
     615 * @param   fSureIsText         Set if we're sure this is UTF-8 text already.
     616 */
     617static int rtStrmWriteLocked(PRTSTREAM pStream, const void *pvBuf, size_t cbWrite, size_t *pcbWritten,
     618                              bool fSureIsText)
     619{
     620    int rc = pStream->i32Error;
     621    if (RT_FAILURE(rc))
     622        return rc;
     623    if (pStream->fRecheckMode)
     624        rtStreamRecheckMode(pStream);
     625
     626#ifdef RT_OS_WINDOWS
     627    /*
     628     * Use the unicode console API when possible in order to avoid stuff
     629     * getting lost in unnecessary code page translations.
     630     */
     631    HANDLE hCon;
     632    if (rtStrmIsConsoleUnlocked(pStream, &hCon))
     633    {
     634# ifdef HAVE_FWRITE_UNLOCKED
     635        if (!fflush_unlocked(pStream->pFile))
     636# else
     637        if (!fflush(pStream->pFile))
     638# endif
     639        {
     640            /** @todo Consider buffering later. For now, we'd rather correct output than
     641             *        fast output. */
     642            DWORD    cwcWritten = 0;
     643            PRTUTF16 pwszSrc = NULL;
     644            size_t   cwcSrc = 0;
     645            rc = RTStrToUtf16Ex((const char *)pvBuf, cbWrite, &pwszSrc, 0, &cwcSrc);
     646            if (RT_SUCCESS(rc))
     647            {
     648                if (!WriteConsoleW(hCon, pwszSrc, (DWORD)cwcSrc, &cwcWritten, NULL))
     649                {
     650                    /* try write char-by-char to avoid heap problem. */
     651                    cwcWritten = 0;
     652                    while (cwcWritten != cwcSrc)
     653                    {
     654                        DWORD cwcThis;
     655                        if (!WriteConsoleW(hCon, &pwszSrc[cwcWritten], 1, &cwcThis, NULL))
     656                        {
     657                            if (!pcbWritten || cwcWritten == 0)
     658                                rc = RTErrConvertFromErrno(GetLastError());
     659                            break;
     660                        }
     661                        if (cwcThis != 0)
     662                            break;
     663                        cwcWritten++;
     664                    }
     665                }
     666                if (RT_SUCCESS(rc))
     667                {
     668                    if (cwcWritten == cwcSrc)
     669                    {
     670                        if (pcbWritten)
     671                            *pcbWritten = cbWrite;
     672                    }
     673                    else if (pcbWritten)
     674                    {
     675                        PCRTUTF16   pwszCur = pwszSrc;
     676                        const char *pszCur  = (const char *)pvBuf;
     677                        while ((uintptr_t)(pwszCur - pwszSrc) < cwcWritten)
     678                        {
     679                            RTUNICP CpIgnored;
     680                            RTUtf16GetCpEx(&pwszCur, &CpIgnored);
     681                            RTStrGetCpEx(&pszCur, &CpIgnored);
     682                        }
     683                        *pcbWritten = pszCur - (const char *)pvBuf;
     684                    }
     685                    else
     686                        rc = VERR_WRITE_ERROR;
     687                }
     688                RTUtf16Free(pwszSrc);
     689            }
     690        }
     691        else
     692            rc = RTErrConvertFromErrno(errno);
     693        if (RT_FAILURE(rc))
     694            ASMAtomicWriteS32(&pStream->i32Error, rc);
     695        return rc;
     696    }
     697#endif /* RT_OS_WINDOWS */
     698
     699    /*
     700     * If we're sure it's text output, convert it from UTF-8 to the current
     701     * code page before printing it.
     702     * 
     703     * Note! Partial writes are not supported in this scenario because we
     704     *       cannot easily report back a written length matching the input.
     705     */
     706    /** @todo Skip this if the current code set is UTF-8. */
     707    if (   pStream->fCurrentCodeSet
     708        && !pStream->fBinary
     709        && (   fSureIsText
     710            || rtStrmIsUtf8Text(pvBuf, cbWrite))
     711       )
     712    {
     713        char       *pszSrcFree = NULL;
     714        const char *pszSrc     = (const char *)pvBuf;
     715        if (pszSrc[cbWrite])
     716        {
     717            pszSrc = pszSrcFree = RTStrDupN(pszSrc, cbWrite);
     718            if (pszSrc == NULL)
     719                rc = VERR_NO_STR_MEMORY;
     720        }
    470721        if (RT_SUCCESS(rc))
    471722        {
    472             if (pcbRead)
     723            char *pszSrcCurCP;
     724            rc = RTStrUtf8ToCurrentCP(&pszSrcCurCP, pszSrc);
     725            if (RT_SUCCESS(rc))
    473726            {
    474                 /*
    475                  * Can do with a partial read.
    476                  */
    477                 *pcbRead = fread(pvBuf, 1, cbRead, pStream->pFile);
    478                 if (    *pcbRead == cbRead
    479                     || !ferror(pStream->pFile))
    480                     return VINF_SUCCESS;
    481                 if (feof(pStream->pFile))
     727                size_t  cchSrcCurCP = strlen(pszSrcCurCP);
     728                IPRT_ALIGNMENT_CHECKS_DISABLE(); /* glibc / mempcpy again */
     729#ifdef HAVE_FWRITE_UNLOCKED
     730                ssize_t cbWritten = fwrite_unlocked(pszSrcCurCP, cchSrcCurCP, 1, pStream->pFile);
     731#else
     732                ssize_t cbWritten = fwrite(pszSrcCurCP, cchSrcCurCP, 1, pStream->pFile);
     733#endif
     734                IPRT_ALIGNMENT_CHECKS_ENABLE();
     735                if (cbWritten == 1)
    482736                {
    483                     if (*pcbRead)
    484                         return VINF_EOF;
    485                     rc = VERR_EOF;
     737                    if (pcbWritten)
     738                        *pcbWritten = cbWrite;
    486739                }
    487                 else if (ferror(pStream->pFile))
    488                     rc = VERR_READ_ERROR;
     740#ifdef HAVE_FWRITE_UNLOCKED
     741                else if (!ferror_unlocked(pStream->pFile))
     742#else
     743                else if (!ferror(pStream->pFile))
     744#endif
     745                {
     746                    if (pcbWritten)
     747                        *pcbWritten = 0;
     748                }
    489749                else
    490                 {
    491                     AssertMsgFailed(("This shouldn't happen\n"));
    492                     rc = VERR_INTERNAL_ERROR;
    493                 }
     750                    rc = VERR_WRITE_ERROR;
     751                RTStrFree(pszSrcCurCP);
    494752            }
    495             else
    496             {
    497                 /*
    498                  * Must read it all!
    499                  */
    500                 if (fread(pvBuf, cbRead, 1, pStream->pFile) == 1)
    501                     return VINF_SUCCESS;
    502 
    503                 /* possible error/eof. */
    504                 if (feof(pStream->pFile))
    505                     rc = VERR_EOF;
    506                 else if (ferror(pStream->pFile))
    507                     rc = VERR_READ_ERROR;
    508                 else
    509                 {
    510                     AssertMsgFailed(("This shouldn't happen\n"));
    511                     rc = VERR_INTERNAL_ERROR;
    512                 }
    513             }
    514             ASMAtomicXchgS32(&pStream->i32Error, rc);
     753            RTStrFree(pszSrcFree);
    515754        }
     755
     756        if (RT_FAILURE(rc))
     757            ASMAtomicWriteS32(&pStream->i32Error, rc);
     758        return rc;
     759    }
     760
     761    /*
     762     * Otherwise, just write it as-is.
     763     */
     764    if (pcbWritten)
     765    {
     766        IPRT_ALIGNMENT_CHECKS_DISABLE(); /* glibc / mempcpy again */
     767#ifdef HAVE_FWRITE_UNLOCKED
     768        *pcbWritten = fwrite_unlocked(pvBuf, 1, cbWrite, pStream->pFile);
     769#else
     770        *pcbWritten = fwrite(pvBuf, 1, cbWrite, pStream->pFile);
     771#endif
     772        IPRT_ALIGNMENT_CHECKS_ENABLE();
     773        if (    *pcbWritten == cbWrite
     774#ifdef HAVE_FWRITE_UNLOCKED
     775            ||  !ferror_unlocked(pStream->pFile))
     776#else
     777            ||  !ferror(pStream->pFile))
     778#endif
     779            return VINF_SUCCESS;
     780        rc = VERR_WRITE_ERROR;
    516781    }
    517782    else
    518783    {
    519         AssertMsgFailed(("Invalid stream!\n"));
    520         rc = VERR_INVALID_PARAMETER;
    521     }
     784        /* Must write it all! */
     785        IPRT_ALIGNMENT_CHECKS_DISABLE(); /* glibc / mempcpy again */
     786#ifdef HAVE_FWRITE_UNLOCKED
     787        size_t cbWritten = fwrite_unlocked(pvBuf, cbWrite, 1, pStream->pFile);
     788#else
     789        size_t cbWritten = fwrite(pvBuf, cbWrite, 1, pStream->pFile);
     790#endif
     791        IPRT_ALIGNMENT_CHECKS_ENABLE();
     792        if (cbWritten == 1)
     793            return VINF_SUCCESS;
     794#ifdef HAVE_FWRITE_UNLOCKED
     795        if (!ferror_unlocked(pStream->pFile))
     796#else
     797        if (!ferror(pStream->pFile))
     798#endif
     799            return VINF_SUCCESS; /* WEIRD! But anyway... */
     800
     801        rc = VERR_WRITE_ERROR;
     802    }
     803    ASMAtomicWriteS32(&pStream->i32Error, rc);
     804
     805    return rc;
     806}
     807
     808
     809/**
     810 * Internal write API.
     811 * 
     812 * @returns IPRT status code.
     813 * @param   pStream             The stream.
     814 * @param   pvBuf               What to write.
     815 * @param   cbWrite             How much to write.
     816 * @param   pcbWritten          Where to optionally return the number of bytes
     817 *                              written.
     818 * @param   fSureIsText         Set if we're sure this is UTF-8 text already.
     819 */
     820static int rtStrmWrite(PRTSTREAM pStream, const void *pvBuf, size_t cbWrite, size_t *pcbWritten, bool fSureIsText)
     821{
     822    rtStrmLock(pStream);
     823    int rc = rtStrmWriteLocked(pStream, pvBuf, cbWrite, pcbWritten, fSureIsText);
     824    rtStrmUnlock(pStream);
    522825    return rc;
    523826}
     
    536839RTR3DECL(int) RTStrmWriteEx(PRTSTREAM pStream, const void *pvBuf, size_t cbWrite, size_t *pcbWritten)
    537840{
    538     int rc;
    539     if (pStream && pStream->u32Magic == RTSTREAM_MAGIC)
    540     {
    541         rc = pStream->i32Error;
    542         if (RT_SUCCESS(rc))
    543         {
    544             if (pcbWritten)
    545             {
    546                 IPRT_ALIGNMENT_CHECKS_DISABLE(); /* glibc / mempcpy again */
    547                 *pcbWritten = fwrite(pvBuf, 1, cbWrite, pStream->pFile);
    548                 IPRT_ALIGNMENT_CHECKS_ENABLE();
    549                 if (    *pcbWritten == cbWrite
    550                     ||  !ferror(pStream->pFile))
    551                     return VINF_SUCCESS;
    552                 rc = VERR_WRITE_ERROR;
    553             }
    554             else
    555             {
    556                 /*
    557                  * Must write it all!
    558                  */
    559                 IPRT_ALIGNMENT_CHECKS_DISABLE(); /* glibc / mempcpy again */
    560                 size_t cbWritten = fwrite(pvBuf, cbWrite, 1, pStream->pFile);
    561                 IPRT_ALIGNMENT_CHECKS_ENABLE();
    562                 if (cbWritten == 1)
    563                     return VINF_SUCCESS;
    564                 if (!ferror(pStream->pFile))
    565                     return VINF_SUCCESS; /* WEIRD! But anyway... */
    566 
    567                 rc = VERR_WRITE_ERROR;
    568             }
    569             ASMAtomicXchgS32(&pStream->i32Error, rc);
    570         }
    571     }
    572     else
    573     {
    574         AssertMsgFailed(("Invalid stream!\n"));
    575         rc = VERR_INVALID_PARAMETER;
    576     }
    577     return rc;
     841    AssertReturn(RT_VALID_PTR(pStream) && pStream->u32Magic == RTSTREAM_MAGIC, VERR_INVALID_PARAMETER);
     842    return rtStrmWrite(pStream, pvBuf, cbWrite, pcbWritten, false);
    578843}
    579844
     
    605870RTR3DECL(int) RTStrmPutCh(PRTSTREAM pStream, int ch)
    606871{
    607     return RTStrmWriteEx(pStream, &ch, 1, NULL);
     872    return rtStrmWrite(pStream, &ch, 1, NULL, true /*fSureIsText*/);
    608873}
    609874
     
    621886{
    622887    size_t cch = strlen(pszString);
    623     return RTStrmWriteEx(pStream, pszString, cch, NULL);
     888    return rtStrmWrite(pStream, pszString, cch, NULL, true /*fSureIsText*/);
    624889}
    625890
     
    638903RTR3DECL(int) RTStrmGetLine(PRTSTREAM pStream, char *pszString, size_t cchString)
    639904{
     905    AssertReturn(RT_VALID_PTR(pStream) && pStream->u32Magic == RTSTREAM_MAGIC, VERR_INVALID_PARAMETER);
    640906    int rc;
    641     if (pStream && pStream->u32Magic == RTSTREAM_MAGIC)
    642     {
    643         if (pszString && cchString > 1)
     907    if (pszString && cchString > 1)
     908    {
     909        rc = pStream->i32Error;
     910        if (RT_SUCCESS(rc))
    644911        {
    645             rc = pStream->i32Error;
    646             if (RT_SUCCESS(rc))
     912            cchString--;            /* save space for the terminator. */
     913            rtStrmLock(pStream);
     914            for (;;)
    647915            {
    648                 cchString--;            /* save space for the terminator. */
    649                 rtStrmLock(pStream);
    650                 for (;;)
     916#ifdef HAVE_FWRITE_UNLOCKED /** @todo darwin + freebsd(?) has fgetc_unlocked but not fwrite_unlocked, optimize... */
     917                int ch = fgetc_unlocked(pStream->pFile);
     918#else
     919                int ch = fgetc(pStream->pFile);
     920#endif
     921                if (ch == EOF)
    651922                {
    652 #ifdef HAVE_FWRITE_UNLOCKED /** @todo darwin + freebsd(?) has fgetc_unlocked but not fwrite_unlocked, optimize... */
    653                     int ch = fgetc_unlocked(pStream->pFile);
    654 #else
    655                     int ch = fgetc(pStream->pFile);
    656 #endif
    657                     if (ch == EOF)
     923#ifdef HAVE_FWRITE_UNLOCKED
     924                    if (feof_unlocked(pStream->pFile))
     925#else
     926                    if (feof(pStream->pFile))
     927#endif
    658928                    {
    659 #ifdef HAVE_FWRITE_UNLOCKED
    660                         if (feof_unlocked(pStream->pFile))
    661 #else
    662                         if (feof(pStream->pFile))
    663 #endif
    664                         {
    665                             rc = VERR_EOF;
    666                             break;
    667                         }
    668 #ifdef HAVE_FWRITE_UNLOCKED
    669                         if (ferror_unlocked(pStream->pFile))
    670 #else
    671                         if (ferror(pStream->pFile))
    672 #endif
    673                             rc = VERR_READ_ERROR;
    674                         else
    675                         {
    676                             AssertMsgFailed(("This shouldn't happen\n"));
    677                             rc = VERR_INTERNAL_ERROR;
    678                         }
     929                        rc = VERR_EOF;
    679930                        break;
    680931                    }
    681                     if (ch == '\0' || ch == '\n' || ch == '\r')
    682                         break;
    683                     *pszString++ = ch;
    684                     if (--cchString <= 0)
     932#ifdef HAVE_FWRITE_UNLOCKED
     933                    if (ferror_unlocked(pStream->pFile))
     934#else
     935                    if (ferror(pStream->pFile))
     936#endif
     937                        rc = VERR_READ_ERROR;
     938                    else
    685939                    {
    686                         rc = VINF_BUFFER_OVERFLOW;
    687                         break;
     940                        AssertMsgFailed(("This shouldn't happen\n"));
     941                        rc = VERR_INTERNAL_ERROR;
    688942                    }
     943                    break;
    689944                }
    690                 rtStrmUnlock(pStream);
    691 
    692                 *pszString = '\0';
    693                 if (RT_FAILURE(rc))
    694                     ASMAtomicXchgS32(&pStream->i32Error, rc);
     945                if (ch == '\0' || ch == '\n' || ch == '\r')
     946                    break;
     947                *pszString++ = ch;
     948                if (--cchString <= 0)
     949                {
     950                    rc = VINF_BUFFER_OVERFLOW;
     951                    break;
     952                }
    695953            }
     954            rtStrmUnlock(pStream);
     955
     956            *pszString = '\0';
     957            if (RT_FAILURE(rc))
     958                ASMAtomicWriteS32(&pStream->i32Error, rc);
    696959        }
    697         else
    698         {
    699             AssertMsgFailed(("no buffer or too small buffer!\n"));
    700             rc = VERR_INVALID_PARAMETER;
    701         }
    702960    }
    703961    else
    704962    {
    705         AssertMsgFailed(("Invalid stream!\n"));
     963        AssertMsgFailed(("no buffer or too small buffer!\n"));
    706964        rc = VERR_INVALID_PARAMETER;
    707965    }
     
    735993{
    736994    if (cchChars)
    737     {
    738         PRTSTREAM pStream = (PRTSTREAM)pvArg;
    739         int rc = pStream->i32Error;
    740         if (RT_SUCCESS(rc))
    741         {
    742             IPRT_ALIGNMENT_CHECKS_DISABLE(); /* glibc / mempcpy again */
    743 #ifdef HAVE_FWRITE_UNLOCKED
    744             if (fwrite_unlocked(pachChars, cchChars, 1, pStream->pFile) != 1)
    745 #else
    746             if (fwrite(pachChars, cchChars, 1, pStream->pFile) != 1)
    747 #endif
    748                 ASMAtomicXchgS32(&pStream->i32Error, VERR_WRITE_ERROR);
    749             IPRT_ALIGNMENT_CHECKS_ENABLE();
    750         }
    751     }
     995        rtStrmWriteLocked((PRTSTREAM)pvArg, pachChars, cchChars, NULL, true /*fSureIsText*/);
    752996    /* else: ignore termination call. */
    753997    return cchChars;
     
    7651009RTR3DECL(int) RTStrmPrintfV(PRTSTREAM pStream, const char *pszFormat, va_list args)
    7661010{
    767     int rc;
    768     if (pStream && pStream->u32Magic == RTSTREAM_MAGIC)
    769     {
    770         rc = pStream->i32Error;
    771         if (RT_SUCCESS(rc))
    772         {
    773             rtStrmLock(pStream);
    774             rc = (int)RTStrFormatV(rtstrmOutput, pStream, NULL, NULL, pszFormat, args);
    775             rtStrmUnlock(pStream);
    776             Assert(rc >= 0);
    777         }
    778         else
    779             rc = -1;
     1011    AssertReturn(RT_VALID_PTR(pStream) && pStream->u32Magic == RTSTREAM_MAGIC, VERR_INVALID_PARAMETER);
     1012    int rc = pStream->i32Error;
     1013    if (RT_SUCCESS(rc))
     1014    {
     1015        rtStrmLock(pStream);
     1016//        pStream->fShouldFlush = true;
     1017        rc = (int)RTStrFormatV(rtstrmOutput, pStream, NULL, NULL, pszFormat, args);
     1018        rtStrmUnlock(pStream);
     1019        Assert(rc >= 0);
    7801020    }
    7811021    else
    782     {
    783         AssertMsgFailed(("Invalid stream!\n"));
    7841022        rc = -1;
    785     }
    7861023    return rc;
    7871024}
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