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