@@ -29,7 +29,6 @@ public class ContentDispositionHeaderValue
2929 private const string ReadDateString = "read-date" ;
3030 private const string SizeString = "size" ;
3131 private const int MaxStackAllocSizeBytes = 256 ;
32- private const int MaxStackAllocSizeChars = MaxStackAllocSizeBytes / 2 ;
3332 private static readonly char [ ] QuestionMark = new char [ ] { '?' } ;
3433 private static readonly char [ ] SingleQuote = new char [ ] { '\' ' } ;
3534 private static readonly char [ ] EscapeChars = new char [ ] { '\\ ' , '"' } ;
@@ -38,8 +37,8 @@ public class ContentDispositionHeaderValue
3837
3938 // attr-char definition from RFC5987
4039 // Same as token except ( "*" / "'" / "%" )
41- private static readonly SearchValues < byte > Rfc5987AttrChar =
42- SearchValues . Create ( "!#$&+-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ^_`abcdefghijklmnopqrstuvwxyz|~"u8 ) ;
40+ private static readonly SearchValues < char > Rfc5987AttrChar =
41+ SearchValues . Create ( "!#$&+-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ^_`abcdefghijklmnopqrstuvwxyz|~" ) ;
4342
4443 private static readonly HttpHeaderParser < ContentDispositionHeaderValue > Parser
4544 = new GenericHeaderParser < ContentDispositionHeaderValue > ( false , GetDispositionTypeLength ) ;
@@ -619,58 +618,42 @@ private static bool TryDecodeMime(StringSegment input, [NotNullWhen(true)] out s
619618 private static string Encode5987 ( StringSegment input )
620619 {
621620 var builder = new StringBuilder ( "UTF-8\' \' " ) ;
622-
623- var maxInputBytes = Encoding . UTF8 . GetMaxByteCount ( input . Length ) ;
624- byte [ ] ? bufferFromPool = null ;
625- Span < byte > inputBytes = maxInputBytes <= MaxStackAllocSizeBytes
626- ? stackalloc byte [ MaxStackAllocSizeBytes ]
627- : bufferFromPool = ArrayPool < byte > . Shared . Rent ( maxInputBytes ) ;
628-
629- char [ ] ? charBufferFromPool = null ;
630- Span < char > tempCharBuffer = input . Length <= MaxStackAllocSizeChars
631- ? stackalloc char [ MaxStackAllocSizeChars ]
632- : charBufferFromPool = ArrayPool < char > . Shared . Rent ( input . Length ) ;
633-
634- var bytesWritten = Encoding . UTF8 . GetBytes ( input , inputBytes ) ;
635- inputBytes = inputBytes [ ..bytesWritten ] ;
636-
637- while ( inputBytes . Length > 0 )
621+ Span < byte > utf8CharBuffer = stackalloc byte [ 4 ] ;
622+ var remaining = input . AsSpan ( ) ;
623+ while ( remaining . Length > 0 )
638624 {
639- var length = inputBytes . IndexOfAnyExcept ( Rfc5987AttrChar ) ;
625+ var length = remaining . IndexOfAnyExcept ( Rfc5987AttrChar ) ;
640626 if ( length < 0 )
641627 {
642- length = inputBytes . Length ;
628+ length = remaining . Length ;
643629 }
644- int asciiCharCount = Encoding . ASCII . GetChars ( inputBytes . Slice ( 0 , length ) , tempCharBuffer ) ;
645- builder . Append ( tempCharBuffer [ ..asciiCharCount ] ) ;
630+ builder . Append ( remaining [ ..length ] ) ;
646631
647- inputBytes = inputBytes . Slice ( length ) ;
648- if ( inputBytes . Length == 0 )
632+ remaining = remaining . Slice ( length ) ;
633+ if ( remaining . Length == 0 )
649634 {
650635 break ;
651636 }
652637
653- length = inputBytes . IndexOfAny ( Rfc5987AttrChar ) ;
638+ length = remaining . IndexOfAny ( Rfc5987AttrChar ) ;
654639 if ( length < 0 )
655640 {
656- length = inputBytes . Length ;
641+ length = remaining . Length ;
657642 }
658643
659- for ( int i = 0 ; i < length ; i ++ )
644+ for ( int i = 0 ; i < length ; )
660645 {
661- HexEscape ( builder , inputBytes [ i ] ) ;
662- }
663-
664- inputBytes = inputBytes . Slice ( length ) ;
665- }
666-
667- if ( bufferFromPool is not null )
646+ 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 ++ )
668649 {
669- ArrayPool < byte > . Shared . Return ( bufferFromPool ) ;
650+ var utf8Part = utf8CharBuffer [ j ] ;
651+ builder . Append ( CultureInfo . InvariantCulture , $ "%{ HexUpperChars [ ( utf8Part & 0xf0 ) >> 4 ] } { HexUpperChars [ utf8Part & 0xf ] } ") ;
670652 }
671- if ( charBufferFromPool is not null )
672- {
673- ArrayPool < char > . Shared . Return ( charBufferFromPool ) ;
653+ i += runeLength ;
654+ }
655+
656+ remaining = remaining . Slice ( length ) ;
674657 }
675658
676659 return builder . ToString ( ) ;
0 commit comments