Merge pull request #2893 from swaroop-sridhar/redirect
[platform/upstream/coreclr.git] / src / mscorlib / src / System / Text / UTF7Encoding.cs
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4
5 //
6 // Don't override IsAlwaysNormalized because it is just a Unicode Transformation and could be confused.
7 //
8
9 namespace System.Text
10 {
11     using System;
12     using System.Runtime.Serialization;
13     using System.Security.Permissions;
14     using System.Diagnostics.Contracts;
15
16
17     [Serializable]
18 [System.Runtime.InteropServices.ComVisible(true)]
19     public class UTF7Encoding : Encoding
20     {
21         private const String base64Chars =
22             "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
23         //   0123456789111111111122222222223333333333444444444455555555556666
24         //             012345678901234567890123456789012345678901234567890123
25
26         // These are the characters that can be directly encoded in UTF7.
27         private const String directChars =
28             "\t\n\r '(),-./0123456789:?ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
29
30         // These are the characters that can be optionally directly encoded in UTF7.
31         private const String optionalChars =
32             "!\"#$%&*;<=>@[]^_`{|}";
33
34         // The set of base 64 characters.
35         private byte[] base64Bytes;
36         // The decoded bits for every base64 values. This array has a size of 128 elements.
37         // The index is the code point value of the base 64 characters.  The value is -1 if
38         // the code point is not a valid base 64 character.  Otherwise, the value is a value
39         // from 0 ~ 63.
40         private sbyte[] base64Values;
41         // The array to decide if a Unicode code point below 0x80 can be directly encoded in UTF7.
42         // This array has a size of 128.
43         private bool[] directEncode;
44
45         [OptionalField(VersionAdded = 2)]
46         private bool   m_allowOptionals;
47
48         private const int UTF7_CODEPAGE=65000;
49
50
51         public UTF7Encoding()
52             : this(false)
53         {
54         }
55
56         public UTF7Encoding(bool allowOptionals)
57             : base(UTF7_CODEPAGE) //Set the data item.
58         {
59             // Allowing optionals?
60             this.m_allowOptionals = allowOptionals;
61
62             // Make our tables
63             MakeTables();
64         }
65
66         private void MakeTables()
67         {
68             // Build our tables
69             base64Bytes = new byte[64];
70             for (int i = 0; i < 64; i++) base64Bytes[i] = (byte)base64Chars[i];
71             base64Values = new sbyte[128];
72             for (int i = 0; i < 128; i++) base64Values[i] = -1;
73             for (int i = 0; i < 64; i++) base64Values[base64Bytes[i]] = (sbyte)i;
74             directEncode = new bool[128];
75             int count = directChars.Length;
76             for (int i = 0; i < count; i++)
77             {
78                 directEncode[directChars[i]] = true;
79             }
80
81             if (this.m_allowOptionals)
82             {
83                 count = optionalChars.Length;
84                 for (int i = 0; i < count; i++)
85                 {
86                     directEncode[optionalChars[i]] = true;
87                 }
88             }
89         }
90
91         // We go ahead and set this because Encoding expects it, however nothing can fall back in UTF7.
92         internal override void SetDefaultFallbacks()
93         {
94             // UTF7 had an odd decoderFallback behavior, and the Encoder fallback
95             // is irrelevent because we encode surrogates individually and never check for unmatched ones
96             // (so nothing can fallback during encoding)
97             this.encoderFallback = new EncoderReplacementFallback(String.Empty);
98             this.decoderFallback = new DecoderUTF7Fallback();
99         }
100
101
102 #region Serialization
103         [OnDeserializing]
104         private void OnDeserializing(StreamingContext ctx)
105         {
106             // make sure the optional fields initialized correctly.
107             base.OnDeserializing();
108         }
109
110         [OnDeserialized]
111         private void OnDeserialized(StreamingContext ctx)
112         {
113             base.OnDeserialized();
114
115             if (m_deserializedFromEverett)
116             {
117                 // If 1st optional char is encoded we're allowing optionals
118                 m_allowOptionals = directEncode[optionalChars[0]];
119             }
120
121             MakeTables();
122         }
123 #endregion Serialization
124
125
126
127         [System.Runtime.InteropServices.ComVisible(false)]
128         public override bool Equals(Object value)
129         {
130             UTF7Encoding that = value as UTF7Encoding;
131             if (that != null)
132             {
133                 return (m_allowOptionals == that.m_allowOptionals) &&
134                        (EncoderFallback.Equals(that.EncoderFallback)) &&
135                        (DecoderFallback.Equals(that.DecoderFallback));
136             }
137             return (false);
138         }
139
140         // Compared to all the other encodings, variations of UTF7 are unlikely
141
142         [System.Runtime.InteropServices.ComVisible(false)]
143         public override int GetHashCode()
144         {
145             return this.CodePage + this.EncoderFallback.GetHashCode() + this.DecoderFallback.GetHashCode();
146         }
147
148         //
149         // The following methods are copied from EncodingNLS.cs.
150         // Unfortunately EncodingNLS.cs is internal and we're public, so we have to reimpliment them here.
151         // These should be kept in sync for the following classes:
152         // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
153         //
154
155         // Returns the number of bytes required to encode a range of characters in
156         // a character array.
157         //
158         // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
159         // So if you fix this, fix the others.  Currently those include:
160         // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
161         // parent method is safe
162
163         [System.Security.SecuritySafeCritical]  // auto-generated
164         public override unsafe int GetByteCount(char[] chars, int index, int count)
165         {
166             // Validate input parameters
167             if (chars == null)
168                 throw new ArgumentNullException("chars",
169                       Environment.GetResourceString("ArgumentNull_Array"));
170
171             if (index < 0 || count < 0)
172                 throw new ArgumentOutOfRangeException((index<0 ? "index" : "count"),
173                       Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
174
175             if (chars.Length - index < count)
176                 throw new ArgumentOutOfRangeException("chars",
177                       Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
178             Contract.EndContractBlock();
179
180             // If no input, return 0, avoid fixed empty array problem
181             if (chars.Length == 0)
182                 return 0;
183
184             // Just call the pointer version
185             fixed (char* pChars = chars)
186                 return GetByteCount(pChars + index, count, null);
187         }
188
189         // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
190         // So if you fix this, fix the others.  Currently those include:
191         // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
192         // parent method is safe
193
194         [System.Security.SecuritySafeCritical]  // auto-generated
195         [System.Runtime.InteropServices.ComVisible(false)]
196         public override unsafe int GetByteCount(String s)
197         {
198             // Validate input
199             if (s==null)
200                 throw new ArgumentNullException("s");
201             Contract.EndContractBlock();
202
203             fixed (char* pChars = s)
204                 return GetByteCount(pChars, s.Length, null);
205         }
206
207         // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
208         // So if you fix this, fix the others.  Currently those include:
209         // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
210
211         [System.Security.SecurityCritical]  // auto-generated
212         [CLSCompliant(false)]
213         [System.Runtime.InteropServices.ComVisible(false)]
214         public override unsafe int GetByteCount(char* chars, int count)
215         {
216             // Validate Parameters
217             if (chars == null)
218                 throw new ArgumentNullException("chars",
219                     Environment.GetResourceString("ArgumentNull_Array"));
220
221             if (count < 0)
222                 throw new ArgumentOutOfRangeException("count",
223                     Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
224             Contract.EndContractBlock();
225
226             // Call it with empty encoder
227             return GetByteCount(chars, count, null);
228         }
229
230         // Parent method is safe.
231         // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
232         // So if you fix this, fix the others.  Currently those include:
233         // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
234
235         [System.Security.SecuritySafeCritical]  // auto-generated
236         [System.Runtime.InteropServices.ComVisible(false)]
237         public override unsafe int GetBytes(String s, int charIndex, int charCount,
238                                               byte[] bytes, int byteIndex)
239         {
240             if (s == null || bytes == null)
241                 throw new ArgumentNullException((s == null ? "s" : "bytes"),
242                       Environment.GetResourceString("ArgumentNull_Array"));
243
244             if (charIndex < 0 || charCount < 0)
245                 throw new ArgumentOutOfRangeException((charIndex<0 ? "charIndex" : "charCount"),
246                       Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
247
248             if (s.Length - charIndex < charCount)
249                 throw new ArgumentOutOfRangeException("s",
250                       Environment.GetResourceString("ArgumentOutOfRange_IndexCount"));
251
252             if (byteIndex < 0 || byteIndex > bytes.Length)
253                 throw new ArgumentOutOfRangeException("byteIndex",
254                     Environment.GetResourceString("ArgumentOutOfRange_Index"));
255             Contract.EndContractBlock();
256
257             int byteCount = bytes.Length - byteIndex;
258
259             // Fixed doesn't like empty arrays
260             if (bytes.Length == 0)
261                 bytes = new byte[1];
262
263             fixed (char* pChars = s)
264                 fixed ( byte* pBytes = bytes)
265                     return GetBytes(pChars + charIndex, charCount,
266                                     pBytes + byteIndex, byteCount, null);
267         }
268
269         // Encodes a range of characters in a character array into a range of bytes
270         // in a byte array. An exception occurs if the byte array is not large
271         // enough to hold the complete encoding of the characters. The
272         // GetByteCount method can be used to determine the exact number of
273         // bytes that will be produced for a given range of characters.
274         // Alternatively, the GetMaxByteCount method can be used to
275         // determine the maximum number of bytes that will be produced for a given
276         // number of characters, regardless of the actual character values.
277         //
278         // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
279         // So if you fix this, fix the others.  Currently those include:
280         // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
281         // parent method is safe
282
283         [System.Security.SecuritySafeCritical]  // auto-generated
284         public override unsafe int GetBytes(char[] chars, int charIndex, int charCount,
285                                                byte[] bytes, int byteIndex)
286         {
287             // Validate parameters
288             if (chars == null || bytes == null)
289                 throw new ArgumentNullException((chars == null ? "chars" : "bytes"),
290                       Environment.GetResourceString("ArgumentNull_Array"));
291
292             if (charIndex < 0 || charCount < 0)
293                 throw new ArgumentOutOfRangeException((charIndex<0 ? "charIndex" : "charCount"),
294                       Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
295
296             if (chars.Length - charIndex < charCount)
297                 throw new ArgumentOutOfRangeException("chars",
298                       Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
299
300             if (byteIndex < 0 || byteIndex > bytes.Length)
301                 throw new ArgumentOutOfRangeException("byteIndex",
302                      Environment.GetResourceString("ArgumentOutOfRange_Index"));
303             Contract.EndContractBlock();
304
305             // If nothing to encode return 0, avoid fixed problem
306             if (chars.Length == 0)
307                 return 0;
308
309             // Just call pointer version
310             int byteCount = bytes.Length - byteIndex;
311
312             // Fixed doesn't like empty arrays
313             if (bytes.Length == 0)
314                 bytes = new byte[1];
315
316             fixed (char* pChars = chars)
317                 fixed (byte* pBytes = bytes)
318                     // Remember that byteCount is # to decode, not size of array.
319                     return GetBytes(pChars + charIndex, charCount,
320                                     pBytes + byteIndex, byteCount, null);
321         }
322
323         // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
324         // So if you fix this, fix the others.  Currently those include:
325         // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
326
327         [System.Security.SecurityCritical]  // auto-generated
328         [CLSCompliant(false)]
329         [System.Runtime.InteropServices.ComVisible(false)]
330         public override unsafe int GetBytes(char* chars, int charCount, byte* bytes, int byteCount)
331         {
332             // Validate Parameters
333             if (bytes == null || chars == null)
334                 throw new ArgumentNullException(bytes == null ? "bytes" : "chars",
335                     Environment.GetResourceString("ArgumentNull_Array"));
336
337             if (charCount < 0 || byteCount < 0)
338                 throw new ArgumentOutOfRangeException((charCount<0 ? "charCount" : "byteCount"),
339                     Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
340             Contract.EndContractBlock();
341
342             return GetBytes(chars, charCount, bytes, byteCount, null);
343         }
344
345         // Returns the number of characters produced by decoding a range of bytes
346         // in a byte array.
347         //
348         // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
349         // So if you fix this, fix the others.  Currently those include:
350         // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
351         // parent method is safe
352
353         [System.Security.SecuritySafeCritical]  // auto-generated
354         public override unsafe int GetCharCount(byte[] bytes, int index, int count)
355         {
356             // Validate Parameters
357             if (bytes == null)
358                 throw new ArgumentNullException("bytes",
359                     Environment.GetResourceString("ArgumentNull_Array"));
360
361             if (index < 0 || count < 0)
362                 throw new ArgumentOutOfRangeException((index<0 ? "index" : "count"),
363                     Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
364
365             if (bytes.Length - index < count)
366                 throw new ArgumentOutOfRangeException("bytes",
367                     Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
368             Contract.EndContractBlock();
369
370             // If no input just return 0, fixed doesn't like 0 length arrays.
371             if (bytes.Length == 0)
372                 return 0;
373
374             // Just call pointer version
375             fixed (byte* pBytes = bytes)
376                 return GetCharCount(pBytes + index, count, null);
377         }
378
379         // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
380         // So if you fix this, fix the others.  Currently those include:
381         // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
382
383         [System.Security.SecurityCritical]  // auto-generated
384         [CLSCompliant(false)]
385         [System.Runtime.InteropServices.ComVisible(false)]
386         public override unsafe int GetCharCount(byte* bytes, int count)
387         {
388             // Validate Parameters
389             if (bytes == null)
390                 throw new ArgumentNullException("bytes",
391                     Environment.GetResourceString("ArgumentNull_Array"));
392
393             if (count < 0)
394                 throw new ArgumentOutOfRangeException("count",
395                     Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
396             Contract.EndContractBlock();
397
398             return GetCharCount(bytes, count, null);
399         }
400
401         // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
402         // So if you fix this, fix the others.  Currently those include:
403         // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
404         // parent method is safe
405
406         [System.Security.SecuritySafeCritical]  // auto-generated
407         public override unsafe int GetChars(byte[] bytes, int byteIndex, int byteCount,
408                                               char[] chars, int charIndex)
409         {
410             // Validate Parameters
411             if (bytes == null || chars == null)
412                 throw new ArgumentNullException(bytes == null ? "bytes" : "chars",
413                     Environment.GetResourceString("ArgumentNull_Array"));
414
415             if (byteIndex < 0 || byteCount < 0)
416                 throw new ArgumentOutOfRangeException((byteIndex<0 ? "byteIndex" : "byteCount"),
417                     Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
418
419             if ( bytes.Length - byteIndex < byteCount)
420                 throw new ArgumentOutOfRangeException("bytes",
421                     Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
422
423             if (charIndex < 0 || charIndex > chars.Length)
424                 throw new ArgumentOutOfRangeException("charIndex",
425                     Environment.GetResourceString("ArgumentOutOfRange_Index"));
426             Contract.EndContractBlock();
427
428             // If no input, return 0 & avoid fixed problem
429             if (bytes.Length == 0)
430                 return 0;
431
432             // Just call pointer version
433             int charCount = chars.Length - charIndex;
434
435             // Fixed doesn't like empty arrays
436             if (chars.Length == 0)
437                 chars = new char[1];
438
439             fixed (byte* pBytes = bytes)
440                 fixed (char* pChars = chars)
441                     // Remember that charCount is # to decode, not size of array
442                     return GetChars(pBytes + byteIndex, byteCount,
443                                     pChars + charIndex, charCount, null);
444         }
445
446         // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
447         // So if you fix this, fix the others.  Currently those include:
448         // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
449
450         [System.Security.SecurityCritical]  // auto-generated
451         [CLSCompliant(false)]
452         [System.Runtime.InteropServices.ComVisible(false)]
453         public unsafe override int GetChars(byte* bytes, int byteCount, char* chars, int charCount)
454         {
455             // Validate Parameters
456             if (bytes == null || chars == null)
457                 throw new ArgumentNullException(bytes == null ? "bytes" : "chars",
458                     Environment.GetResourceString("ArgumentNull_Array"));
459
460             if (charCount < 0 || byteCount < 0)
461                 throw new ArgumentOutOfRangeException((charCount<0 ? "charCount" : "byteCount"),
462                     Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
463             Contract.EndContractBlock();
464
465             return GetChars(bytes, byteCount, chars, charCount, null);
466         }
467
468         // Returns a string containing the decoded representation of a range of
469         // bytes in a byte array.
470         //
471         // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
472         // So if you fix this, fix the others.  Currently those include:
473         // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
474         // parent method is safe
475
476         [System.Security.SecuritySafeCritical]  // auto-generated
477         [System.Runtime.InteropServices.ComVisible(false)]
478         public override unsafe String GetString(byte[] bytes, int index, int count)
479         {
480             // Validate Parameters
481             if (bytes == null)
482                 throw new ArgumentNullException("bytes",
483                     Environment.GetResourceString("ArgumentNull_Array"));
484
485             if (index < 0 || count < 0)
486                 throw new ArgumentOutOfRangeException((index < 0 ? "index" : "count"),
487                     Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
488
489             if (bytes.Length - index < count)
490                 throw new ArgumentOutOfRangeException("bytes",
491                     Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
492             Contract.EndContractBlock();
493
494             // Avoid problems with empty input buffer
495             if (bytes.Length == 0) return String.Empty;
496
497             fixed (byte* pBytes = bytes)
498                 return String.CreateStringFromEncoding(
499                     pBytes + index, count, this);
500         }
501
502         //
503         // End of standard methods copied from EncodingNLS.cs
504         //
505
506         [System.Security.SecurityCritical]  // auto-generated
507         internal override unsafe int GetByteCount(char* chars, int count, EncoderNLS baseEncoder)
508         {
509             Contract.Assert(chars!=null, "[UTF7Encoding.GetByteCount]chars!=null");
510             Contract.Assert(count >=0, "[UTF7Encoding.GetByteCount]count >=0");
511
512             // Just call GetBytes with bytes == null
513             return GetBytes(chars, count, null, 0, baseEncoder);
514         }
515
516         [System.Security.SecurityCritical]  // auto-generated
517         internal override unsafe int GetBytes(char* chars, int charCount,
518                                                 byte* bytes, int byteCount, EncoderNLS baseEncoder)
519         {
520             Contract.Assert(byteCount >=0, "[UTF7Encoding.GetBytes]byteCount >=0");
521             Contract.Assert(chars!=null, "[UTF7Encoding.GetBytes]chars!=null");
522             Contract.Assert(charCount >=0, "[UTF7Encoding.GetBytes]charCount >=0");
523
524             // Get encoder info
525             UTF7Encoding.Encoder encoder = (UTF7Encoding.Encoder)baseEncoder;
526
527             // Default bits & count
528             int bits = 0;
529             int bitCount = -1;
530
531             // prepare our helpers
532             Encoding.EncodingByteBuffer buffer = new Encoding.EncodingByteBuffer(
533                 this, encoder, bytes, byteCount, chars, charCount);
534
535             if (encoder != null)
536             {
537                 bits = encoder.bits;
538                 bitCount = encoder.bitCount;
539
540                 // May have had too many left over
541                 while (bitCount >= 6)
542                 {
543                     bitCount -= 6;
544                     // If we fail we'll never really have enough room
545                     if (!buffer.AddByte(base64Bytes[(bits >> bitCount) & 0x3F]))
546                         ThrowBytesOverflow(encoder, buffer.Count == 0);
547                 }
548             }
549
550             while (buffer.MoreData)
551             {
552                 char currentChar = buffer.GetNextChar();
553
554                 if (currentChar < 0x80 && directEncode[currentChar])
555                 {
556                     if (bitCount >= 0)
557                     {
558                         if (bitCount > 0)
559                         {
560                             // Try to add the next byte
561                             if (!buffer.AddByte(base64Bytes[bits << 6 - bitCount & 0x3F]))
562                                 break;                                          // Stop here, didn't throw
563
564                             bitCount = 0;
565                         }
566
567                         // Need to get emit '-' and our char, 2 bytes total
568                         if (!buffer.AddByte((byte)'-'))
569                             break;                                          // Stop here, didn't throw
570
571                         bitCount = -1;
572                     }
573
574                     // Need to emit our char
575                     if (!buffer.AddByte((byte)currentChar))
576                         break;                                          // Stop here, didn't throw
577                 }
578                 else if (bitCount < 0 && currentChar == '+')
579                 {
580                     if (!buffer.AddByte((byte)'+', (byte)'-'))
581                         break;                                          // Stop here, didn't throw
582                 }
583                 else
584                 {
585                     if (bitCount < 0)
586                     {
587                         // Need to emit a + and 12 bits (3 bytes)
588                         // Only 12 of the 16 bits will be emitted this time, the other 4 wait 'til next time
589                         if (!buffer.AddByte((byte)'+'))
590                             break;                                          // Stop here, didn't throw
591
592                         // We're now in bit mode, but haven't stored data yet
593                         bitCount = 0;
594                     }
595
596                     // Add our bits
597                     bits = bits << 16 | currentChar;
598                     bitCount += 16;
599
600                     while (bitCount >= 6)
601                     {
602                         bitCount -= 6;
603                         if (!buffer.AddByte(base64Bytes[(bits >> bitCount) & 0x3F]))
604                         {
605                             bitCount += 6;                              // We didn't use these bits
606                             currentChar = buffer.GetNextChar();              // We're processing this char still, but AddByte
607                                                                         // --'d it when we ran out of space
608                             break;                                      // Stop here, not enough room for bytes
609                         }
610                     }
611
612                     if (bitCount >= 6)
613                         break;                  // Didn't have room to encode enough bits
614                 }
615             }
616
617             // Now if we have bits left over we have to encode them.
618             // MustFlush may have been cleared by encoding.ThrowBytesOverflow earlier if converting
619             if (bitCount >= 0 && (encoder == null || encoder.MustFlush))
620             {
621                 // Do we have bits we have to stick in?
622                 if (bitCount > 0)
623                 {
624                     if (buffer.AddByte(base64Bytes[(bits << (6 - bitCount)) & 0x3F]))
625                     {
626                         // Emitted spare bits, 0 bits left
627                         bitCount = 0;
628                     }
629                 }
630
631                 // If converting and failed bitCount above, then we'll fail this too
632                 if (buffer.AddByte((byte)'-'))
633                 {
634                     // turned off bit mode';
635                     bits = 0;
636                     bitCount = -1;
637                 }
638                 else
639                     // If not successful, convert will maintain state for next time, also
640                     // AddByte will have decremented our char count, however we need it to remain the same
641                     buffer.GetNextChar();
642             }
643
644             // Do we have an encoder we're allowed to use?
645             // bytes == null if counting, so don't use encoder then
646             if (bytes != null && encoder != null)
647             {
648                 // We already cleared bits & bitcount for mustflush case
649                 encoder.bits = bits;
650                 encoder.bitCount = bitCount;
651                 encoder.m_charsUsed = buffer.CharsUsed;
652             }
653
654             return buffer.Count;
655         }
656
657         [System.Security.SecurityCritical]  // auto-generated
658         internal override unsafe int GetCharCount(byte* bytes, int count, DecoderNLS baseDecoder)
659         {
660             Contract.Assert(count >=0, "[UTF7Encoding.GetCharCount]count >=0");
661             Contract.Assert(bytes!=null, "[UTF7Encoding.GetCharCount]bytes!=null");
662
663             // Just call GetChars with null char* to do counting
664             return GetChars(bytes, count, null, 0, baseDecoder);
665         }
666
667         [System.Security.SecurityCritical]  // auto-generated
668         internal override unsafe int GetChars(byte* bytes, int byteCount,
669                                                 char* chars, int charCount, DecoderNLS baseDecoder)
670         {
671             Contract.Assert(byteCount >=0, "[UTF7Encoding.GetChars]byteCount >=0");
672             Contract.Assert(bytes!=null, "[UTF7Encoding.GetChars]bytes!=null");
673             Contract.Assert(charCount >=0, "[UTF7Encoding.GetChars]charCount >=0");
674
675             // Might use a decoder
676             UTF7Encoding.Decoder decoder = (UTF7Encoding.Decoder) baseDecoder;
677
678             // Get our output buffer info.
679             Encoding.EncodingCharBuffer buffer = new Encoding.EncodingCharBuffer(
680                 this, decoder, chars, charCount, bytes, byteCount);
681
682             // Get decoder info
683             int bits = 0;
684             int bitCount = -1;
685             bool firstByte = false;
686             if (decoder != null)
687             {
688                 bits = decoder.bits;
689                 bitCount = decoder.bitCount;
690                 firstByte = decoder.firstByte;
691
692                 Contract.Assert(firstByte == false || decoder.bitCount <= 0,
693                     "[UTF7Encoding.GetChars]If remembered bits, then first byte flag shouldn't be set");
694             }
695
696             // We may have had bits in the decoder that we couldn't output last time, so do so now
697             if (bitCount >= 16)
698             {
699                 // Check our decoder buffer
700                 if (!buffer.AddChar((char)((bits >> (bitCount - 16)) & 0xFFFF)))
701                     ThrowCharsOverflow(decoder, true);  // Always throw, they need at least 1 char even in Convert
702
703                 // Used this one, clean up extra bits
704                 bitCount -= 16;
705             }
706
707             // Loop through the input
708             while (buffer.MoreData)
709             {
710                 byte currentByte = buffer.GetNextByte();
711                 int c;
712
713                 if (bitCount >= 0)
714                 {
715                     //
716                     // Modified base 64 encoding.
717                     //
718                     sbyte v;
719                     if (currentByte < 0x80 && ((v = base64Values[currentByte]) >=0))
720                     {
721                         firstByte = false;
722                         bits = (bits << 6) | ((byte)v);
723                         bitCount += 6;
724                         if (bitCount >= 16)
725                         {
726                             c = (bits >> (bitCount - 16)) & 0xFFFF;
727                             bitCount -= 16;
728                         }
729                         // If not enough bits just continue
730                         else continue;
731                     }
732                     else
733                     {
734                         // If it wasn't a base 64 byte, everything's going to turn off base 64 mode
735                         bitCount = -1;
736
737                         if (currentByte != '-')
738                         {
739                             // >= 0x80 (because of 1st if statemtn)
740                             // We need this check since the base64Values[b] check below need b <= 0x7f.
741                             // This is not a valid base 64 byte.  Terminate the shifted-sequence and
742                             // emit this byte.
743
744                             // not in base 64 table
745                             // According to the RFC 1642 and the example code of UTF-7
746                             // in Unicode 2.0, we should just zero-extend the invalid UTF7 byte
747
748                             // Chars won't be updated unless this works, try to fallback
749                             if (!buffer.Fallback(currentByte))
750                                 break;                                          // Stop here, didn't throw
751
752                             // Used that byte, we're done with it
753                             continue;
754                         }
755
756                         //
757                         // The encoding for '+' is "+-".
758                         //
759                         if (firstByte) c = '+';
760                         // We just turn it off if not emitting a +, so we're done.
761                         else continue;
762                     }
763                     //
764                     // End of modified base 64 encoding block.
765                     //
766                 }
767                 else if (currentByte == '+')
768                 {
769                     //
770                     // Found the start of a modified base 64 encoding block or a plus sign.
771                     //
772                     bitCount = 0;
773                     firstByte = true;
774                     continue;
775                 }
776                 else
777                 {
778                     // Normal character
779                     if (currentByte >= 0x80)
780                     {
781                         // Try to fallback
782                         if (!buffer.Fallback(currentByte))
783                             break;                                          // Stop here, didn't throw
784
785                         // Done falling back
786                         continue;
787                     }
788
789                     // Use the normal character
790                     c = currentByte;
791                 }
792
793                 if (c >= 0)
794                 {
795                     // Check our buffer
796                     if (!buffer.AddChar((char)c))
797                     {
798                         // No room.  If it was a plain char we'll try again later.
799                         // Note, we'll consume this byte and stick it in decoder, even if we can't output it
800                         if (bitCount >= 0)                                  // Can we rememmber this byte (char)
801                         {
802                             buffer.AdjustBytes(+1);                         // Need to readd the byte that AddChar subtracted when it failed
803                             bitCount += 16;                                 // We'll still need that char we have in our bits
804                         }
805                         break;                                              // didn't throw, stop
806                     }
807                 }
808             }
809
810             // Stick stuff in the decoder if we can (chars == null if counting, so don't store decoder)
811             if (chars != null && decoder != null)
812             {
813                 // MustFlush?  (Could've been cleared by ThrowCharsOverflow if Convert & didn't reach end of buffer)
814                 if (decoder.MustFlush)
815                 {
816                     // RFC doesn't specify what would happen if we have non-0 leftover bits, we just drop them
817                     decoder.bits = 0;
818                     decoder.bitCount = -1;
819                     decoder.firstByte = false;
820                 }
821                 else
822                 {
823                     decoder.bits = bits;
824                     decoder.bitCount = bitCount;
825                     decoder.firstByte = firstByte;
826                 }
827                 decoder.m_bytesUsed = buffer.BytesUsed;
828             }
829             // else ignore any hanging bits.
830
831             // Return our count
832             return buffer.Count;
833         }
834
835
836         public override System.Text.Decoder GetDecoder()
837         {
838             return new UTF7Encoding.Decoder(this);
839         }
840
841
842         public override System.Text.Encoder GetEncoder()
843         {
844             return new UTF7Encoding.Encoder(this);
845         }
846
847
848         public override int GetMaxByteCount(int charCount)
849         {
850             if (charCount < 0)
851                throw new ArgumentOutOfRangeException("charCount",
852                     Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
853             Contract.EndContractBlock();
854
855             // Suppose that every char can not be direct-encoded, we know that
856             // a byte can encode 6 bits of the Unicode character.  And we will
857             // also need two extra bytes for the shift-in ('+') and shift-out ('-') mark.
858             // Therefore, the max byte should be:
859             // byteCount = 2 + Math.Ceiling((double)charCount * 16 / 6);
860             // That is always <= 2 + 3 * charCount;
861             // Longest case is alternating encoded, direct, encoded data for 5 + 1 + 5... bytes per char.
862             // UTF7 doesn't have left over surrogates, but if no input we may need an output - to turn off
863             // encoding if MustFlush is true.
864
865             // Its easiest to think of this as 2 bytes to turn on/off the base64 mode, then 3 bytes per char.
866             // 3 bytes is 18 bits of encoding, which is more than we need, but if its direct encoded then 3
867             // bytes allows us to turn off and then back on base64 mode if necessary.
868
869             // Note that UTF7 encoded surrogates individually and isn't worried about mismatches, so all
870             // code points are encodable int UTF7.
871             long byteCount = (long)charCount * 3 + 2;
872
873             // check for overflow
874             if (byteCount > 0x7fffffff)
875                 throw new ArgumentOutOfRangeException("charCount", Environment.GetResourceString("ArgumentOutOfRange_GetByteCountOverflow"));
876
877             return (int)byteCount;
878         }
879
880
881         public override int GetMaxCharCount(int byteCount)
882         {
883             if (byteCount < 0)
884                throw new ArgumentOutOfRangeException("byteCount",
885                     Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
886             Contract.EndContractBlock();
887
888             // Worst case is 1 char per byte.  Minimum 1 for left over bits in case decoder is being flushed
889             // Also note that we ignore extra bits (per spec), so UTF7 doesn't have unknown in this direction.
890             int charCount = byteCount;
891             if (charCount == 0) charCount = 1;
892
893             return charCount;
894         }
895
896         [Serializable]
897         // Of all the amazing things... This MUST be Decoder so that our com name
898         // for System.Text.Decoder doesn't change
899         private class Decoder : DecoderNLS, ISerializable
900         {
901             /*private*/ internal int bits;
902             /*private*/ internal int bitCount;
903             /*private*/ internal bool firstByte;
904
905             public Decoder(UTF7Encoding encoding) : base (encoding)
906             {
907                 // base calls reset
908             }
909
910             // Constructor called by serialization, have to handle deserializing from Everett
911             internal Decoder(SerializationInfo info, StreamingContext context)
912             {
913                 // Any info?
914                 if (info==null) throw new ArgumentNullException("info");
915                 Contract.EndContractBlock();
916
917                 // Get common info
918                 this.bits = (int)info.GetValue("bits", typeof(int));
919                 this.bitCount = (int)info.GetValue("bitCount", typeof(int));
920                 this.firstByte = (bool)info.GetValue("firstByte", typeof(bool));
921                 this.m_encoding = (Encoding)info.GetValue("encoding", typeof(Encoding));
922             }
923
924 #if FEATURE_SERIALIZATION
925             // ISerializable implementation, get data for this object
926             [System.Security.SecurityCritical]  // auto-generated_required
927             void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
928             {
929                 // Any info?
930                 if (info==null) throw new ArgumentNullException("info");
931                 Contract.EndContractBlock();
932
933                 // Save Whidbey data
934                 info.AddValue("encoding", this.m_encoding);
935                 info.AddValue("bits", this.bits);
936                 info.AddValue("bitCount", this.bitCount);
937                 info.AddValue("firstByte", this.firstByte);
938             }
939 #endif
940
941             public override void Reset()
942             {
943                 this.bits = 0;
944                 this.bitCount = -1;
945                 this.firstByte = false;
946                 if (m_fallbackBuffer != null)
947                     m_fallbackBuffer.Reset();
948             }
949
950             // Anything left in our encoder?
951             internal override bool HasState
952             {
953                 get
954                 {
955                     // NOTE: This forces the last -, which some encoder might not encode.  If we
956                     // don't see it we don't think we're done reading.
957                     return (this.bitCount != -1);
958                 }
959             }
960         }
961
962         [Serializable]
963         // Of all the amazing things... This MUST be Encoder so that our com name
964         // for System.Text.Encoder doesn't change
965         private class Encoder : EncoderNLS, ISerializable
966         {
967             /*private*/ internal int bits;
968             /*private*/ internal int bitCount;
969
970             public Encoder(UTF7Encoding encoding) : base(encoding)
971             {
972                 // base calls reset
973             }
974
975             // Constructor called by serialization, have to handle deserializing from Everett
976             internal Encoder(SerializationInfo info, StreamingContext context)
977             {
978                 // Any info?
979                 if (info==null) throw new ArgumentNullException("info");
980                 Contract.EndContractBlock();
981
982                 // Get common info
983                 this.bits = (int)info.GetValue("bits", typeof(int));
984                 this.bitCount = (int)info.GetValue("bitCount", typeof(int));
985                 this.m_encoding = (Encoding)info.GetValue("encoding", typeof(Encoding));
986             }
987
988 #if FEATURE_SERIALIZATION
989             // ISerializable implementation, get data for this object
990             [System.Security.SecurityCritical]  // auto-generated_required
991             void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
992             {
993                 // Any info?
994                 if (info==null) throw new ArgumentNullException("info");
995                 Contract.EndContractBlock();
996
997                 // Save Whidbey data
998                 info.AddValue("encoding", this.m_encoding);
999                 info.AddValue("bits", this.bits);
1000                 info.AddValue("bitCount", this.bitCount);
1001             }
1002 #endif
1003
1004             public override void Reset()
1005             {
1006                 this.bitCount = -1;
1007                 this.bits = 0;
1008                 if (m_fallbackBuffer != null)
1009                     m_fallbackBuffer.Reset();         
1010             }
1011
1012             // Anything left in our encoder?
1013             internal override bool HasState
1014             {
1015                 get
1016                 {
1017                     return (this.bits != 0 || this.bitCount != -1);
1018                 }
1019             }
1020         }
1021
1022         // Preexisting UTF7 behavior for bad bytes was just to spit out the byte as the next char
1023         // and turn off base64 mode if it was in that mode.  We still exit the mode, but now we fallback.
1024         [Serializable]
1025         internal sealed class DecoderUTF7Fallback : DecoderFallback
1026         {
1027             // Construction.  Default replacement fallback uses no best fit and ? replacement string
1028             public DecoderUTF7Fallback()
1029             {
1030             }
1031
1032             public override DecoderFallbackBuffer CreateFallbackBuffer()
1033             {
1034                 return new DecoderUTF7FallbackBuffer(this);
1035             }
1036
1037             // Maximum number of characters that this instance of this fallback could return
1038             public override int MaxCharCount
1039             {
1040                 get
1041                 {
1042                     // returns 1 char per bad byte
1043                     return 1;
1044                 }
1045             }
1046
1047              public override bool Equals(Object value)
1048             {
1049                 DecoderUTF7Fallback that = value as DecoderUTF7Fallback;
1050                 if (that != null)
1051                 {
1052                     return true;
1053                 }
1054                 return (false);
1055             }
1056
1057             public override int GetHashCode()
1058             {
1059                 return 984;
1060             }
1061         }
1062
1063         internal sealed class DecoderUTF7FallbackBuffer : DecoderFallbackBuffer
1064         {
1065             // Store our default string
1066             char cFallback = (char)0;
1067             int  iCount = -1;
1068             int  iSize;
1069
1070             // Construction
1071             public DecoderUTF7FallbackBuffer(DecoderUTF7Fallback fallback)
1072             {
1073             }
1074
1075             // Fallback Methods
1076             public override bool Fallback(byte[] bytesUnknown, int index)
1077             {
1078                 // We expect no previous fallback in our buffer
1079                 Contract.Assert(iCount < 0, "[DecoderUTF7FallbackBuffer.Fallback] Can't have recursive fallbacks");
1080                 Contract.Assert(bytesUnknown.Length == 1, "[DecoderUTF7FallbackBuffer.Fallback] Only possible fallback case should be 1 unknown byte");
1081
1082                 // Go ahead and get our fallback
1083                 cFallback = (char)bytesUnknown[0];
1084
1085                 // Any of the fallback characters can be handled except for 0
1086                 if (cFallback == 0)
1087                 {
1088                     return false;
1089                 }
1090
1091                 iCount = iSize = 1;
1092
1093                 return true;
1094             }
1095
1096             public override char GetNextChar()
1097             {
1098                 if (iCount-- > 0)
1099                     return cFallback;
1100
1101                 // Note: this means that 0 in UTF7 stream will never be emitted.
1102                 return (char)0;
1103             }
1104
1105             public override bool MovePrevious()
1106             {
1107                 if (iCount >= 0)
1108                 {
1109                     iCount++;
1110                 }
1111
1112                 // return true if we were allowed to do this
1113                 return (iCount >= 0 && iCount <= iSize);
1114             }
1115
1116             // Return # of chars left in this fallback
1117             public override int Remaining
1118             {
1119                 get
1120                 {
1121                     return (iCount > 0) ? iCount : 0;
1122                 }
1123             }
1124
1125             // Clear the buffer
1126             [System.Security.SecuritySafeCritical] // overrides public transparent member
1127             public override unsafe void Reset()
1128             {
1129                 iCount = -1;
1130                 byteStart = null; 
1131             }
1132
1133             // This version just counts the fallback and doesn't actually copy anything.
1134             [System.Security.SecurityCritical]  // auto-generated
1135             internal unsafe override int InternalFallback(byte[] bytes, byte* pBytes)
1136             // Right now this has both bytes and bytes[], since we might have extra bytes, hence the
1137             // array, and we might need the index, hence the byte*
1138             {
1139                 // We expect no previous fallback in our buffer
1140                 Contract.Assert(iCount < 0, "[DecoderUTF7FallbackBuffer.InternalFallback] Can't have recursive fallbacks");
1141                 if (bytes.Length != 1)
1142                 {
1143                     throw new ArgumentException(Environment.GetResourceString("Argument_InvalidCharSequenceNoIndex"));
1144                 }
1145
1146                 // Can't fallback a byte 0, so return for that case, 1 otherwise.
1147                 return bytes[0] == 0 ? 0 : 1;
1148             }
1149         }
1150
1151     }
1152 }