@@ -618,7 +618,6 @@ private static bool TryDecodeMime(StringSegment input, [NotNullWhen(true)] out s
618618 private static string Encode5987 ( StringSegment input )
619619 {
620620 var builder = new StringBuilder ( "UTF-8\' \' " ) ;
621- Span < byte > utf8CharBuffer = stackalloc byte [ 4 ] ;
622621 var remaining = input . AsSpan ( ) ;
623622 while ( remaining . Length > 0 )
624623 {
@@ -644,14 +643,9 @@ private static string Encode5987(StringSegment input)
644643 for ( int i = 0 ; i < length ; )
645644 {
646645 Rune . DecodeFromUtf16 ( remaining . Slice ( i ) , out Rune rune , out var runeLength ) ;
647- int utf8Length = rune . EncodeToUtf8 ( utf8CharBuffer ) ;
648- for ( int j = 0 ; j < utf8Length ; j ++ )
649- {
650- var utf8Part = utf8CharBuffer [ j ] ;
651- builder . Append ( CultureInfo . InvariantCulture , $ "%{ HexUpperChars [ ( utf8Part & 0xf0 ) >> 4 ] } { HexUpperChars [ utf8Part & 0xf ] } ") ;
652- }
646+ EncodeToUtf8Hex ( rune , builder ) ;
653647 i += runeLength ;
654- }
648+ }
655649
656650 remaining = remaining . Slice ( length ) ;
657651 }
@@ -663,9 +657,45 @@ private static string Encode5987(StringSegment input)
663657 '0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' ,
664658 '8' , '9' , 'A' , 'B' , 'C' , 'D' , 'E' , 'F' } ;
665659
666- private static void HexEscape ( StringBuilder builder , byte b )
660+ private static void EncodeToUtf8Hex ( Rune rune , StringBuilder builder )
667661 {
668- builder . Append ( CultureInfo . InvariantCulture , $ "%{ HexUpperChars [ ( b & 0xf0 ) >> 4 ] } { HexUpperChars [ b & 0xf ] } ") ;
662+ // Inspired by https://source.dot.net/#System.Private.CoreLib/src/libraries/System.Private.CoreLib/src/System/Text/Rune.cs TryEncodeToUtf8
663+ var value = ( uint ) rune . Value ;
664+ if ( rune . IsAscii )
665+ {
666+ var byteValue = ( byte ) value ;
667+ builder . Append ( CultureInfo . InvariantCulture , $ "%{ HexUpperChars [ ( byteValue & 0xf0 ) >> 4 ] } { HexUpperChars [ byteValue & 0xf ] } ") ;
668+ }
669+ else if ( rune . Value <= 0x7FFu )
670+ {
671+ // Scalar 00000yyy yyxxxxxx -> bytes [ 110yyyyy 10xxxxxx ]
672+ var byteValue = ( byte ) ( ( value + ( 0b110u << 11 ) ) >> 6 ) ;
673+ builder . Append ( CultureInfo . InvariantCulture , $ "%{ HexUpperChars [ ( byteValue & 0xf0 ) >> 4 ] } { HexUpperChars [ byteValue & 0xf ] } ") ;
674+ byteValue = ( byte ) ( ( value & 0x3Fu ) + 0x80u ) ;
675+ builder . Append ( CultureInfo . InvariantCulture , $ "%{ HexUpperChars [ ( byteValue & 0xf0 ) >> 4 ] } { HexUpperChars [ byteValue & 0xf ] } ") ;
676+ }
677+ else if ( rune . Value <= 0xFFFFu )
678+ {
679+ // Scalar zzzzyyyy yyxxxxxx -> bytes [ 1110zzzz 10yyyyyy 10xxxxxx ]
680+ var byteValue = ( byte ) ( ( value + ( 0b1110 << 16 ) ) >> 12 ) ;
681+ builder . Append ( CultureInfo . InvariantCulture , $ "%{ HexUpperChars [ ( byteValue & 0xf0 ) >> 4 ] } { HexUpperChars [ byteValue & 0xf ] } ") ;
682+ byteValue = ( byte ) ( ( ( value & ( 0x3Fu << 6 ) ) >> 6 ) + 0x80u ) ;
683+ builder . Append ( CultureInfo . InvariantCulture , $ "%{ HexUpperChars [ ( byteValue & 0xf0 ) >> 4 ] } { HexUpperChars [ byteValue & 0xf ] } ") ;
684+ byteValue = ( byte ) ( ( value & 0x3Fu ) + 0x80u ) ;
685+ builder . Append ( CultureInfo . InvariantCulture , $ "%{ HexUpperChars [ ( byteValue & 0xf0 ) >> 4 ] } { HexUpperChars [ byteValue & 0xf ] } ") ;
686+ }
687+ else
688+ {
689+ // Scalar 000uuuuu zzzzyyyy yyxxxxxx -> bytes [ 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx ]
690+ var byteValue = ( byte ) ( ( value + ( 0b11110 << 21 ) ) >> 18 ) ;
691+ builder . Append ( CultureInfo . InvariantCulture , $ "%{ HexUpperChars [ ( byteValue & 0xf0 ) >> 4 ] } { HexUpperChars [ byteValue & 0xf ] } ") ;
692+ byteValue = ( byte ) ( ( ( value & ( 0x3Fu << 12 ) ) >> 12 ) + 0x80u ) ;
693+ builder . Append ( CultureInfo . InvariantCulture , $ "%{ HexUpperChars [ ( byteValue & 0xf0 ) >> 4 ] } { HexUpperChars [ byteValue & 0xf ] } ") ;
694+ byteValue = ( byte ) ( ( ( value & ( 0x3Fu << 6 ) ) >> 6 ) + 0x80u ) ;
695+ builder . Append ( CultureInfo . InvariantCulture , $ "%{ HexUpperChars [ ( byteValue & 0xf0 ) >> 4 ] } { HexUpperChars [ byteValue & 0xf ] } ") ;
696+ byteValue = ( byte ) ( ( value & 0x3Fu ) + 0x80u ) ;
697+ builder . Append ( CultureInfo . InvariantCulture , $ "%{ HexUpperChars [ ( byteValue & 0xf0 ) >> 4 ] } { HexUpperChars [ byteValue & 0xf ] } ") ;
698+ }
669699 }
670700
671701 // Attempt to decode using RFC 5987 encoding.
0 commit comments