3 // Copyright (c) Microsoft Corporation. All rights reserved.
7 // Don't override IsAlwaysNormalized because it is just a Unicode Transformation and could be confused.
13 using System.Runtime.Serialization;
14 using System.Security.Permissions;
15 using System.Diagnostics.Contracts;
19 [System.Runtime.InteropServices.ComVisible(true)]
20 public class UTF7Encoding : Encoding
22 private const String base64Chars =
23 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
24 // 0123456789111111111122222222223333333333444444444455555555556666
25 // 012345678901234567890123456789012345678901234567890123
27 // These are the characters that can be directly encoded in UTF7.
28 private const String directChars =
29 "\t\n\r '(),-./0123456789:?ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
31 // These are the characters that can be optionally directly encoded in UTF7.
32 private const String optionalChars =
33 "!\"#$%&*;<=>@[]^_`{|}";
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
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;
46 [OptionalField(VersionAdded = 2)]
47 private bool m_allowOptionals;
49 private const int UTF7_CODEPAGE=65000;
57 public UTF7Encoding(bool allowOptionals)
58 : base(UTF7_CODEPAGE) //Set the data item.
60 // Allowing optionals?
61 this.m_allowOptionals = allowOptionals;
67 private void MakeTables()
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++)
79 directEncode[directChars[i]] = true;
82 if (this.m_allowOptionals)
84 count = optionalChars.Length;
85 for (int i = 0; i < count; i++)
87 directEncode[optionalChars[i]] = true;
92 // We go ahead and set this because Encoding expects it, however nothing can fall back in UTF7.
93 internal override void SetDefaultFallbacks()
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();
103 #region Serialization
105 private void OnDeserializing(StreamingContext ctx)
107 // make sure the optional fields initialized correctly.
108 base.OnDeserializing();
112 private void OnDeserialized(StreamingContext ctx)
114 base.OnDeserialized();
116 if (m_deserializedFromEverett)
118 // If 1st optional char is encoded we're allowing optionals
119 m_allowOptionals = directEncode[optionalChars[0]];
124 #endregion Serialization
128 [System.Runtime.InteropServices.ComVisible(false)]
129 public override bool Equals(Object value)
131 UTF7Encoding that = value as UTF7Encoding;
134 return (m_allowOptionals == that.m_allowOptionals) &&
135 (EncoderFallback.Equals(that.EncoderFallback)) &&
136 (DecoderFallback.Equals(that.DecoderFallback));
141 // Compared to all the other encodings, variations of UTF7 are unlikely
143 [System.Runtime.InteropServices.ComVisible(false)]
144 public override int GetHashCode()
146 return this.CodePage + this.EncoderFallback.GetHashCode() + this.DecoderFallback.GetHashCode();
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
156 // Returns the number of bytes required to encode a range of characters in
157 // a character array.
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
164 [System.Security.SecuritySafeCritical] // auto-generated
165 public override unsafe int GetByteCount(char[] chars, int index, int count)
167 // Validate input parameters
169 throw new ArgumentNullException("chars",
170 Environment.GetResourceString("ArgumentNull_Array"));
172 if (index < 0 || count < 0)
173 throw new ArgumentOutOfRangeException((index<0 ? "index" : "count"),
174 Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
176 if (chars.Length - index < count)
177 throw new ArgumentOutOfRangeException("chars",
178 Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
179 Contract.EndContractBlock();
181 // If no input, return 0, avoid fixed empty array problem
182 if (chars.Length == 0)
185 // Just call the pointer version
186 fixed (char* pChars = chars)
187 return GetByteCount(pChars + index, count, null);
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
195 [System.Security.SecuritySafeCritical] // auto-generated
196 [System.Runtime.InteropServices.ComVisible(false)]
197 public override unsafe int GetByteCount(String s)
201 throw new ArgumentNullException("s");
202 Contract.EndContractBlock();
204 fixed (char* pChars = s)
205 return GetByteCount(pChars, s.Length, null);
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
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)
217 // Validate Parameters
219 throw new ArgumentNullException("chars",
220 Environment.GetResourceString("ArgumentNull_Array"));
223 throw new ArgumentOutOfRangeException("count",
224 Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
225 Contract.EndContractBlock();
227 // Call it with empty encoder
228 return GetByteCount(chars, count, null);
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
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)
241 if (s == null || bytes == null)
242 throw new ArgumentNullException((s == null ? "s" : "bytes"),
243 Environment.GetResourceString("ArgumentNull_Array"));
245 if (charIndex < 0 || charCount < 0)
246 throw new ArgumentOutOfRangeException((charIndex<0 ? "charIndex" : "charCount"),
247 Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
249 if (s.Length - charIndex < charCount)
250 throw new ArgumentOutOfRangeException("s",
251 Environment.GetResourceString("ArgumentOutOfRange_IndexCount"));
253 if (byteIndex < 0 || byteIndex > bytes.Length)
254 throw new ArgumentOutOfRangeException("byteIndex",
255 Environment.GetResourceString("ArgumentOutOfRange_Index"));
256 Contract.EndContractBlock();
258 int byteCount = bytes.Length - byteIndex;
260 // Fixed doesn't like empty arrays
261 if (bytes.Length == 0)
264 fixed (char* pChars = s)
265 fixed ( byte* pBytes = bytes)
266 return GetBytes(pChars + charIndex, charCount,
267 pBytes + byteIndex, byteCount, null);
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.
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
284 [System.Security.SecuritySafeCritical] // auto-generated
285 public override unsafe int GetBytes(char[] chars, int charIndex, int charCount,
286 byte[] bytes, int byteIndex)
288 // Validate parameters
289 if (chars == null || bytes == null)
290 throw new ArgumentNullException((chars == null ? "chars" : "bytes"),
291 Environment.GetResourceString("ArgumentNull_Array"));
293 if (charIndex < 0 || charCount < 0)
294 throw new ArgumentOutOfRangeException((charIndex<0 ? "charIndex" : "charCount"),
295 Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
297 if (chars.Length - charIndex < charCount)
298 throw new ArgumentOutOfRangeException("chars",
299 Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
301 if (byteIndex < 0 || byteIndex > bytes.Length)
302 throw new ArgumentOutOfRangeException("byteIndex",
303 Environment.GetResourceString("ArgumentOutOfRange_Index"));
304 Contract.EndContractBlock();
306 // If nothing to encode return 0, avoid fixed problem
307 if (chars.Length == 0)
310 // Just call pointer version
311 int byteCount = bytes.Length - byteIndex;
313 // Fixed doesn't like empty arrays
314 if (bytes.Length == 0)
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);
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
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)
333 // Validate Parameters
334 if (bytes == null || chars == null)
335 throw new ArgumentNullException(bytes == null ? "bytes" : "chars",
336 Environment.GetResourceString("ArgumentNull_Array"));
338 if (charCount < 0 || byteCount < 0)
339 throw new ArgumentOutOfRangeException((charCount<0 ? "charCount" : "byteCount"),
340 Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
341 Contract.EndContractBlock();
343 return GetBytes(chars, charCount, bytes, byteCount, null);
346 // Returns the number of characters produced by decoding a range of bytes
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
354 [System.Security.SecuritySafeCritical] // auto-generated
355 public override unsafe int GetCharCount(byte[] bytes, int index, int count)
357 // Validate Parameters
359 throw new ArgumentNullException("bytes",
360 Environment.GetResourceString("ArgumentNull_Array"));
362 if (index < 0 || count < 0)
363 throw new ArgumentOutOfRangeException((index<0 ? "index" : "count"),
364 Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
366 if (bytes.Length - index < count)
367 throw new ArgumentOutOfRangeException("bytes",
368 Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
369 Contract.EndContractBlock();
371 // If no input just return 0, fixed doesn't like 0 length arrays.
372 if (bytes.Length == 0)
375 // Just call pointer version
376 fixed (byte* pBytes = bytes)
377 return GetCharCount(pBytes + index, count, null);
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
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)
389 // Validate Parameters
391 throw new ArgumentNullException("bytes",
392 Environment.GetResourceString("ArgumentNull_Array"));
395 throw new ArgumentOutOfRangeException("count",
396 Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
397 Contract.EndContractBlock();
399 return GetCharCount(bytes, count, null);
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
407 [System.Security.SecuritySafeCritical] // auto-generated
408 public override unsafe int GetChars(byte[] bytes, int byteIndex, int byteCount,
409 char[] chars, int charIndex)
411 // Validate Parameters
412 if (bytes == null || chars == null)
413 throw new ArgumentNullException(bytes == null ? "bytes" : "chars",
414 Environment.GetResourceString("ArgumentNull_Array"));
416 if (byteIndex < 0 || byteCount < 0)
417 throw new ArgumentOutOfRangeException((byteIndex<0 ? "byteIndex" : "byteCount"),
418 Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
420 if ( bytes.Length - byteIndex < byteCount)
421 throw new ArgumentOutOfRangeException("bytes",
422 Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
424 if (charIndex < 0 || charIndex > chars.Length)
425 throw new ArgumentOutOfRangeException("charIndex",
426 Environment.GetResourceString("ArgumentOutOfRange_Index"));
427 Contract.EndContractBlock();
429 // If no input, return 0 & avoid fixed problem
430 if (bytes.Length == 0)
433 // Just call pointer version
434 int charCount = chars.Length - charIndex;
436 // Fixed doesn't like empty arrays
437 if (chars.Length == 0)
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);
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
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)
456 // Validate Parameters
457 if (bytes == null || chars == null)
458 throw new ArgumentNullException(bytes == null ? "bytes" : "chars",
459 Environment.GetResourceString("ArgumentNull_Array"));
461 if (charCount < 0 || byteCount < 0)
462 throw new ArgumentOutOfRangeException((charCount<0 ? "charCount" : "byteCount"),
463 Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
464 Contract.EndContractBlock();
466 return GetChars(bytes, byteCount, chars, charCount, null);
469 // Returns a string containing the decoded representation of a range of
470 // bytes in a byte array.
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
477 [System.Security.SecuritySafeCritical] // auto-generated
478 [System.Runtime.InteropServices.ComVisible(false)]
479 public override unsafe String GetString(byte[] bytes, int index, int count)
481 // Validate Parameters
483 throw new ArgumentNullException("bytes",
484 Environment.GetResourceString("ArgumentNull_Array"));
486 if (index < 0 || count < 0)
487 throw new ArgumentOutOfRangeException((index < 0 ? "index" : "count"),
488 Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
490 if (bytes.Length - index < count)
491 throw new ArgumentOutOfRangeException("bytes",
492 Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
493 Contract.EndContractBlock();
495 // Avoid problems with empty input buffer
496 if (bytes.Length == 0) return String.Empty;
498 fixed (byte* pBytes = bytes)
499 return String.CreateStringFromEncoding(
500 pBytes + index, count, this);
504 // End of standard methods copied from EncodingNLS.cs
507 [System.Security.SecurityCritical] // auto-generated
508 internal override unsafe int GetByteCount(char* chars, int count, EncoderNLS baseEncoder)
510 Contract.Assert(chars!=null, "[UTF7Encoding.GetByteCount]chars!=null");
511 Contract.Assert(count >=0, "[UTF7Encoding.GetByteCount]count >=0");
513 // Just call GetBytes with bytes == null
514 return GetBytes(chars, count, null, 0, baseEncoder);
517 [System.Security.SecurityCritical] // auto-generated
518 internal override unsafe int GetBytes(char* chars, int charCount,
519 byte* bytes, int byteCount, EncoderNLS baseEncoder)
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");
526 UTF7Encoding.Encoder encoder = (UTF7Encoding.Encoder)baseEncoder;
528 // Default bits & count
532 // prepare our helpers
533 Encoding.EncodingByteBuffer buffer = new Encoding.EncodingByteBuffer(
534 this, encoder, bytes, byteCount, chars, charCount);
539 bitCount = encoder.bitCount;
541 // May have had too many left over
542 while (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);
551 while (buffer.MoreData)
553 char currentChar = buffer.GetNextChar();
555 if (currentChar < 0x80 && directEncode[currentChar])
561 // Try to add the next byte
562 if (!buffer.AddByte(base64Bytes[bits << 6 - bitCount & 0x3F]))
563 break; // Stop here, didn't throw
568 // Need to get emit '-' and our char, 2 bytes total
569 if (!buffer.AddByte((byte)'-'))
570 break; // Stop here, didn't throw
575 // Need to emit our char
576 if (!buffer.AddByte((byte)currentChar))
577 break; // Stop here, didn't throw
579 else if (bitCount < 0 && currentChar == '+')
581 if (!buffer.AddByte((byte)'+', (byte)'-'))
582 break; // Stop here, didn't throw
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
593 // We're now in bit mode, but haven't stored data yet
598 bits = bits << 16 | currentChar;
601 while (bitCount >= 6)
604 if (!buffer.AddByte(base64Bytes[(bits >> bitCount) & 0x3F]))
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
614 break; // Didn't have room to encode enough bits
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))
622 // Do we have bits we have to stick in?
625 if (buffer.AddByte(base64Bytes[(bits << (6 - bitCount)) & 0x3F]))
627 // Emitted spare bits, 0 bits left
632 // If converting and failed bitCount above, then we'll fail this too
633 if (buffer.AddByte((byte)'-'))
635 // turned off bit mode';
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();
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)
649 // We already cleared bits & bitcount for mustflush case
651 encoder.bitCount = bitCount;
652 encoder.m_charsUsed = buffer.CharsUsed;
658 [System.Security.SecurityCritical] // auto-generated
659 internal override unsafe int GetCharCount(byte* bytes, int count, DecoderNLS baseDecoder)
661 Contract.Assert(count >=0, "[UTF7Encoding.GetCharCount]count >=0");
662 Contract.Assert(bytes!=null, "[UTF7Encoding.GetCharCount]bytes!=null");
664 // Just call GetChars with null char* to do counting
665 return GetChars(bytes, count, null, 0, baseDecoder);
668 [System.Security.SecurityCritical] // auto-generated
669 internal override unsafe int GetChars(byte* bytes, int byteCount,
670 char* chars, int charCount, DecoderNLS baseDecoder)
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");
676 // Might use a decoder
677 UTF7Encoding.Decoder decoder = (UTF7Encoding.Decoder) baseDecoder;
679 // Get our output buffer info.
680 Encoding.EncodingCharBuffer buffer = new Encoding.EncodingCharBuffer(
681 this, decoder, chars, charCount, bytes, byteCount);
686 bool firstByte = false;
690 bitCount = decoder.bitCount;
691 firstByte = decoder.firstByte;
693 Contract.Assert(firstByte == false || decoder.bitCount <= 0,
694 "[UTF7Encoding.GetChars]If remembered bits, then first byte flag shouldn't be set");
697 // We may have had bits in the decoder that we couldn't output last time, so do so now
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
704 // Used this one, clean up extra bits
708 // Loop through the input
709 while (buffer.MoreData)
711 byte currentByte = buffer.GetNextByte();
717 // Modified base 64 encoding.
720 if (currentByte < 0x80 && ((v = base64Values[currentByte]) >=0))
723 bits = (bits << 6) | ((byte)v);
727 c = (bits >> (bitCount - 16)) & 0xFFFF;
730 // If not enough bits just continue
735 // If it wasn't a base 64 byte, everything's going to turn off base 64 mode
738 if (currentByte != '-')
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
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
749 // Chars won't be updated unless this works, try to fallback
750 if (!buffer.Fallback(currentByte))
751 break; // Stop here, didn't throw
753 // Used that byte, we're done with it
758 // The encoding for '+' is "+-".
760 if (firstByte) c = '+';
761 // We just turn it off if not emitting a +, so we're done.
765 // End of modified base 64 encoding block.
768 else if (currentByte == '+')
771 // Found the start of a modified base 64 encoding block or a plus sign.
780 if (currentByte >= 0x80)
783 if (!buffer.Fallback(currentByte))
784 break; // Stop here, didn't throw
790 // Use the normal character
797 if (!buffer.AddChar((char)c))
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)
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
806 break; // didn't throw, stop
811 // Stick stuff in the decoder if we can (chars == null if counting, so don't store decoder)
812 if (chars != null && decoder != null)
814 // MustFlush? (Could've been cleared by ThrowCharsOverflow if Convert & didn't reach end of buffer)
815 if (decoder.MustFlush)
817 // RFC doesn't specify what would happen if we have non-0 leftover bits, we just drop them
819 decoder.bitCount = -1;
820 decoder.firstByte = false;
825 decoder.bitCount = bitCount;
826 decoder.firstByte = firstByte;
828 decoder.m_bytesUsed = buffer.BytesUsed;
830 // else ignore any hanging bits.
837 public override System.Text.Decoder GetDecoder()
839 return new UTF7Encoding.Decoder(this);
843 public override System.Text.Encoder GetEncoder()
845 return new UTF7Encoding.Encoder(this);
849 public override int GetMaxByteCount(int charCount)
852 throw new ArgumentOutOfRangeException("charCount",
853 Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
854 Contract.EndContractBlock();
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.
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.
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;
874 // check for overflow
875 if (byteCount > 0x7fffffff)
876 throw new ArgumentOutOfRangeException("charCount", Environment.GetResourceString("ArgumentOutOfRange_GetByteCountOverflow"));
878 return (int)byteCount;
882 public override int GetMaxCharCount(int byteCount)
885 throw new ArgumentOutOfRangeException("byteCount",
886 Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
887 Contract.EndContractBlock();
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;
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
902 /*private*/ internal int bits;
903 /*private*/ internal int bitCount;
904 /*private*/ internal bool firstByte;
906 public Decoder(UTF7Encoding encoding) : base (encoding)
911 // Constructor called by serialization, have to handle deserializing from Everett
912 internal Decoder(SerializationInfo info, StreamingContext context)
915 if (info==null) throw new ArgumentNullException("info");
916 Contract.EndContractBlock();
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));
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)
931 if (info==null) throw new ArgumentNullException("info");
932 Contract.EndContractBlock();
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);
942 public override void Reset()
946 this.firstByte = false;
947 if (m_fallbackBuffer != null)
948 m_fallbackBuffer.Reset();
951 // Anything left in our encoder?
952 internal override bool HasState
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);
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
968 /*private*/ internal int bits;
969 /*private*/ internal int bitCount;
971 public Encoder(UTF7Encoding encoding) : base(encoding)
976 // Constructor called by serialization, have to handle deserializing from Everett
977 internal Encoder(SerializationInfo info, StreamingContext context)
980 if (info==null) throw new ArgumentNullException("info");
981 Contract.EndContractBlock();
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));
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)
995 if (info==null) throw new ArgumentNullException("info");
996 Contract.EndContractBlock();
999 info.AddValue("encoding", this.m_encoding);
1000 info.AddValue("bits", this.bits);
1001 info.AddValue("bitCount", this.bitCount);
1005 public override void Reset()
1009 if (m_fallbackBuffer != null)
1010 m_fallbackBuffer.Reset();
1013 // Anything left in our encoder?
1014 internal override bool HasState
1018 return (this.bits != 0 || this.bitCount != -1);
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.
1026 internal sealed class DecoderUTF7Fallback : DecoderFallback
1028 // Construction. Default replacement fallback uses no best fit and ? replacement string
1029 public DecoderUTF7Fallback()
1033 public override DecoderFallbackBuffer CreateFallbackBuffer()
1035 return new DecoderUTF7FallbackBuffer(this);
1038 // Maximum number of characters that this instance of this fallback could return
1039 public override int MaxCharCount
1043 // returns 1 char per bad byte
1048 public override bool Equals(Object value)
1050 DecoderUTF7Fallback that = value as DecoderUTF7Fallback;
1058 public override int GetHashCode()
1064 internal sealed class DecoderUTF7FallbackBuffer : DecoderFallbackBuffer
1066 // Store our default string
1067 char cFallback = (char)0;
1072 public DecoderUTF7FallbackBuffer(DecoderUTF7Fallback fallback)
1077 public override bool Fallback(byte[] bytesUnknown, int index)
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");
1083 // Go ahead and get our fallback
1084 cFallback = (char)bytesUnknown[0];
1086 // Any of the fallback characters can be handled except for 0
1097 public override char GetNextChar()
1102 // Note: this means that 0 in UTF7 stream will never be emitted.
1106 public override bool MovePrevious()
1113 // return true if we were allowed to do this
1114 return (iCount >= 0 && iCount <= iSize);
1117 // Return # of chars left in this fallback
1118 public override int Remaining
1122 return (iCount > 0) ? iCount : 0;
1127 [System.Security.SecuritySafeCritical] // overrides public transparent member
1128 public override unsafe void Reset()
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*
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)
1144 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidCharSequenceNoIndex"));
1147 // Can't fallback a byte 0, so return for that case, 1 otherwise.
1148 return bytes[0] == 0 ? 0 : 1;