int CoreVfwprintf()

in CoreCLRProfiler/native/coreclr_headers/src/pal/src/cruntime/printfcpp.cpp [1020:1448]


int CoreVfwprintf(CPalThread *pthrCurrent, PAL_FILE *stream, const wchar_16 *format, va_list aparg)
{
    CHAR TempBuff[1024]; /* used to hold a single %<foo> format string */
    LPCWSTR Fmt = format;
    LPCWSTR TempWStr = NULL;
    LPWSTR AllocedTempWStr = NULL;
    LPWSTR WorkingWStr = NULL;
    WCHAR TempWChar[2];
    INT Flags;
    INT Width;
    INT Precision;
    INT Prefix;
    INT Type;
    INT TempInt;
    int mbtowcResult;
    int written=0;
    int paddingReturnValue;
    int ret;
    va_list ap;

    /* fwprintf for now in the PAL is always used on file opened
       in text mode. In those case the output should be ANSI not Unicode */
    BOOL textMode = TRUE;

    PERF_ENTRY(vfwprintf);
    ENTRY("vfwprintf (stream=%p, format=%p (%S))\n",
          stream, format, format);

    va_copy(ap, aparg);

    while (*Fmt)
    {
        if(*Fmt == '%' &&
                TRUE == Internal_ExtractFormatW(pthrCurrent, &Fmt, TempBuff, &Flags,
                                                &Width, &Precision,
                                                &Prefix, &Type))
        {
            if (((Prefix == PFF_PREFIX_LONG || Prefix == PFF_PREFIX_LONG_W) &&
                 (Type == PFF_TYPE_STRING || Type == PFF_TYPE_WSTRING)) ||
                 (Type == PFF_TYPE_WSTRING && (Flags & PFF_ZERO) != 0))
            {
                AllocedTempWStr = NULL;

                if (WIDTH_STAR == Width)
                {
                    Width = va_arg(ap, INT);
                }
                else if (WIDTH_INVALID == Width)
                {
                    /* both a '*' and a number, ignore, but remove arg */
                    TempInt = va_arg(ap, INT); /* value not used */
                }

                if (PRECISION_STAR == Precision)
                {
                    Precision = va_arg(ap, INT);
                }
                else if (PRECISION_INVALID == Precision)
                {
                    /* both a '*' and a number, ignore, but remove arg */
                    TempInt = va_arg(ap, INT); /* value not used */
                }

                if (Type == PFF_TYPE_STRING || Prefix == PFF_PREFIX_LONG_W)
                {
                    TempWStr = va_arg(ap, LPWSTR);
                }
                else
                {
                    /* %lS assumes a LPSTR argument. */
                    LPCSTR s = va_arg(ap, LPSTR );
                    if (s == NULL)
                    {
                        TempWStr = NULL;
                    }
                    else
                    {
                        UINT Length = 0;
                        Length = MultiByteToWideChar( CP_ACP, 0, s, -1, NULL, 0 );
                        if ( Length != 0 )
                        {
                            AllocedTempWStr =
                                (LPWSTR)InternalMalloc( (Length) * sizeof( WCHAR ) );

                            if ( AllocedTempWStr )
                            {
                                MultiByteToWideChar( CP_ACP, 0, s, -1,
                                                     AllocedTempWStr, Length );
                                TempWStr = AllocedTempWStr;
                            }
                            else
                            {
                                ERROR( "InternalMalloc failed.\n" );
                                LOGEXIT("vfwprintf returns int -1\n");
                                PERF_EXIT(vfwprintf);
                                va_end(ap);
                                return -1;
                            }
                        }
                        else
                        {
                            ASSERT( "Unable to convert from multibyte "
                                   " to wide char.\n" );
                            LOGEXIT("vfwprintf returns int -1\n");
                            PERF_EXIT(vfwprintf);
                            va_end(ap);
                            return -1;
                        }
                    }
                }

                if (TempWStr == NULL)
                {
                    TempWStr = __wnullstring;
                }

                INT Length = PAL_wcslen(TempWStr);
                WorkingWStr = (LPWSTR) InternalMalloc((sizeof(WCHAR) * (Length + 1)));
                if (!WorkingWStr)
                {
                    ERROR("InternalMalloc failed\n");
                    LOGEXIT("vfwprintf returns int -1\n");
                    PERF_EXIT(vfwprintf);
                    pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
                    free(AllocedTempWStr);
                    va_end(ap);
                    return -1;
                }
                if (PRECISION_DOT == Precision)
                {
                    /* copy nothing */
                    *WorkingWStr = 0;
                    Length = 0;
                }
                else if (Precision > 0 && Precision < Length)
                {
                    if (wcsncpy_s(WorkingWStr, (Length + 1), TempWStr, Precision+1) != SAFECRT_SUCCESS)
                    {
                        ERROR("Internal_AddPaddingVfwprintf failed\n");
                        free(AllocedTempWStr);
                        free(WorkingWStr);
                        LOGEXIT("wcsncpy_s failed!\n");
                        PERF_EXIT(vfwprintf);
                        va_end(ap);
                        return (-1);
                    }

                    Length = Precision;
                }
                /* copy everything */
                else
                {
                    PAL_wcscpy(WorkingWStr, TempWStr);
                }


                /* do the padding (if needed)*/
                paddingReturnValue =
                    Internal_AddPaddingVfwprintf( pthrCurrent, stream, WorkingWStr,
                                                 Width - Length,
                                                 Flags,textMode);

                if (paddingReturnValue == -1)
                {
                    ERROR("Internal_AddPaddingVfwprintf failed\n");
                    free(AllocedTempWStr);
                    free(WorkingWStr);
                    LOGEXIT("vfwprintf returns int -1\n");
                    PERF_EXIT(vfwprintf);
                    va_end(ap);
                    return (-1);
                }
                written += paddingReturnValue;

                free(WorkingWStr);
                free(AllocedTempWStr);
            }
            else if (Prefix == PFF_PREFIX_LONG && Type == PFF_TYPE_CHAR)
            {
                if (WIDTH_STAR == Width ||
                    WIDTH_INVALID == Width)
                {
                    /* ignore (because it's a char), and remove arg */
                    TempInt = va_arg(ap, INT); /* value not used */
                }

                if (PRECISION_STAR == Precision ||
                    PRECISION_INVALID == Precision)
                {
                    /* ignore (because it's a char), and remove arg */
                    TempInt = va_arg(ap, INT); /* value not used */
                }

                TempWChar[0] = va_arg(ap, int);
                TempWChar[1] = 0;

               /* do the padding (if needed)*/
                paddingReturnValue =
                    Internal_AddPaddingVfwprintf(pthrCurrent, stream, TempWChar,
                                                 Width - 1,
                                                 Flags,textMode);
                if (paddingReturnValue == -1)
                {
                    ERROR("Internal_AddPaddingVfwprintf failed\n");
                    LOGEXIT("vfwprintf returns int -1\n");
                    PERF_EXIT(vfwprintf);
                    va_end(ap);
                    return(-1);
                }
                written += paddingReturnValue;
            }
            /* this places the number of bytes written to the buffer in the
               next arg */
            else if (Type == PFF_TYPE_N)
            {
                if (WIDTH_STAR == Width)
                {
                    Width = va_arg(ap, INT);
                }

                if (PRECISION_STAR == Precision)
                {
                    Precision = va_arg(ap, INT);
                }

                if (Prefix == PFF_PREFIX_SHORT)
                {
                    *(va_arg(ap, short *)) = written;
                }
                else
                {
                    *(va_arg(ap, LPLONG)) = written;
                }
            }
            else
            {
                // Types that sprintf can handle.

                /* note: I'm using the wide buffer as a (char *) buffer when I
                   pass it to sprintf().  After I get the buffer back I make a
                   backup of the chars copied and then convert them to wide
                   and place them in the buffer (BufferPtr) */

                // This argument will be limited to 1024 characters.
                // It should be enough.
                size_t TEMP_COUNT = 1024;
                char TempSprintfStrBuffer[1024];
                char *TempSprintfStrPtr = NULL;
                char *TempSprintfStr = TempSprintfStrBuffer;
                LPWSTR TempWideBuffer;

                TempInt = 0;
                // %h (short) doesn't seem to be handled properly by local sprintf,
                // so we do the truncation ourselves for some cases.
                if (Type == PFF_TYPE_P && Prefix == PFF_PREFIX_SHORT)
                {
                    // Convert from pointer -> int -> short to avoid warnings.
                    long trunc1;
                    short trunc2;

                    trunc1 = va_arg(ap, LONG);
                    trunc2 = (short)trunc1;
                    trunc1 = trunc2;

                    TempInt = snprintf(TempSprintfStr, TEMP_COUNT, TempBuff, trunc1);

                    if (TempInt < 0 || static_cast<size_t>(TempInt) >= TEMP_COUNT)
                    {
                        if (NULL == (TempSprintfStrPtr = (char*)InternalMalloc(++TempInt)))
                        {
                            ERROR("InternalMalloc failed\n");
                            LOGEXIT("vfwprintf returns int -1\n");
                            PERF_EXIT(vfwprintf);
                            pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
                            va_end(ap);
                            return -1;
                        }

                        TempSprintfStr = TempSprintfStrPtr;
                        snprintf(TempSprintfStr, TempInt, TempBuff, trunc2);
                    }
                }
                else if (Type == PFF_TYPE_INT && Prefix == PFF_PREFIX_SHORT)
                {
                    // Convert explicitly from int to short to get
                    // correct sign extension for shorts on all systems.
                    int n;
                    short s;

                    n = va_arg(ap, int);
                    s = (short) n;

                    TempInt = snprintf(TempSprintfStr, TEMP_COUNT, TempBuff, s);

                    if (TempInt < 0 || static_cast<size_t>(TempInt) >= TEMP_COUNT)
                    {
                        if (NULL == (TempSprintfStrPtr = (char*)InternalMalloc(++TempInt)))
                        {
                            ERROR("InternalMalloc failed\n");
                            LOGEXIT("vfwprintf returns int -1\n");
                            PERF_EXIT(vfwprintf);
                            pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
                            va_end(ap);
                            return -1;
                        }

                        TempSprintfStr = TempSprintfStrPtr;
                        snprintf(TempSprintfStr, TempInt, TempBuff, s);
                    }
                }
                else
                {
                    va_list apcopy;

                    va_copy(apcopy, ap);
                    TempInt = _vsnprintf_s(TempSprintfStr, TEMP_COUNT, _TRUNCATE, TempBuff, apcopy);
                    va_end(apcopy);
                    PAL_printf_arg_remover(&ap, Width, Precision, Type, Prefix);

                    if (TempInt < 0 || static_cast<size_t>(TempInt) >= TEMP_COUNT)
                    {
                        if (NULL == (TempSprintfStrPtr = (char*)InternalMalloc(++TempInt)))
                        {
                            ERROR("InternalMalloc failed\n");
                            LOGEXIT("vfwprintf returns int -1\n");
                            PERF_EXIT(vfwprintf);
                            pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
                            va_end(ap);
                            return -1;
                        }

                        TempSprintfStr = TempSprintfStrPtr;
                        va_copy(apcopy, ap);
                        _vsnprintf_s(TempSprintfStr, TempInt, _TRUNCATE, TempBuff, apcopy);
                        va_end(apcopy);
                        PAL_printf_arg_remover(&ap, Width, Precision, Type, Prefix);
                    }
                }

                mbtowcResult = MultiByteToWideChar(CP_ACP, 0,
                                                   TempSprintfStr, -1,
                                                   NULL, 0);

                if (mbtowcResult == 0)
                {
                    ERROR("MultiByteToWideChar failed\n");
                    if(TempSprintfStrPtr)
                    {
                        free(TempSprintfStrPtr);
                    }
                    LOGEXIT("vfwprintf returns int -1\n");
                    PERF_EXIT(vfwprintf);
                    va_end(ap);
                    return -1;
                }

                TempWideBuffer = (LPWSTR) InternalMalloc(mbtowcResult*sizeof(WCHAR));
                if (!TempWideBuffer)
                {
                    ERROR("InternalMalloc failed\n");
                    LOGEXIT("vfwprintf returns int -1\n");
                    PERF_EXIT(vfwprintf);
                    pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
                    if(TempSprintfStrPtr)
                    {
                        free(TempSprintfStrPtr);
                    }
                    va_end(ap);
                    return -1;
                }

                MultiByteToWideChar(CP_ACP, 0, TempSprintfStr, -1,
                                    TempWideBuffer, mbtowcResult);

                ret = Internal_Convertfwrite(
                                    pthrCurrent,
                                    TempWideBuffer,
                                    sizeof(wchar_16),
                                    mbtowcResult-1,
                                    (FILE*)stream->bsdFilePtr,
                                    textMode);

                if (-1 == ret)
                {
                    ERROR("fwrite() failed with errno == %d (%s)\n", errno, strerror(errno));
                    LOGEXIT("vfwprintf returns int -1\n");
                    PERF_EXIT(vfwprintf);
                    free(TempWideBuffer);
                    if(TempSprintfStrPtr)
                    {
                        free(TempSprintfStrPtr);
                    }
                    va_end(ap);
                    return -1;
                }
                if(TempSprintfStrPtr)
                {
                    free(TempSprintfStrPtr);
                }
                free(TempWideBuffer);
            }
        }
        else
        {
            ret = Internal_Convertfwrite(
                                    pthrCurrent,
                                    Fmt++,
                                    sizeof(wchar_16),
                                    1,
                                    (FILE*)stream->bsdFilePtr,
                                    textMode); /* copy regular chars into buffer */

            if (-1 == ret)
            {
                ERROR("fwrite() failed with errno == %d\n", errno);
                LOGEXIT("vfwprintf returns int -1\n");
                PERF_EXIT(vfwprintf);
                va_end(ap);
                return -1;
            }
            ++written;
       }
    }

    LOGEXIT("vfwprintf returns int %d\n", written);
    PERF_EXIT(vfwprintf);
    va_end(ap);
    return (written);
}