@@ -466,6 +466,8 @@ CBaseHudChatInputLine::CBaseHudChatInputLine( CBaseHudChat *parent, char const *
466466 m_pPrompt = new vgui::Label ( this , " ChatInputPrompt" , L" Enter text:" );
467467 m_pInput = new CBaseHudChatEntry ( this , " ChatInput" , parent );
468468 m_pInput->SetMaximumCharCount ( 127 );
469+ // Send converts text to utf-8
470+ m_pInput->m_iMaxByteCount = 127 ;
469471}
470472
471473void CBaseHudChatInputLine::ApplySchemeSettings (vgui::IScheme *pScheme)
@@ -2519,3 +2521,59 @@ void CBaseHudChat::FireGameEvent( IGameEvent *event )
25192521 ChatPrintf ( player->entindex (), CHAT_FILTER_NONE, " (SourceTV) %s" , event->GetString ( " text" ) );
25202522 }
25212523}
2524+
2525+ // Prevent player from inserting text over utf-8 byte limit
2526+ void CBaseHudChatEntry::InsertChar (wchar_t ch)
2527+ {
2528+ if ( m_iMaxByteCount == -1 )
2529+ {
2530+ BaseClass::InsertChar (ch);
2531+ return ;
2532+ }
2533+
2534+ // single utf-16 char converted to utf-8 is 3 byte long in worst case
2535+ const int iBufLen = BaseClass::GetTextLength () * 3 ;
2536+
2537+ // Shortcut: fitting max byte count even in worst case
2538+ if ( iBufLen + 4 <= m_iMaxByteCount )
2539+ {
2540+ BaseClass::InsertChar (ch);
2541+ return ;
2542+ }
2543+
2544+ // Count bytes of converted utf-8 str
2545+ m_szCharBuf.EnsureCapacity ( iBufLen );
2546+ BaseClass::GetText ( m_szCharBuf.Base (), m_szCharBuf.Count () );
2547+ const int iCurrentByteLen = Q_strlen ( m_szCharBuf.Base () );
2548+
2549+ // Shortcut: average case
2550+ if ( iCurrentByteLen + 4 <= m_iMaxByteCount )
2551+ {
2552+ BaseClass::InsertChar (ch);
2553+ return ;
2554+ }
2555+
2556+ // Edge case: check if current wchar_t will cause Send to truncate message
2557+ int iCharByteLen; // utf-8
2558+ if ( ch < 0x80 ) iCharByteLen = 1 ;
2559+ else if ( ch < 0x800 ) iCharByteLen = 2 ;
2560+ else if ( ch >= 0xD800 && ch <= 0xDBFF ) iCharByteLen = 4 ; // high surrogate, assume pair
2561+ else if ( ch >= 0xDC00 && ch <= 0xDFFF ) // low surrogate
2562+ {
2563+ // Check if previous wchar was a high surrogate
2564+ wchar_t wszHigh[2 ];
2565+ const int iLast = BaseClass::GetTextLength () - 1 ;
2566+ BaseClass::GetTextRange ( wszHigh, iLast, 1 );
2567+ if ( wszHigh[0 ] >= 0xD800 && wszHigh[0 ] <= 0xDBFF ) { BaseClass::InsertChar (ch); return ; }
2568+ else return ; // it was not a hight surrogate, reject
2569+ }
2570+ else iCharByteLen = 3 ;
2571+
2572+ if ( iCurrentByteLen + iCharByteLen <= m_iMaxByteCount )
2573+ {
2574+ BaseClass::InsertChar (ch);
2575+ return ;
2576+ }
2577+
2578+ return ; // do not insert anything
2579+ }
0 commit comments