@@ -37,19 +37,29 @@ class ImapTokenCache
3737 readonly Dictionary < ImapTokenKey , LinkedListNode < ImapTokenItem > > cache ;
3838 readonly LinkedList < ImapTokenItem > list ;
3939 readonly ImapTokenKey lookupKey ;
40+ readonly Decoder [ ] decoders ;
41+ readonly char [ ] chars ;
4042
4143 public ImapTokenCache ( )
4244 {
4345 cache = new Dictionary < ImapTokenKey , LinkedListNode < ImapTokenItem > > ( ) ;
4446 list = new LinkedList < ImapTokenItem > ( ) ;
4547 lookupKey = new ImapTokenKey ( ) ;
48+
49+ // Start with the assumption that token values will be valid UTF-8 and then fall back to iso-8859-1.
50+ decoders = new Decoder [ 2 ] {
51+ TextEncodings . UTF8 . GetDecoder ( ) ,
52+ TextEncodings . Latin1 . GetDecoder ( )
53+ } ;
54+
55+ chars = new char [ 128 ] ;
4656 }
4757
4858 public ImapToken AddOrGet ( ImapTokenType type , ByteArrayBuilder builder )
4959 {
5060 lock ( cache ) {
5161 // lookupKey is a pre-allocated key used for lookups
52- lookupKey . Init ( type , builder . GetBuffer ( ) , builder . Length ) ;
62+ lookupKey . Init ( decoders , chars , type , builder . GetBuffer ( ) , builder . Length ) ;
5363
5464 if ( cache . TryGetValue ( lookupKey , out var node ) ) {
5565 // move the node to the head of the list
@@ -102,7 +112,7 @@ public ImapTokenKey (ImapTokenType type, string key)
102112 Init ( type , key ) ;
103113 }
104114
105- public void Init ( ImapTokenType type , byte [ ] key , int length )
115+ public void Init ( Decoder [ ] decoders , char [ ] chars , ImapTokenType type , byte [ ] key , int length )
106116 {
107117 this . type = type ;
108118 this . byteArrayKey = key ;
@@ -111,8 +121,30 @@ public void Init (ImapTokenType type, byte[] key, int length)
111121
112122 var hash = new HashCode ( ) ;
113123 hash . Add ( ( int ) type ) ;
114- for ( int i = 0 ; i < length ; i ++ )
115- hash . Add ( ( char ) key [ i ] ) ;
124+
125+ foreach ( var decoder in decoders ) {
126+ bool completed ;
127+ int index = 0 ;
128+
129+ do {
130+ try {
131+ decoder . Convert ( key , index , length - index , chars , 0 , chars . Length , true , out var bytesUsed , out var charsUsed , out completed ) ;
132+ index += bytesUsed ;
133+
134+ for ( int i = 0 ; i < charsUsed ; i ++ )
135+ hash . Add ( chars [ i ] ) ;
136+ } catch ( DecoderFallbackException ) {
137+ // Restart the hash...
138+ hash = new HashCode ( ) ;
139+ hash . Add ( ( int ) type ) ;
140+ completed = false ;
141+ break ;
142+ }
143+ } while ( ! completed ) ;
144+
145+ if ( completed )
146+ break ;
147+ }
116148
117149 this . hashCode = hash . ToHashCode ( ) ;
118150 }
0 commit comments