size_t Convert()

in source/shared/globalization.h [194:269]


    size_t Convert(
        iconv_buffer<DestType> & dest,
        iconv_buffer<SrcType> & src,
        bool failIfLossy = false, bool * pHasLoss = NULL, DWORD * pErrorCode = NULL ) const
    {
        if ( !IsValidIConv() )
            return 0;

        size_t iconv_ret;
        size_t cchDest = dest.m_nBytesLeft/sizeof(DestType);

        if ( NULL != pHasLoss )
            *pHasLoss = false;
        if ( NULL != pErrorCode )
            *pErrorCode = ERROR_SUCCESS;

        while ( 0 < dest.m_nBytesLeft && 0 < src.m_nBytesLeft )
        {
            // First clear any intermediate state left over from previous conversions
            iconv_ret = iconv( m_pCvtCache->GetIConv(), NULL, NULL, NULL, NULL );
            assert( 0 == iconv_ret );

            // Now attempt conversion
            iconv_ret = iconv( m_pCvtCache->GetIConv(), &src.m_pBytes, &src.m_nBytesLeft, &dest.m_pBytes, &dest.m_nBytesLeft );
            if ( iconv_ret == (size_t)(-1) )
            {
                // If there's no dest bytes left, then treat as E2BIG even if the error
                // is EILSEQ, etc.  We want E2BIG to take precedence like Windows.
                int err = (0 < dest.m_nBytesLeft ? errno : E2BIG);
                if ( E2BIG != err && failIfLossy )
                {
                    if ( NULL != pErrorCode )
                        *pErrorCode = ERROR_NO_UNICODE_TRANSLATION;
                    return 0;
                }

                switch ( err )
                {
                case EILSEQ: // Invalid multibyte sequence in input
                    if ( CP_UTF8 == m_srcCodePage )
                        src.SkipUtf8Ch();
                    else if ( 1 == sizeof(SrcType) )
                        src.SkipDoubleCh(); // DBCS
                    else
                        src.SkipSingleCh(); // utf32 or incomplate utf16 surrogate

                    if ( !AddDefault(&dest, pHasLoss, pErrorCode) )
                        return 0;

                    break;
                case EINVAL: // Incomplete multibyte sequence in input
                    if ( CP_UTF8 == m_srcCodePage )
                        src.SkipUtf8Ch();
                    else
                        src.SkipSingleCh();

                    if ( !AddDefault(&dest, pHasLoss, pErrorCode) )
                        return 0;

                    break;
                case E2BIG: // Output buffer is out of room
                    if ( NULL != pErrorCode )
                        *pErrorCode = ERROR_INSUFFICIENT_BUFFER;
                    return 0;
                default:
                    if ( NULL != pErrorCode )
                        *pErrorCode = ERROR_INVALID_PARAMETER;
                    return 0;
                }
            }
            //if a shift sequence is encountered, we need to advance output buffer
            iconv_ret = iconv( m_pCvtCache->GetIConv(), NULL, NULL, &dest.m_pBytes, &dest.m_nBytesLeft );
        }

        return cchDest - (dest.m_nBytesLeft / sizeof(DestType));
    }