The Labs \ Source Viewer \ SSCLI \ System.Text \ UnicodeEncoding

  1. // ==++==
  2. //
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. //
  14. // ==--==
  15. //
  16. // Don't override IsAlwaysNormalized because it is just a Unicode Transformation and could be confused.
  17. //
  18. namespace System.Text
  19. {
  20.     using System;
  21.     using System.Globalization;
  22.     using System.Runtime.Serialization;
  23.     using System.Security.Permissions;
  24.    
  25.    
  26.     [Serializable()]
  27.     [System.Runtime.InteropServices.ComVisible(true)]
  28.     public class UnicodeEncoding : Encoding
  29.     {
  30.         [OptionalField(VersionAdded = 2)]
  31.         internal bool isThrowException = false;
  32.        
  33.         internal bool bigEndian = false;
  34.         internal bool byteOrderMark = true;
  35.        
  36.         // Unicode version 2.0 character size in bytes
  37.         // Why's this _)(*@&#)(*&@#$ thing public !!!!!
  38.        
  39.         public const int CharSize = 2;
  40.        
  41.        
  42.         public UnicodeEncoding() : this(false, true)
  43.         {
  44.         }
  45.        
  46.        
  47.         public UnicodeEncoding(bool bigEndian, bool byteOrderMark) : this(bigEndian, byteOrderMark, false)
  48.         {
  49.         }
  50.        
  51.        
  52.         //Set the data item.
  53.         public UnicodeEncoding(bool bigEndian, bool byteOrderMark, bool throwOnInvalidBytes) : base(bigEndian ? 1201 : 1200)
  54.         {
  55.             this.isThrowException = throwOnInvalidBytes;
  56.             this.bigEndian = bigEndian;
  57.             this.byteOrderMark = byteOrderMark;
  58.            
  59.             if (this.isThrowException)
  60.                 SetDefaultFallbacks();
  61.         }
  62.        
  63.         #region Serialization
  64.         [OnDeserializing()]
  65.         private void OnDeserializing(StreamingContext ctx)
  66.         {
  67.             isThrowException = false;
  68.         }
  69.         #endregion Serialization
  70.        
  71.         internal override void SetDefaultFallbacks()
  72.         {
  73.             // For UTF-X encodings, we use a replacement fallback with an empty string
  74.             if (this.isThrowException) {
  75.                 this.encoderFallback = EncoderFallback.ExceptionFallback;
  76.                 this.decoderFallback = DecoderFallback.ExceptionFallback;
  77.             }
  78.             else {
  79.                 this.encoderFallback = new EncoderReplacementFallback(String.Empty);
  80.                 this.decoderFallback = new DecoderReplacementFallback(String.Empty);
  81.             }
  82.         }
  83.        
  84.         //
  85.        
  86.         //
  87.        
  88.         unsafe public override int GetByteCount(char[] chars, int index, int count)
  89.         {
  90.             // Validate input parameters
  91.             if (chars == null)
  92.                 throw new ArgumentNullException("chars", Environment.GetResourceString("ArgumentNull_Array"));
  93.            
  94.             if (index < 0 || count < 0)
  95.                 throw new ArgumentOutOfRangeException((index < 0 ? "index" : "count"), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
  96.            
  97.             if (chars.Length - index < count)
  98.                 throw new ArgumentOutOfRangeException("chars", Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
  99.            
  100.             // If no input, return 0, avoid fixed empty array problem
  101.             if (chars.Length == 0)
  102.                 return 0;
  103.            
  104.             // Just call the pointer version
  105.             fixed (char* pChars = chars)
  106.                 return GetByteCount(pChars + index, count, null);
  107.         }
  108.        
  109.         // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
  110.         // So if you fix this, fix the others. Currently those include:
  111.         // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
  112.         // parent method is safe
  113.        
  114.         unsafe public override int GetByteCount(string s)
  115.         {
  116.             // Validate input
  117.             if (s == null)
  118.                 throw new ArgumentNullException("s");
  119.            
  120.             fixed (char* pChars = s)
  121.                 return GetByteCount(pChars, s.Length, null);
  122.         }
  123.        
  124.         // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
  125.         // So if you fix this, fix the others. Currently those include:
  126.         // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
  127.        
  128.         [CLSCompliant(false)]
  129.         [System.Runtime.InteropServices.ComVisible(false)]
  130.         unsafe public override int GetByteCount(char* chars, int count)
  131.         {
  132.             // Validate Parameters
  133.             if (chars == null)
  134.                 throw new ArgumentNullException("chars", Environment.GetResourceString("ArgumentNull_Array"));
  135.            
  136.             if (count < 0)
  137.                 throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
  138.            
  139.             // Call it with empty encoder
  140.             return GetByteCount(chars, count, null);
  141.         }
  142.        
  143.         // Parent method is safe.
  144.         // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
  145.         // So if you fix this, fix the others. Currently those include:
  146.         // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
  147.        
  148.         unsafe public override int GetBytes(string s, int charIndex, int charCount, byte[] bytes, int byteIndex)
  149.         {
  150.             if (s == null || bytes == null)
  151.                 throw new ArgumentNullException((s == null ? "s" : "bytes"), Environment.GetResourceString("ArgumentNull_Array"));
  152.            
  153.             if (charIndex < 0 || charCount < 0)
  154.                 throw new ArgumentOutOfRangeException((charIndex < 0 ? "charIndex" : "charCount"), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
  155.            
  156.             if (s.Length - charIndex < charCount)
  157.                 throw new ArgumentOutOfRangeException("s", Environment.GetResourceString("ArgumentOutOfRange_IndexCount"));
  158.            
  159.             if (byteIndex < 0 || byteIndex > bytes.Length)
  160.                 throw new ArgumentOutOfRangeException("byteIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
  161.            
  162.             int byteCount = bytes.Length - byteIndex;
  163.            
  164.             // Fixed doesn't like 0 length arrays.
  165.             if (bytes.Length == 0)
  166.                 bytes = new byte[1];
  167.            
  168.             fixed (char* pChars = s)
  169.                 fixed (byte* pBytes = bytes)
  170.                     return GetBytes(pChars + charIndex, charCount, pBytes + byteIndex, byteCount, null);
  171.         }
  172.        
  173.         // Encodes a range of characters in a character array into a range of bytes
  174.         // in a byte array. An exception occurs if the byte array is not large
  175.         // enough to hold the complete encoding of the characters. The
  176.         // GetByteCount method can be used to determine the exact number of
  177.         // bytes that will be produced for a given range of characters.
  178.         // Alternatively, the GetMaxByteCount method can be used to
  179.         // determine the maximum number of bytes that will be produced for a given
  180.         // number of characters, regardless of the actual character values.
  181.         //
  182.         // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
  183.         // So if you fix this, fix the others. Currently those include:
  184.         // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
  185.         // parent method is safe
  186.        
  187.         unsafe public override int GetBytes(char[] chars, int charIndex, int charCount, byte[] bytes, int byteIndex)
  188.         {
  189.             // Validate parameters
  190.             if (chars == null || bytes == null)
  191.                 throw new ArgumentNullException((chars == null ? "chars" : "bytes"), Environment.GetResourceString("ArgumentNull_Array"));
  192.            
  193.             if (charIndex < 0 || charCount < 0)
  194.                 throw new ArgumentOutOfRangeException((charIndex < 0 ? "charIndex" : "charCount"), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
  195.            
  196.             if (chars.Length - charIndex < charCount)
  197.                 throw new ArgumentOutOfRangeException("chars", Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
  198.            
  199.             if (byteIndex < 0 || byteIndex > bytes.Length)
  200.                 throw new ArgumentOutOfRangeException("byteIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
  201.            
  202.             // If nothing to encode return 0, avoid fixed problem
  203.             if (chars.Length == 0)
  204.                 return 0;
  205.            
  206.             // Just call pointer version
  207.             int byteCount = bytes.Length - byteIndex;
  208.            
  209.             // Fixed doesn't like 0 length arrays.
  210.             if (bytes.Length == 0)
  211.                 bytes = new byte[1];
  212.            
  213.             fixed (char* pChars = chars)
  214.                 fixed (byte* pBytes = bytes)
  215.                 // Remember that byteCount is # to decode, not size of array.
  216.                     return GetBytes(pChars + charIndex, charCount, pBytes + byteIndex, byteCount, null);
  217.         }
  218.        
  219.         // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
  220.         // So if you fix this, fix the others. Currently those include:
  221.         // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
  222.        
  223.         [CLSCompliant(false)]
  224.         [System.Runtime.InteropServices.ComVisible(false)]
  225.         unsafe public override int GetBytes(char* chars, int charCount, byte* bytes, int byteCount)
  226.         {
  227.             // Validate Parameters
  228.             if (bytes == null || chars == null)
  229.                 throw new ArgumentNullException(bytes == null ? "bytes" : "chars", Environment.GetResourceString("ArgumentNull_Array"));
  230.            
  231.             if (charCount < 0 || byteCount < 0)
  232.                 throw new ArgumentOutOfRangeException((charCount < 0 ? "charCount" : "byteCount"), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
  233.            
  234.             return GetBytes(chars, charCount, bytes, byteCount, null);
  235.         }
  236.        
  237.         // Returns the number of characters produced by decoding a range of bytes
  238.         // in a byte array.
  239.         //
  240.         // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
  241.         // So if you fix this, fix the others. Currently those include:
  242.         // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
  243.         // parent method is safe
  244.        
  245.         unsafe public override int GetCharCount(byte[] bytes, int index, int count)
  246.         {
  247.             // Validate Parameters
  248.             if (bytes == null)
  249.                 throw new ArgumentNullException("bytes", Environment.GetResourceString("ArgumentNull_Array"));
  250.            
  251.             if (index < 0 || count < 0)
  252.                 throw new ArgumentOutOfRangeException((index < 0 ? "index" : "count"), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
  253.            
  254.             if (bytes.Length - index < count)
  255.                 throw new ArgumentOutOfRangeException("bytes", Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
  256.            
  257.             // If no input just return 0, fixed doesn't like 0 length arrays
  258.             if (bytes.Length == 0)
  259.                 return 0;
  260.            
  261.             // Just call pointer version
  262.             fixed (byte* pBytes = bytes)
  263.                 return GetCharCount(pBytes + index, count, null);
  264.         }
  265.        
  266.         // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
  267.         // So if you fix this, fix the others. Currently those include:
  268.         // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
  269.        
  270.         [CLSCompliant(false)]
  271.         [System.Runtime.InteropServices.ComVisible(false)]
  272.         unsafe public override int GetCharCount(byte* bytes, int count)
  273.         {
  274.             // Validate Parameters
  275.             if (bytes == null)
  276.                 throw new ArgumentNullException("bytes", Environment.GetResourceString("ArgumentNull_Array"));
  277.            
  278.             if (count < 0)
  279.                 throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
  280.            
  281.             return GetCharCount(bytes, count, null);
  282.         }
  283.        
  284.         // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
  285.         // So if you fix this, fix the others. Currently those include:
  286.         // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
  287.         // parent method is safe
  288.        
  289.         unsafe public override int GetChars(byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex)
  290.         {
  291.             // Validate Parameters
  292.             if (bytes == null || chars == null)
  293.                 throw new ArgumentNullException(bytes == null ? "bytes" : "chars", Environment.GetResourceString("ArgumentNull_Array"));
  294.            
  295.             if (byteIndex < 0 || byteCount < 0)
  296.                 throw new ArgumentOutOfRangeException((byteIndex < 0 ? "byteIndex" : "byteCount"), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
  297.            
  298.             if (bytes.Length - byteIndex < byteCount)
  299.                 throw new ArgumentOutOfRangeException("bytes", Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
  300.            
  301.             if (charIndex < 0 || charIndex > chars.Length)
  302.                 throw new ArgumentOutOfRangeException("charIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
  303.            
  304.             // If no input, return 0 & avoid fixed problem
  305.             if (bytes.Length == 0)
  306.                 return 0;
  307.            
  308.             // Just call pointer version
  309.             int charCount = chars.Length - charIndex;
  310.            
  311.             // Fixed doesn't like 0 length arrays.
  312.             if (chars.Length == 0)
  313.                 chars = new char[1];
  314.            
  315.             fixed (byte* pBytes = bytes)
  316.                 fixed (char* pChars = chars)
  317.                 // Remember that charCount is # to decode, not size of array
  318.                     return GetChars(pBytes + byteIndex, byteCount, pChars + charIndex, charCount, null);
  319.         }
  320.        
  321.         // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
  322.         // So if you fix this, fix the others. Currently those include:
  323.         // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
  324.        
  325.         [CLSCompliant(false)]
  326.         [System.Runtime.InteropServices.ComVisible(false)]
  327.         unsafe public override int GetChars(byte* bytes, int byteCount, char* chars, int charCount)
  328.         {
  329.             // Validate Parameters
  330.             if (bytes == null || chars == null)
  331.                 throw new ArgumentNullException(bytes == null ? "bytes" : "chars", Environment.GetResourceString("ArgumentNull_Array"));
  332.            
  333.             if (charCount < 0 || byteCount < 0)
  334.                 throw new ArgumentOutOfRangeException((charCount < 0 ? "charCount" : "byteCount"), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
  335.            
  336.             return GetChars(bytes, byteCount, chars, charCount, null);
  337.         }
  338.        
  339.         // Returns a string containing the decoded representation of a range of
  340.         // bytes in a byte array.
  341.         //
  342.         // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
  343.         // So if you fix this, fix the others. Currently those include:
  344.         // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
  345.         // parent method is safe
  346.        
  347.         [System.Runtime.InteropServices.ComVisible(false)]
  348.         unsafe public override string GetString(byte[] bytes, int index, int count)
  349.         {
  350.             // Validate Parameters
  351.             if (bytes == null)
  352.                 throw new ArgumentNullException("bytes", Environment.GetResourceString("ArgumentNull_Array"));
  353.            
  354.             if (index < 0 || count < 0)
  355.                 throw new ArgumentOutOfRangeException((index < 0 ? "index" : "count"), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
  356.            
  357.             if (bytes.Length - index < count)
  358.                 throw new ArgumentOutOfRangeException("bytes", Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
  359.            
  360.             // Avoid problems with empty input buffer
  361.             if (bytes.Length == 0)
  362.                 return String.Empty;
  363.            
  364.             fixed (byte* pBytes = bytes)
  365.                 return String.CreateStringFromEncoding(pBytes + index, count, this);
  366.         }
  367.        
  368.         //
  369.         // End of standard methods copied from EncodingNLS.cs
  370.         //
  371.        
  372.         unsafe internal override int GetByteCount(char* chars, int count, EncoderNLS encoder)
  373.         {
  374.             BCLDebug.Assert(chars != null, "[UnicodeEncoding.GetByteCount]chars!=null");
  375.             BCLDebug.Assert(count >= 0, "[UnicodeEncoding.GetByteCount]count >=0");
  376.            
  377.             // Start by assuming each char gets 2 bytes
  378.             int byteCount = count << 1;
  379.            
  380.             if (byteCount < 0)
  381.                 throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_GetByteCountOverflow"));
  382.            
  383.             char* charStart = chars;
  384.             char* charEnd = chars + count;
  385.             char charLeftOver = (char)0;
  386.            
  387.             bool wasHereBefore = false;
  388.            
  389.             // Need -1 to check 2 at a time. If we have an even #, longChars will go
  390.             // from longEnd - 1/2 long to longEnd + 1/2 long. If we're odd, longChars
  391.             // will go from longEnd - 1 long to longEnd. (Might not get to use this)
  392.             ulong* longEnd = (ulong*)(charEnd - 3);
  393.            
  394.             // For fallback we may need a fallback buffer
  395.             EncoderFallbackBuffer fallbackBuffer = null;
  396.            
  397.             if (encoder != null) {
  398.                 charLeftOver = encoder.charLeftOver;
  399.                
  400.                 // Assume extra bytes to encode charLeftOver if it existed
  401.                 if (charLeftOver > 0)
  402.                     byteCount += 2;
  403.                
  404.                 // We mustn't have left over fallback data when counting
  405.                 if (encoder.InternalHasFallbackBuffer) {
  406.                     if ((fallbackBuffer = encoder.FallbackBuffer).Remaining > 0)
  407.                         throw new ArgumentException(Environment.GetResourceString("Argument_EncoderFallbackNotEmpty", this.EncodingName, encoder.Fallback.GetType()));
  408.                    
  409.                     // Set our internal fallback interesting things.
  410.                     fallbackBuffer.InternalInitialize(charStart, charEnd, encoder, false);
  411.                 }
  412.             }
  413.            
  414.             char ch;
  415.             TryAgain:
  416.            
  417.             while (((ch = (fallbackBuffer == null) ? (char)0 : fallbackBuffer.InternalGetNextChar()) != 0) || chars < charEnd) {
  418.                 // First unwind any fallback
  419.                 if (ch == 0) {
  420.                     // No fallback, maybe we can do it fast
  421.                     #if BIGENDIAN // If endianess is backwards then each pair of bytes would be backwards.
  422.                     if (bigEndian && )
  423.                         #else
  424.                         #endif // BIGENDIAN
  425.                        
  426.                         if (!bigEndian && charLeftOver == 0 && (unchecked((int)chars) & 3) == 0) {
  427.                             // Need new char* so we can check 4 at a time
  428.                             ulong* longChars = (ulong*)chars;
  429.                            
  430.                             while (longChars < longEnd) {
  431.                                 if (((ulong)(9223512776490647552ul) & *longChars) != 0) {
  432.                                     // See if all 4 of those are bad...
  433.                                     // Surrogate pairs are "backwards" for little endian machines read in as one
  434.                                     // Mask off surrogate bits
  435.                                     ulong uTemp = (15564677810327967744ul & *longChars) ^ 15564677810327967744ul;
  436.                                    
  437.                                     // Check each of the 4 chars. 0 for those 16 bits means it was a surrogate
  438.                                     if ((uTemp & 18446462598732840960ul) == 0 || (uTemp & 281470681743360l) == 0 || (uTemp & 4294901760u) == 0 || (uTemp & 65535) == 0) {
  439.                                         // Does it happen to have 4 good surrogates?
  440.                                         #if BIGENDIAN
  441.                                         if (((15852912584593300480ul & *longChars) ^ 15564682208374479872ul) != 0)
  442.                                             #else
  443.                                             #endif
  444.                                             if (((15852912584593300480ul & *longChars) ^ 15852908186546788352ul) != 0) {
  445.                                                 // If it wasn't 4 good surrogates then fall through to slow loop
  446.                                                 break;
  447.                                             }
  448.                                     }
  449.                                    
  450.                                     // It was a good value, we'll use these 4 characters
  451.                                 }
  452.                                
  453.                                 // We already counted these four chars, go to next long.
  454.                                 longChars++;
  455.                             }
  456.                            
  457.                             chars = (char*)longChars;
  458.                            
  459.                             if (chars >= charEnd)
  460.                                 break;
  461.                         }
  462.                    
  463.                     // No fallback, just get next char
  464.                     ch = *chars;
  465.                     chars++;
  466.                 }
  467.                 else {
  468.                     // We weren't preallocating fallback space.
  469.                     byteCount += 2;
  470.                 }
  471.                
  472.                 // Check for high or low surrogates
  473.                 if (ch >= 55296 && ch <= 57343) {
  474.                     // Was it a high surrogate?
  475.                     if (ch <= 56319) {
  476.                         // Its a high surrogate, if we already had a high surrogate do its fallback
  477.                         if (charLeftOver > 0) {
  478.                             // Unwind the current character, this should be safe because we
  479.                             // don't have leftover data in the fallback, so chars must have
  480.                             // advanced already.
  481.                             BCLDebug.Assert(chars > charStart, "[UnicodeEncoding.GetByteCount]Expected chars to have advanced in unexpected high surrogate");
  482.                             chars--;
  483.                            
  484.                             // If previous high surrogate deallocate 2 bytes
  485.                             byteCount -= 2;
  486.                            
  487.                             // Fallback the previous surrogate
  488.                             // Need to initialize fallback buffer?
  489.                             if (fallbackBuffer == null) {
  490.                                 if (encoder == null)
  491.                                     fallbackBuffer = this.encoderFallback.CreateFallbackBuffer();
  492.                                 else
  493.                                     fallbackBuffer = encoder.FallbackBuffer;
  494.                                
  495.                                 // Set our internal fallback interesting things.
  496.                                 fallbackBuffer.InternalInitialize(charStart, charEnd, encoder, false);
  497.                             }
  498.                            
  499.                             fallbackBuffer.InternalFallback(charLeftOver, ref chars);
  500.                            
  501.                             // Now no high surrogate left over
  502.                             charLeftOver = (char)0;
  503.                             continue;
  504.                         }
  505.                        
  506.                         // Remember this high surrogate
  507.                         charLeftOver = ch;
  508.                         continue;
  509.                     }
  510.                    
  511.                    
  512.                     // Its a low surrogate
  513.                     if (charLeftOver == 0) {
  514.                         // Expected a previous high surrogate.
  515.                         // Don't count this one (we'll count its fallback if necessary)
  516.                         byteCount -= 2;
  517.                        
  518.                         // fallback this one
  519.                         // Need to initialize fallback buffer?
  520.                         if (fallbackBuffer == null) {
  521.                             if (encoder == null)
  522.                                 fallbackBuffer = this.encoderFallback.CreateFallbackBuffer();
  523.                             else
  524.                                 fallbackBuffer = encoder.FallbackBuffer;
  525.                            
  526.                             // Set our internal fallback interesting things.
  527.                             fallbackBuffer.InternalInitialize(charStart, charEnd, encoder, false);
  528.                         }
  529.                         fallbackBuffer.InternalFallback(ch, ref chars);
  530.                         continue;
  531.                     }
  532.                    
  533.                     // Valid surrogate pair, add our charLeftOver
  534.                     charLeftOver = (char)0;
  535.                     continue;
  536.                 }
  537.                 else if (charLeftOver > 0) {
  538.                     // Expected a low surrogate, but this char is normal
  539.                    
  540.                     // Rewind the current character, fallback previous character.
  541.                     // this should be safe because we don't have leftover data in the
  542.                     // fallback, so chars must have advanced already.
  543.                     BCLDebug.Assert(chars > charStart, "[UnicodeEncoding.GetByteCount]Expected chars to have advanced when expected low surrogate");
  544.                     chars--;
  545.                    
  546.                     // fallback previous chars
  547.                     // Need to initialize fallback buffer?
  548.                     if (fallbackBuffer == null) {
  549.                         if (encoder == null)
  550.                             fallbackBuffer = this.encoderFallback.CreateFallbackBuffer();
  551.                         else
  552.                             fallbackBuffer = encoder.FallbackBuffer;
  553.                        
  554.                         // Set our internal fallback interesting things.
  555.                         fallbackBuffer.InternalInitialize(charStart, charEnd, encoder, false);
  556.                     }
  557.                     fallbackBuffer.InternalFallback(charLeftOver, ref chars);
  558.                    
  559.                     // Ignore charLeftOver or throw
  560.                     byteCount -= 2;
  561.                     charLeftOver = (char)0;
  562.                    
  563.                     continue;
  564.                 }
  565.                
  566.                 // Ok we had something to add (already counted)
  567.             }
  568.            
  569.             // Don't allocate space for left over char
  570.             if (charLeftOver > 0) {
  571.                 byteCount -= 2;
  572.                
  573.                 // If we have to flush, stick it in fallback and try again
  574.                 if (encoder == null || encoder.MustFlush) {
  575.                     if (wasHereBefore) {
  576.                         // Throw it, using our complete character
  577.                         throw new ArgumentException(Environment.GetResourceString("Argument_RecursiveFallback", charLeftOver), "chars");
  578.                     }
  579.                     else {
  580.                         // Need to initialize fallback buffer?
  581.                         if (fallbackBuffer == null) {
  582.                             if (encoder == null)
  583.                                 fallbackBuffer = this.encoderFallback.CreateFallbackBuffer();
  584.                             else
  585.                                 fallbackBuffer = encoder.FallbackBuffer;
  586.                            
  587.                             // Set our internal fallback interesting things.
  588.                             fallbackBuffer.InternalInitialize(charStart, charEnd, encoder, false);
  589.                         }
  590.                         fallbackBuffer.InternalFallback(charLeftOver, ref chars);
  591.                         charLeftOver = (char)0;
  592.                         wasHereBefore = true;
  593.                         goto TryAgain;
  594.                     }
  595.                 }
  596.             }
  597.            
  598.             // Shouldn't have anything in fallback buffer for GetByteCount
  599.             // (don't have to check m_throwOnOverflow for count)
  600.             BCLDebug.Assert(fallbackBuffer == null || fallbackBuffer.Remaining == 0, "[UnicodeEncoding.GetByteCount]Expected empty fallback buffer at end");
  601.            
  602.             // Don't remember fallbackBuffer.encoder for counting
  603.             return byteCount;
  604.         }
  605.        
  606.         unsafe internal override int GetBytes(char* chars, int charCount, byte* bytes, int byteCount, EncoderNLS encoder)
  607.         {
  608.             BCLDebug.Assert(chars != null, "[UnicodeEncoding.GetBytes]chars!=null");
  609.             BCLDebug.Assert(byteCount >= 0, "[UnicodeEncoding.GetBytes]byteCount >=0");
  610.             BCLDebug.Assert(charCount >= 0, "[UnicodeEncoding.GetBytes]charCount >=0");
  611.             BCLDebug.Assert(bytes != null, "[UnicodeEncoding.GetBytes]bytes!=null");
  612.            
  613.             char charLeftOver = (char)0;
  614.             char ch;
  615.             bool wasHereBefore = false;
  616.            
  617.            
  618.             byte* byteEnd = bytes + byteCount;
  619.             char* charEnd = chars + charCount;
  620.             byte* byteStart = bytes;
  621.             char* charStart = chars;
  622.            
  623.             // For fallback we may need a fallback buffer
  624.             EncoderFallbackBuffer fallbackBuffer = null;
  625.            
  626.             // Get our encoder, but don't clear it yet.
  627.             if (encoder != null) {
  628.                 charLeftOver = encoder.charLeftOver;
  629.                
  630.                 // We mustn't have left over fallback data when counting
  631.                 if (encoder.InternalHasFallbackBuffer) {
  632.                     // We always need the fallback buffer in get bytes so we can flush any remaining ones if necessary
  633.                     fallbackBuffer = encoder.FallbackBuffer;
  634.                     if (fallbackBuffer.Remaining > 0 && encoder.m_throwOnOverflow)
  635.                         throw new ArgumentException(Environment.GetResourceString("Argument_EncoderFallbackNotEmpty", this.EncodingName, encoder.Fallback.GetType()));
  636.                    
  637.                     // Set our internal fallback interesting things.
  638.                     fallbackBuffer.InternalInitialize(charStart, charEnd, encoder, false);
  639.                 }
  640.             }
  641.             TryAgain:
  642.            
  643.             while (((ch = (fallbackBuffer == null) ? (char)0 : fallbackBuffer.InternalGetNextChar()) != 0) || chars < charEnd) {
  644.                 // First unwind any fallback
  645.                 if (ch == 0) {
  646.                     // No fallback, maybe we can do it fast
  647.                     #if BIGENDIAN // If endianess is backwards then each pair of bytes would be backwards.
  648.                     if (bigEndian && )
  649.                         #else
  650.                         #endif // BIGENDIAN
  651.                         if (!bigEndian && (unchecked((int)chars) & 3) == 0 && (unchecked((int)bytes) & 3) == 0 && charLeftOver == 0) {
  652.                             // Need -1 to check 2 at a time. If we have an even #, longChars will go
  653.                             // from longEnd - 1/2 long to longEnd + 1/2 long. If we're odd, longChars
  654.                             // will go from longEnd - 1 long to longEnd. (Might not get to use this)
  655.                             // We can only go iCount units (limited by shorter of char or byte buffers.
  656.                             ulong* longEnd = (ulong*)(chars - 3 + (((byteEnd - bytes) >> 1 < charEnd - chars) ? (byteEnd - bytes) >> 1 : charEnd - chars));
  657.                            
  658.                             // Need new char* so we can check 4 at a time
  659.                             ulong* longChars = (ulong*)chars;
  660.                             ulong* longBytes = (ulong*)bytes;
  661.                            
  662.                             while (longChars < longEnd) {
  663.                                 if (((ulong)(9223512776490647552ul) & *longChars) != 0) {
  664.                                     // See if all 4 of those are bad...
  665.                                     // Surrogate pairs are "backwards" for little endian machines read in as one
  666.                                     // Mask off surrogate bits
  667.                                     ulong uTemp = (15564677810327967744ul & *longChars) ^ 15564677810327967744ul;
  668.                                    
  669.                                     // Check each of the 4 chars. 0 for those 16 bits means it was a surrogate
  670.                                     if ((uTemp & 18446462598732840960ul) == 0 || (uTemp & 281470681743360l) == 0 || (uTemp & 4294901760u) == 0 || (uTemp & 65535) == 0) {
  671.                                         // Does it happen to have 4 good surrogates?
  672.                                         #if BIGENDIAN
  673.                                         if (((15852912584593300480ul & *longChars) ^ 15564682208374479872ul) != 0)
  674.                                             #else
  675.                                             #endif // BIGENDIAN
  676.                                             if (((15852912584593300480ul & *longChars) ^ 15852908186546788352ul) != 0) {
  677.                                                 // If it wasn't 4 good surrogates then fall through to slow loop
  678.                                                 break;
  679.                                             }
  680.                                        
  681.                                         // Use these 4 lucky ordered surrogate pairs.
  682.                                     }
  683.                                    
  684.                                     // Use these 4 high, but not surrogates
  685.                                 }
  686.                                
  687.                                 // We can use these 4 chars.
  688.                                 *longBytes = *longChars;
  689.                                 longChars++;
  690.                                 longBytes++;
  691.                             }
  692.                            
  693.                             chars = (char*)longChars;
  694.                             bytes = (byte*)longBytes;
  695.                            
  696.                             if (chars >= charEnd)
  697.                                 break;
  698.                         }
  699.                         // Not aligned, but maybe we can still be somewhat faster
  700.                         // Also somehow this optimizes the above loop? It seems to cause something above
  701.                         // to get enregistered, but I haven't figured out how to make that happen without this loop.
  702.                         #if BIGENDIAN
  703.                         #else
  704.                         #endif // BIGENDIAN
  705.                        
  706.                         // Only do this if chars & bytes are out of line, otherwise faster loop'll be faster next time
  707.                         else if ((charLeftOver == 0) && bigEndian && !bigEndian && (unchecked((int)chars) & 3) != (unchecked((int)bytes) & 3) && (unchecked((int)(bytes)) & 1) == 0) {
  708.                             // # to use
  709.                             long iCount = ((byteEnd - bytes) >> 1 < charEnd - chars) ? (byteEnd - bytes) >> 1 : charEnd - chars;
  710.                            
  711.                             // Need new char*
  712.                             char* charOut = ((char*)bytes);
  713.                             // a char* for our output
  714.                             char* tempEnd = chars + iCount - 1;
  715.                             // Our end pointer
  716.                             while (chars < tempEnd) {
  717.                                 if (*chars >= (char)55296 && *chars <= (char)57343) {
  718.                                     // break for fallback for low surrogate
  719.                                     if (*chars >= 56320)
  720.                                         break;
  721.                                    
  722.                                     // break if next one's not a low surrogate (will do fallback)
  723.                                     if (*(chars + 1) < 56320 || *(chars + 1) > 57343)
  724.                                         break;
  725.                                    
  726.                                     // They both exist, use them
  727.                                 }
  728.                                 // If 2nd char is surrogate & this one isn't then only add one
  729.                                 else if (*(chars + 1) >= (char)55296 && *(chars + 1) <= 57343) {
  730.                                     *charOut = *chars;
  731.                                     charOut++;
  732.                                     chars++;
  733.                                     continue;
  734.                                 }
  735.                                
  736.                                 *charOut = *chars;
  737.                                 *(charOut + 1) = *(chars + 1);
  738.                                 charOut += 2;
  739.                                 chars += 2;
  740.                                
  741.                             }
  742.                            
  743.                             bytes = (byte*)charOut;
  744.                            
  745.                             if (chars >= charEnd)
  746.                                 break;
  747.                         }
  748.                    
  749.                     // No fallback, just get next char
  750.                     ch = *chars;
  751.                     chars++;
  752.                 }
  753.                
  754.                 // Check for high or low surrogates
  755.                 if (ch >= 55296 && ch <= 57343) {
  756.                     // Was it a high surrogate?
  757.                     if (ch <= 56319) {
  758.                         // Its a high surrogate, see if we already had a high surrogate
  759.                         if (charLeftOver > 0) {
  760.                             // Unwind the current character, this should be safe because we
  761.                             // don't have leftover data in the fallback, so chars must have
  762.                             // advanced already.
  763.                             BCLDebug.Assert(chars > charStart, "[UnicodeEncoding.GetBytes]Expected chars to have advanced in unexpected high surrogate");
  764.                             chars--;
  765.                            
  766.                             // Fallback the previous surrogate
  767.                             // Might need to create our fallback buffer
  768.                             if (fallbackBuffer == null) {
  769.                                 if (encoder == null)
  770.                                     fallbackBuffer = this.encoderFallback.CreateFallbackBuffer();
  771.                                 else
  772.                                     fallbackBuffer = encoder.FallbackBuffer;
  773.                                
  774.                                 // Set our internal fallback interesting things.
  775.                                 fallbackBuffer.InternalInitialize(charStart, charEnd, encoder, true);
  776.                             }
  777.                            
  778.                             fallbackBuffer.InternalFallback(charLeftOver, ref chars);
  779.                            
  780.                             charLeftOver = (char)0;
  781.                             continue;
  782.                         }
  783.                        
  784.                         // Remember this high surrogate
  785.                         charLeftOver = ch;
  786.                         continue;
  787.                     }
  788.                    
  789.                     // Its a low surrogate
  790.                     if (charLeftOver == 0) {
  791.                         // We'll fall back this one
  792.                         // Might need to create our fallback buffer
  793.                         if (fallbackBuffer == null) {
  794.                             if (encoder == null)
  795.                                 fallbackBuffer = this.encoderFallback.CreateFallbackBuffer();
  796.                             else
  797.                                 fallbackBuffer = encoder.FallbackBuffer;
  798.                            
  799.                             // Set our internal fallback interesting things.
  800.                             fallbackBuffer.InternalInitialize(charStart, charEnd, encoder, true);
  801.                         }
  802.                        
  803.                         fallbackBuffer.InternalFallback(ch, ref chars);
  804.                         continue;
  805.                     }
  806.                    
  807.                     // Valid surrogate pair, add our charLeftOver
  808.                     if (bytes + 3 >= byteEnd) {
  809.                         // Not enough room to add this surrogate pair
  810.                         if (fallbackBuffer != null && fallbackBuffer.bFallingBack) {
  811.                             // These must have both been from the fallbacks.
  812.                             // Both of these MUST have been from a fallback because if the 1st wasn't
  813.                             // from a fallback, then a high surrogate followed by an illegal char
  814.                             // would've caused the high surrogate to fall back. If a high surrogate
  815.                             // fell back, then it was consumed and both chars came from the fallback.
  816.                             fallbackBuffer.MovePrevious();
  817.                             // Didn't use either fallback surrogate
  818.                             fallbackBuffer.MovePrevious();
  819.                         }
  820.                         else {
  821.                             // If we don't have enough room, then either we should've advanced a while
  822.                             // or we should have bytes==byteStart and throw below
  823.                             BCLDebug.Assert(chars > charStart + 1 || bytes == byteStart, "[UnicodeEncoding.GetBytes]Expected chars to have when no room to add surrogate pair");
  824.                             chars -= 2;
  825.                             // Didn't use either surrogate
  826.                         }
  827.                         ThrowBytesOverflow(encoder, bytes == byteStart);
  828.                         // Throw maybe (if no bytes written)
  829.                         charLeftOver = (char)0;
  830.                         // we'll retry it later
  831.                         break;
  832.                         // Didn't throw, but stop 'til next time.
  833.                     }
  834.                    
  835.                     if (bigEndian) {
  836.                         *(bytes++) = (byte)(charLeftOver >> 8);
  837.                         *(bytes++) = (byte)charLeftOver;
  838.                     }
  839.                     else {
  840.                         *(bytes++) = (byte)charLeftOver;
  841.                         *(bytes++) = (byte)(charLeftOver >> 8);
  842.                     }
  843.                    
  844.                     charLeftOver = (char)0;
  845.                 }
  846.                 else if (charLeftOver > 0) {
  847.                     // Expected a low surrogate, but this char is normal
  848.                    
  849.                     // Rewind the current character, fallback previous character.
  850.                     // this should be safe because we don't have leftover data in the
  851.                     // fallback, so chars must have advanced already.
  852.                     BCLDebug.Assert(chars > charStart, "[UnicodeEncoding.GetBytes]Expected chars to have advanced after expecting low surrogate");
  853.                     chars--;
  854.                    
  855.                     // fallback previous chars
  856.                     // Might need to create our fallback buffer
  857.                     if (fallbackBuffer == null) {
  858.                         if (encoder == null)
  859.                             fallbackBuffer = this.encoderFallback.CreateFallbackBuffer();
  860.                         else
  861.                             fallbackBuffer = encoder.FallbackBuffer;
  862.                        
  863.                         // Set our internal fallback interesting things.
  864.                         fallbackBuffer.InternalInitialize(charStart, charEnd, encoder, true);
  865.                     }
  866.                    
  867.                     fallbackBuffer.InternalFallback(charLeftOver, ref chars);
  868.                    
  869.                     // Ignore charLeftOver or throw
  870.                     charLeftOver = (char)0;
  871.                     continue;
  872.                 }
  873.                
  874.                 // Ok, we have a char to add
  875.                 if (bytes + 1 >= byteEnd) {
  876.                     // Couldn't add this char
  877.                     if (fallbackBuffer != null && fallbackBuffer.bFallingBack)
  878.                         fallbackBuffer.MovePrevious();
  879.                     // Not using this fallback char
  880.                     else {
  881.                         // Lonely charLeftOver (from previous call) would've been caught up above,
  882.                         // so this must be a case where we've already read an input char.
  883.                         BCLDebug.Assert(chars > charStart, "[UnicodeEncoding.GetBytes]Expected chars to have advanced for failed fallback");
  884.                         chars--;
  885.                         // Not using this char
  886.                     }
  887.                     ThrowBytesOverflow(encoder, bytes == byteStart);
  888.                     // Throw maybe (if no bytes written)
  889.                     break;
  890.                     // didn't throw, just stop
  891.                 }
  892.                
  893.                 if (bigEndian) {
  894.                     *(bytes++) = (byte)(ch >> 8);
  895.                     *(bytes++) = (byte)ch;
  896.                 }
  897.                 else {
  898.                     *(bytes++) = (byte)ch;
  899.                     *(bytes++) = (byte)(ch >> 8);
  900.                 }
  901.             }
  902.            
  903.             // Don't allocate space for left over char
  904.             if (charLeftOver > 0) {
  905.                 // If we aren't flushing we need to fall this back
  906.                 if (encoder == null || encoder.MustFlush) {
  907.                     if (wasHereBefore) {
  908.                         // Throw it, using our complete character
  909.                         throw new ArgumentException(Environment.GetResourceString("Argument_RecursiveFallback", charLeftOver), "chars");
  910.                     }
  911.                     else {
  912.                         // If we have to flush, stick it in fallback and try again
  913.                         // Might need to create our fallback buffer
  914.                         if (fallbackBuffer == null) {
  915.                             if (encoder == null)
  916.                                 fallbackBuffer = this.encoderFallback.CreateFallbackBuffer();
  917.                             else
  918.                                 fallbackBuffer = encoder.FallbackBuffer;
  919.                            
  920.                             // Set our internal fallback interesting things.
  921.                             fallbackBuffer.InternalInitialize(charStart, charEnd, encoder, true);
  922.                         }
  923.                        
  924.                         // If we're not flushing, this'll remember the left over character.
  925.                         fallbackBuffer.InternalFallback(charLeftOver, ref chars);
  926.                        
  927.                         charLeftOver = (char)0;
  928.                         wasHereBefore = true;
  929.                         goto TryAgain;
  930.                     }
  931.                 }
  932.                
  933.             }
  934.            
  935.             // Not flushing, remember it in the encoder
  936.             if (encoder != null) {
  937.                 encoder.charLeftOver = charLeftOver;
  938.                 encoder.m_charsUsed = (int)(chars - charStart);
  939.             }
  940.            
  941.             // Remember charLeftOver if we must, or clear it if we're flushing
  942.             // (charLeftOver should be 0 if we're flushing)
  943.             BCLDebug.Assert((encoder != null && !encoder.MustFlush) || charLeftOver == (char)0, "[UnicodeEncoding.GetBytes] Expected no left over characters if flushing");
  944.            
  945.             BCLDebug.Assert(fallbackBuffer == null || fallbackBuffer.Remaining == 0 || encoder == null || !encoder.m_throwOnOverflow, "[UnicodeEncoding.GetBytes]Expected empty fallback buffer if not converting");
  946.            
  947.             // We used to copy it fast, but this doesn't check for surrogates
  948.             // System.IO.__UnmanagedMemoryStream.memcpyimpl(bytes, (byte*)chars, usedByteCount);
  949.            
  950.             return (int)(bytes - byteStart);
  951.         }
  952.        
  953.         unsafe internal override int GetCharCount(byte* bytes, int count, DecoderNLS baseDecoder)
  954.         {
  955.             BCLDebug.Assert(bytes != null, "[UnicodeEncoding.GetCharCount]bytes!=null");
  956.             BCLDebug.Assert(count >= 0, "[UnicodeEncoding.GetCharCount]count >=0");
  957.            
  958.             UnicodeEncoding.Decoder decoder = (UnicodeEncoding.Decoder)baseDecoder;
  959.            
  960.             byte* byteEnd = bytes + count;
  961.             byte* byteStart = bytes;
  962.            
  963.             // Need last vars
  964.             int lastByte = -1;
  965.             char lastChar = (char)0;
  966.            
  967.             // Start by assuming same # of chars as bytes
  968.             int charCount = count >> 1;
  969.            
  970.             // Need -1 to check 2 at a time. If we have an even #, longBytes will go
  971.             // from longEnd - 1/2 long to longEnd + 1/2 long. If we're odd, longBytes
  972.             // will go from longEnd - 1 long to longEnd. (Might not get to use this)
  973.             ulong* longEnd = (ulong*)(byteEnd - 7);
  974.            
  975.             // For fallback we may need a fallback buffer
  976.             DecoderFallbackBuffer fallbackBuffer = null;
  977.            
  978.             if (decoder != null) {
  979.                 lastByte = decoder.lastByte;
  980.                 lastChar = decoder.lastChar;
  981.                
  982.                 // Assume extra char if last char was around
  983.                 if (lastChar > 0)
  984.                     charCount++;
  985.                
  986.                 // Assume extra char if extra last byte makes up odd # of input bytes
  987.                 if (lastByte >= 0 && (count & 1) == 1) {
  988.                     charCount++;
  989.                 }
  990.                
  991.                 // Shouldn't have anything in fallback buffer for GetCharCount
  992.                 // (don't have to check m_throwOnOverflow for count)
  993.                 BCLDebug.Assert(!decoder.InternalHasFallbackBuffer || decoder.FallbackBuffer.Remaining == 0, "[UnicodeEncoding.GetCharCount]Expected empty fallback buffer at start");
  994.             }
  995.            
  996.             while (bytes < byteEnd) {
  997.                 // If we're aligned then maybe we can do it fast
  998.                 // This'll hurt if we're unaligned because we'll always test but never be aligned
  999.                 #if BIGENDIAN
  1000.                 if (bigEndian && )
  1001.                     #else // BIGENDIAN
  1002.                     #endif // BIGENDIAN
  1003.                     if (!bigEndian && (unchecked((int)bytes) & 3) == 0 && lastByte == -1 && lastChar == 0) {
  1004.                         // Need new char* so we can check 4 at a time
  1005.                         ulong* longBytes = (ulong*)bytes;
  1006.                        
  1007.                         while (longBytes < longEnd) {
  1008.                             if (((ulong)(9223512776490647552ul) & *longBytes) != 0) {
  1009.                                 // See if all 4 of those are bad...
  1010.                                 // Surrogate pairs are "backwards" for little endian machines read in as one
  1011.                                 // Mask off surrogate bits
  1012.                                 ulong uTemp = (15564677810327967744ul & *longBytes) ^ 15564677810327967744ul;
  1013.                                
  1014.                                 // Check each of the 4 chars. 0 for those 16 bits means it was a surrogate
  1015.                                 if ((uTemp & 18446462598732840960ul) == 0 || (uTemp & 281470681743360l) == 0 || (uTemp & 4294901760u) == 0 || (uTemp & 65535) == 0) {
  1016.                                     // Does it happen to have 4 good surrogates?
  1017.                                     #if BIGENDIAN
  1018.                                     if (((15852912584593300480ul & *longBytes) ^ 15564682208374479872ul) != 0)
  1019.                                         #else
  1020.                                         #endif // BIGENDIAN
  1021.                                         if (((15852912584593300480ul & *longBytes) ^ 15852908186546788352ul) != 0) {
  1022.                                             // If it wasn't 4 good surrogates then fall through to slow loop
  1023.                                             break;
  1024.                                         }
  1025.                                    
  1026.                                     // Use these 4 lucky ordered surrogate pairs.
  1027.                                 }
  1028.                                
  1029.                                 // Use these 4 high, but not surrogates
  1030.                             }
  1031.                            
  1032.                             // We can use these 4 chars.
  1033.                             longBytes++;
  1034.                         }
  1035.                        
  1036.                         bytes = (byte*)longBytes;
  1037.                        
  1038.                         if (bytes >= byteEnd)
  1039.                             break;
  1040.                     }
  1041.                
  1042.                 // Get 1st byte
  1043.                 if (lastByte < 0) {
  1044.                     lastByte = *bytes++;
  1045.                     if (bytes >= byteEnd)
  1046.                         break;
  1047.                 }
  1048.                
  1049.                 // Get full char
  1050.                 char ch;
  1051.                 if (bigEndian) {
  1052.                     ch = (char)(lastByte << 8 | *(bytes++));
  1053.                 }
  1054.                 else {
  1055.                     ch = (char)(*(bytes++) << 8 | lastByte);
  1056.                 }
  1057.                 lastByte = -1;
  1058.                
  1059.                 // See if the char's valid
  1060.                 if (ch >= 55296 && ch <= 57343) {
  1061.                     // Was it a high surrogate?
  1062.                     if (ch <= 56319) {
  1063.                         // Its a high surrogate, if we had one then do fallback for previous one
  1064.                         if (lastChar > 0) {
  1065.                             // Ignore previous bad high surrogate
  1066.                             charCount--;
  1067.                            
  1068.                             // Get fallback for previous high surrogate
  1069.                             // Note we have to reconstruct bytes because some may have been in decoder
  1070.                             byte[] byteBuffer = null;
  1071.                             if (bigEndian) {
  1072.                                 byteBuffer = new byte[] {unchecked((byte)(lastChar >> 8)), unchecked((byte)lastChar)};
  1073.                             }
  1074.                             else {
  1075.                                 byteBuffer = new byte[] {unchecked((byte)lastChar), unchecked((byte)(lastChar >> 8))};
  1076.                                
  1077.                             }
  1078.                            
  1079.                             if (fallbackBuffer == null) {
  1080.                                 if (decoder == null)
  1081.                                     fallbackBuffer = this.decoderFallback.CreateFallbackBuffer();
  1082.                                 else
  1083.                                     fallbackBuffer = decoder.FallbackBuffer;
  1084.                                
  1085.                                 // Set our internal fallback interesting things.
  1086.                                 fallbackBuffer.InternalInitialize(byteStart, null);
  1087.                             }
  1088.                            
  1089.                             // Get fallback.
  1090.                             charCount += fallbackBuffer.InternalFallback(byteBuffer, bytes);
  1091.                         }
  1092.                        
  1093.                         // Ignore the last one which fell back already,
  1094.                         // and remember the new high surrogate
  1095.                         lastChar = ch;
  1096.                         continue;
  1097.                     }
  1098.                    
  1099.                     // Its a low surrogate
  1100.                     if (lastChar == 0) {
  1101.                         // Expected a previous high surrogate
  1102.                         charCount--;
  1103.                        
  1104.                         // Get fallback for this low surrogate
  1105.                         // Note we have to reconstruct bytes because some may have been in decoder
  1106.                         byte[] byteBuffer = null;
  1107.                         if (bigEndian) {
  1108.                             byteBuffer = new byte[] {unchecked((byte)(ch >> 8)), unchecked((byte)ch)};
  1109.                         }
  1110.                         else {
  1111.                             byteBuffer = new byte[] {unchecked((byte)ch), unchecked((byte)(ch >> 8))};
  1112.                            
  1113.                         }
  1114.                        
  1115.                         if (fallbackBuffer == null) {
  1116.                             if (decoder == null)
  1117.                                 fallbackBuffer = this.decoderFallback.CreateFallbackBuffer();
  1118.                             else
  1119.                                 fallbackBuffer = decoder.FallbackBuffer;
  1120.                            
  1121.                             // Set our internal fallback interesting things.
  1122.                             fallbackBuffer.InternalInitialize(byteStart, null);
  1123.                         }
  1124.                        
  1125.                         charCount += fallbackBuffer.InternalFallback(byteBuffer, bytes);
  1126.                        
  1127.                         // Ignore this one (we already did its fallback)
  1128.                         continue;
  1129.                     }
  1130.                    
  1131.                     // Valid surrogate pair, already counted.
  1132.                     lastChar = (char)0;
  1133.                 }
  1134.                 else if (lastChar > 0) {
  1135.                     // Had a high surrogate, expected a low surrogate
  1136.                     // Uncount the last high surrogate
  1137.                     charCount--;
  1138.                    
  1139.                     // fall back the high surrogate.
  1140.                     byte[] byteBuffer = null;
  1141.                     if (bigEndian) {
  1142.                         byteBuffer = new byte[] {unchecked((byte)(lastChar >> 8)), unchecked((byte)lastChar)};
  1143.                     }
  1144.                     else {
  1145.                         byteBuffer = new byte[] {unchecked((byte)lastChar), unchecked((byte)(lastChar >> 8))};
  1146.                        
  1147.                     }
  1148.                    
  1149.                     if (fallbackBuffer == null) {
  1150.                         if (decoder == null)
  1151.                             fallbackBuffer = this.decoderFallback.CreateFallbackBuffer();
  1152.                         else
  1153.                             fallbackBuffer = decoder.FallbackBuffer;
  1154.                        
  1155.                         // Set our internal fallback interesting things.
  1156.                         fallbackBuffer.InternalInitialize(byteStart, null);
  1157.                     }
  1158.                    
  1159.                     // Already subtracted high surrogate
  1160.                     charCount += fallbackBuffer.InternalFallback(byteBuffer, bytes);
  1161.                    
  1162.                     // Not left over now, clear previous high surrogate and continue to add current char
  1163.                     lastChar = (char)0;
  1164.                 }
  1165.                
  1166.                 // Valid char, already counted
  1167.             }
  1168.            
  1169.             // Extra space if we can't use decoder
  1170.             if (decoder == null || decoder.MustFlush) {
  1171.                 if (lastChar > 0) {
  1172.                     // No hanging high surrogates allowed, do fallback and remove count for it
  1173.                     charCount--;
  1174.                     byte[] byteBuffer = null;
  1175.                     if (bigEndian) {
  1176.                         byteBuffer = new byte[] {unchecked((byte)(lastChar >> 8)), unchecked((byte)lastChar)};
  1177.                     }
  1178.                     else {
  1179.                         byteBuffer = new byte[] {unchecked((byte)lastChar), unchecked((byte)(lastChar >> 8))};
  1180.                        
  1181.                     }
  1182.                    
  1183.                     if (fallbackBuffer == null) {
  1184.                         if (decoder == null)
  1185.                             fallbackBuffer = this.decoderFallback.CreateFallbackBuffer();
  1186.                         else
  1187.                             fallbackBuffer = decoder.FallbackBuffer;
  1188.                        
  1189.                         // Set our internal fallback interesting things.
  1190.                         fallbackBuffer.InternalInitialize(byteStart, null);
  1191.                     }
  1192.                    
  1193.                     charCount += fallbackBuffer.InternalFallback(byteBuffer, bytes);
  1194.                    
  1195.                     lastChar = (char)0;
  1196.                 }
  1197.                
  1198.                 if (lastByte >= 0) {
  1199.                     if (fallbackBuffer == null) {
  1200.                         if (decoder == null)
  1201.                             fallbackBuffer = this.decoderFallback.CreateFallbackBuffer();
  1202.                         else
  1203.                             fallbackBuffer = decoder.FallbackBuffer;
  1204.                        
  1205.                         // Set our internal fallback interesting things.
  1206.                         fallbackBuffer.InternalInitialize(byteStart, null);
  1207.                     }
  1208.                    
  1209.                     // No hanging odd bytes allowed if must flush
  1210.                     charCount += fallbackBuffer.InternalFallback(new byte[] {unchecked((byte)lastByte)}, bytes);
  1211.                     lastByte = -1;
  1212.                 }
  1213.             }
  1214.            
  1215.             // If we had a high surrogate left over, we can't count it
  1216.             if (lastChar > 0)
  1217.                 charCount--;
  1218.            
  1219.             // Shouldn't have anything in fallback buffer for GetCharCount
  1220.             // (don't have to check m_throwOnOverflow for count)
  1221.             BCLDebug.Assert(fallbackBuffer == null || fallbackBuffer.Remaining == 0, "[UnicodeEncoding.GetCharCount]Expected empty fallback buffer at end");
  1222.            
  1223.             return charCount;
  1224.         }
  1225.        
  1226.         unsafe internal override int GetChars(byte* bytes, int byteCount, char* chars, int charCount, DecoderNLS baseDecoder)
  1227.         {
  1228.             BCLDebug.Assert(chars != null, "[UnicodeEncoding.GetChars]chars!=null");
  1229.             BCLDebug.Assert(byteCount >= 0, "[UnicodeEncoding.GetChars]byteCount >=0");
  1230.             BCLDebug.Assert(charCount >= 0, "[UnicodeEncoding.GetChars]charCount >=0");
  1231.             BCLDebug.Assert(bytes != null, "[UnicodeEncoding.GetChars]bytes!=null");
  1232.            
  1233.             UnicodeEncoding.Decoder decoder = (UnicodeEncoding.Decoder)baseDecoder;
  1234.            
  1235.             // Need last vars
  1236.             int lastByte = -1;
  1237.             char lastChar = (char)0;
  1238.            
  1239.             // Get our decoder (but don't clear it yet)
  1240.             if (decoder != null) {
  1241.                 lastByte = decoder.lastByte;
  1242.                 lastChar = decoder.lastChar;
  1243.                
  1244.                 // Shouldn't have anything in fallback buffer for GetChars
  1245.                 // (don't have to check m_throwOnOverflow for chars)
  1246.                 BCLDebug.Assert(!decoder.InternalHasFallbackBuffer || decoder.FallbackBuffer.Remaining == 0, "[UnicodeEncoding.GetChars]Expected empty fallback buffer at start");
  1247.             }
  1248.            
  1249.             // For fallback we may need a fallback buffer
  1250.             DecoderFallbackBuffer fallbackBuffer = null;
  1251.            
  1252.             byte* byteEnd = bytes + byteCount;
  1253.             char* charEnd = chars + charCount;
  1254.             byte* byteStart = bytes;
  1255.             char* charStart = chars;
  1256.            
  1257.             while (bytes < byteEnd) {
  1258.                 // If we're aligned then maybe we can do it fast
  1259.                 // This'll hurt if we're unaligned because we'll always test but never be aligned
  1260.                 #if BIGENDIAN
  1261.                 if (bigEndian && )
  1262.                     #else // BIGENDIAN
  1263.                     #endif // BIGENDIAN
  1264.                     if (!bigEndian && (unchecked((int)chars) & 3) == 0 && (unchecked((int)bytes) & 3) == 0 && lastByte == -1 && lastChar == 0) {
  1265.                         // Need -1 to check 2 at a time. If we have an even #, longChars will go
  1266.                         // from longEnd - 1/2 long to longEnd + 1/2 long. If we're odd, longChars
  1267.                         // will go from longEnd - 1 long to longEnd. (Might not get to use this)
  1268.                         // We can only go iCount units (limited by shorter of char or byte buffers.
  1269.                         ulong* longEnd = (ulong*)(bytes - 7 + (((byteEnd - bytes) >> 1 < charEnd - chars) ? (byteEnd - bytes) : (charEnd - chars) << 1));
  1270.                        
  1271.                         // Need new char* so we can check 4 at a time
  1272.                         ulong* longBytes = (ulong*)bytes;
  1273.                         ulong* longChars = (ulong*)chars;
  1274.                        
  1275.                         while (longBytes < longEnd) {
  1276.                             if (((ulong)(9223512776490647552ul) & *longBytes) != 0) {
  1277.                                 // See if all 4 of those are bad...
  1278.                                 // Surrogate pairs are "backwards" for little endian machines read in as one
  1279.                                 // Mask off surrogate bits
  1280.                                 ulong uTemp = (15564677810327967744ul & *longBytes) ^ 15564677810327967744ul;
  1281.                                
  1282.                                 // Check each of the 4 chars. 0 for those 16 bits means it was a surrogate
  1283.                                 if ((uTemp & 18446462598732840960ul) == 0 || (uTemp & 281470681743360l) == 0 || (uTemp & 4294901760u) == 0 || (uTemp & 65535) == 0) {
  1284.                                     // Does it happen to have 4 good surrogates?
  1285.                                     #if BIGENDIAN
  1286.                                     if (((15852912584593300480ul & *longBytes) ^ 15564682208374479872ul) != 0)
  1287.                                         #else
  1288.                                         #endif // BIGENDIAN
  1289.                                         if (((15852912584593300480ul & *longBytes) ^ 15852908186546788352ul) != 0) {
  1290.                                             // If it wasn't 4 good surrogates then fall through to slow loop
  1291.                                             break;
  1292.                                         }
  1293.                                    
  1294.                                     // Use these 4 lucky ordered surrogate pairs.
  1295.                                 }
  1296.                                
  1297.                                 // Use these 4 high, but not surrogates
  1298.                             }
  1299.                            
  1300.                             // We can use these 4 chars.
  1301.                             *longChars = *longBytes;
  1302.                             longBytes++;
  1303.                             longChars++;
  1304.                         }
  1305.                        
  1306.                         chars = (char*)longChars;
  1307.                         bytes = (byte*)longBytes;
  1308.                        
  1309.                         if (bytes >= byteEnd)
  1310.                             break;
  1311.                     }
  1312.                
  1313.                 // Get 1st byte
  1314.                 if (lastByte < 0) {
  1315.                     lastByte = *bytes++;
  1316.                     continue;
  1317.                 }
  1318.                
  1319.                 // Get full char
  1320.                 char ch;
  1321.                 if (bigEndian) {
  1322.                     ch = (char)(lastByte << 8 | *(bytes++));
  1323.                 }
  1324.                 else {
  1325.                     ch = (char)(*(bytes++) << 8 | lastByte);
  1326.                 }
  1327.                 lastByte = -1;
  1328.                
  1329.                 // See if the char's valid
  1330.                 if (ch >= 55296 && ch <= 57343) {
  1331.                     // Was it a high surrogate?
  1332.                     if (ch <= 56319) {
  1333.                         // Its a high surrogate, if we had one then do fallback for previous one
  1334.                         if (lastChar > 0) {
  1335.                             // Get fallback for previous high surrogate
  1336.                             // Note we have to reconstruct bytes because some may have been in decoder
  1337.                             byte[] byteBuffer = null;
  1338.                             if (bigEndian) {
  1339.                                 byteBuffer = new byte[] {unchecked((byte)(lastChar >> 8)), unchecked((byte)lastChar)};
  1340.                             }
  1341.                             else {
  1342.                                 byteBuffer = new byte[] {unchecked((byte)lastChar), unchecked((byte)(lastChar >> 8))};
  1343.                                
  1344.                             }
  1345.                            
  1346.                             if (fallbackBuffer == null) {
  1347.                                 if (decoder == null)
  1348.                                     fallbackBuffer = this.decoderFallback.CreateFallbackBuffer();
  1349.                                 else
  1350.                                     fallbackBuffer = decoder.FallbackBuffer;
  1351.                                
  1352.                                 // Set our internal fallback interesting things.
  1353.                                 fallbackBuffer.InternalInitialize(byteStart, charEnd);
  1354.                             }
  1355.                            
  1356.                             if (!fallbackBuffer.InternalFallback(byteBuffer, bytes, ref chars)) {
  1357.                                 // couldn't fall back lonely surrogate
  1358.                                 // We either advanced bytes or chars should == charStart and throw below
  1359.                                 BCLDebug.Assert(bytes >= byteStart + 2 || chars == charStart, "[UnicodeEncoding.GetChars]Expected bytes to have advanced or no output (bad surrogate)");
  1360.                                 bytes -= 2;
  1361.                                 // didn't use these 2 bytes
  1362.                                 fallbackBuffer.InternalReset();
  1363.                                 ThrowCharsOverflow(decoder, chars == charStart);
  1364.                                 // Might throw, if no chars output
  1365.                                 break;
  1366.                                 // couldn't fallback but didn't throw
  1367.                             }
  1368.                         }
  1369.                        
  1370.                         // Ignore the previous high surrogate which fell back already,
  1371.                         // yet remember the current high surrogate for next time.
  1372.                         lastChar = ch;
  1373.                         continue;
  1374.                     }
  1375.                    
  1376.                     // Its a low surrogate
  1377.                     if (lastChar == 0) {
  1378.                         // Expected a previous high surrogate
  1379.                         // Get fallback for this low surrogate
  1380.                         // Note we have to reconstruct bytes because some may have been in decoder
  1381.                         byte[] byteBuffer = null;
  1382.                         if (bigEndian) {
  1383.                             byteBuffer = new byte[] {unchecked((byte)(ch >> 8)), unchecked((byte)ch)};
  1384.                         }
  1385.                         else {
  1386.                             byteBuffer = new byte[] {unchecked((byte)ch), unchecked((byte)(ch >> 8))};
  1387.                            
  1388.                         }
  1389.                        
  1390.                         if (fallbackBuffer == null) {
  1391.                             if (decoder == null)
  1392.                                 fallbackBuffer = this.decoderFallback.CreateFallbackBuffer();
  1393.                             else
  1394.                                 fallbackBuffer = decoder.FallbackBuffer;
  1395.                            
  1396.                             // Set our internal fallback interesting things.
  1397.                             fallbackBuffer.InternalInitialize(byteStart, charEnd);
  1398.                         }
  1399.                        
  1400.                         if (!fallbackBuffer.InternalFallback(byteBuffer, bytes, ref chars)) {
  1401.                             // couldn't fall back lonely surrogate
  1402.                             // We either advanced bytes or chars should == charStart and throw below
  1403.                             BCLDebug.Assert(bytes >= byteStart + 2 || chars == charStart, "[UnicodeEncoding.GetChars]Expected bytes to have advanced or no output (lonely surrogate)");
  1404.                             bytes -= 2;
  1405.                             // didn't use these 2 bytes
  1406.                             fallbackBuffer.InternalReset();
  1407.                             ThrowCharsOverflow(decoder, chars == charStart);
  1408.                             // Might throw, if no chars output
  1409.                             break;
  1410.                             // couldn't fallback but didn't throw
  1411.                         }
  1412.                        
  1413.                         // Didn't throw, ignore this one (we already did its fallback)
  1414.                         continue;
  1415.                     }
  1416.                    
  1417.                     // Valid surrogate pair, add our lastChar (will need 2 chars)
  1418.                     if (chars >= charEnd - 1) {
  1419.                         // couldn't find room for this surrogate pair
  1420.                         // We either advanced bytes or chars should == charStart and throw below
  1421.                         BCLDebug.Assert(bytes >= byteStart + 2 || chars == charStart, "[UnicodeEncoding.GetChars]Expected bytes to have advanced or no output (surrogate pair)");
  1422.                         bytes -= 2;
  1423.                         // didn't use these 2 bytes
  1424.                         ThrowCharsOverflow(decoder, chars == charStart);
  1425.                         // Might throw, if no chars output
  1426.                         // Leave lastChar for next call to Convert()
  1427.                         break;
  1428.                         // couldn't fallback but didn't throw
  1429.                     }
  1430.                    
  1431.                     *chars++ = lastChar;
  1432.                     lastChar = (char)0;
  1433.                 }
  1434.                 else if (lastChar > 0) {
  1435.                     // Had a high surrogate, expected a low surrogate, fall back the high surrogate.
  1436.                     byte[] byteBuffer = null;
  1437.                     if (bigEndian) {
  1438.                         byteBuffer = new byte[] {unchecked((byte)(lastChar >> 8)), unchecked((byte)lastChar)};
  1439.                     }
  1440.                     else {
  1441.                         byteBuffer = new byte[] {unchecked((byte)lastChar), unchecked((byte)(lastChar >> 8))};
  1442.                        
  1443.                     }
  1444.                    
  1445.                     if (fallbackBuffer == null) {
  1446.                         if (decoder == null)
  1447.                             fallbackBuffer = this.decoderFallback.CreateFallbackBuffer();
  1448.                         else
  1449.                             fallbackBuffer = decoder.FallbackBuffer;
  1450.                        
  1451.                         // Set our internal fallback interesting things.
  1452.                         fallbackBuffer.InternalInitialize(byteStart, charEnd);
  1453.                     }
  1454.                    
  1455.                     if (!fallbackBuffer.InternalFallback(byteBuffer, bytes, ref chars)) {
  1456.                         // couldn't fall back high surrogate, or char that would be next
  1457.                         // We either advanced bytes or chars should == charStart and throw below
  1458.                         BCLDebug.Assert(bytes >= byteStart + 2 || chars == charStart, "[UnicodeEncoding.GetChars]Expected bytes to have advanced or no output (no low surrogate)");
  1459.                         bytes -= 2;
  1460.                         // didn't use these 2 bytes
  1461.                         fallbackBuffer.InternalReset();
  1462.                         ThrowCharsOverflow(decoder, chars == charStart);
  1463.                         // Might throw, if no chars output
  1464.                         break;
  1465.                         // couldn't fallback but didn't throw
  1466.                     }
  1467.                    
  1468.                     // Not left over now, clear previous high surrogate and continue to add current char
  1469.                     lastChar = (char)0;
  1470.                 }
  1471.                
  1472.                 // Valid char, room for it?
  1473.                 if (chars >= charEnd) {
  1474.                     // 2 bytes couldn't fall back
  1475.                     // We either advanced bytes or chars should == charStart and throw below
  1476.                     BCLDebug.Assert(bytes >= byteStart + 2 || chars == charStart, "[UnicodeEncoding.GetChars]Expected bytes to have advanced or no output (normal)");
  1477.                     bytes -= 2;
  1478.                     // didn't use these bytes
  1479.                     ThrowCharsOverflow(decoder, chars == charStart);
  1480.                     // Might throw, if no chars output
  1481.                     break;
  1482.                     // couldn't fallback but didn't throw
  1483.                 }
  1484.                
  1485.                 // add it
  1486.                 *chars++ = ch;
  1487.             }
  1488.            
  1489.             // Remember our decoder if we must
  1490.             if (decoder == null || decoder.MustFlush) {
  1491.                 if (lastChar > 0) {
  1492.                     // No hanging high surrogates allowed, do fallback and remove count for it
  1493.                     byte[] byteBuffer = null;
  1494.                     if (bigEndian) {
  1495.                         byteBuffer = new byte[] {unchecked((byte)(lastChar >> 8)), unchecked((byte)lastChar)};
  1496.                     }
  1497.                     else {
  1498.                         byteBuffer = new byte[] {unchecked((byte)lastChar), unchecked((byte)(lastChar >> 8))};
  1499.                        
  1500.                     }
  1501.                    
  1502.                     if (fallbackBuffer == null) {
  1503.                         if (decoder == null)
  1504.                             fallbackBuffer = this.decoderFallback.CreateFallbackBuffer();
  1505.                         else
  1506.                             fallbackBuffer = decoder.FallbackBuffer;
  1507.                        
  1508.                         // Set our internal fallback interesting things.
  1509.                         fallbackBuffer.InternalInitialize(byteStart, charEnd);
  1510.                     }
  1511.                    
  1512.                     if (!fallbackBuffer.InternalFallback(byteBuffer, bytes, ref chars)) {
  1513.                         // 2 bytes couldn't fall back
  1514.                         // We either advanced bytes or chars should == charStart and throw below
  1515.                         BCLDebug.Assert(bytes >= byteStart + 2 || chars == charStart, "[UnicodeEncoding.GetChars]Expected bytes to have advanced or no output (decoder)");
  1516.                         bytes -= 2;
  1517.                         // didn't use these bytes
  1518.                         if (lastByte >= 0)
  1519.                             bytes--;
  1520.                         // had an extra last byte hanging around
  1521.                         fallbackBuffer.InternalReset();
  1522.                         ThrowCharsOverflow(decoder, chars == charStart);
  1523.                         // Might throw, if no chars output
  1524.                         // We'll remember these in our decoder though
  1525.                         bytes += 2;
  1526.                         if (lastByte >= 0)
  1527.                             bytes++;
  1528.                         goto End;
  1529.                     }
  1530.                    
  1531.                     // done with this one
  1532.                     lastChar = (char)0;
  1533.                 }
  1534.                
  1535.                 if (lastByte >= 0) {
  1536.                     if (fallbackBuffer == null) {
  1537.                         if (decoder == null)
  1538.                             fallbackBuffer = this.decoderFallback.CreateFallbackBuffer();
  1539.                         else
  1540.                             fallbackBuffer = decoder.FallbackBuffer;
  1541.                        
  1542.                         // Set our internal fallback interesting things.
  1543.                         fallbackBuffer.InternalInitialize(byteStart, charEnd);
  1544.                     }
  1545.                    
  1546.                     // No hanging odd bytes allowed if must flush
  1547.                     if (!fallbackBuffer.InternalFallback(new byte[] {unchecked((byte)lastByte)}, bytes, ref chars)) {
  1548.                         // odd byte couldn't fall back
  1549.                         bytes--;
  1550.                         // didn't use this byte
  1551.                         fallbackBuffer.InternalReset();
  1552.                         ThrowCharsOverflow(decoder, chars == charStart);
  1553.                         // Might throw, if no chars output
  1554.                         // didn't throw, but we'll remember it in the decoder
  1555.                         bytes++;
  1556.                         goto End;
  1557.                     }
  1558.                    
  1559.                     // Didn't fail, clear buffer
  1560.                     lastByte = -1;
  1561.                 }
  1562.             }
  1563.             End:
  1564.            
  1565.            
  1566.             // Remember our decoder if we must
  1567.             if (decoder != null) {
  1568.                     // + " " + ((int)lastChar).ToString("X4") + " " + lastByte.ToString("X2")
  1569.                 BCLDebug.Assert((decoder.MustFlush == false) || ((lastChar == (char)0) && (lastByte == -1)), "[UnicodeEncoding.GetChars] Expected no left over chars or bytes if flushing");
  1570.                
  1571.                 decoder.m_bytesUsed = (int)(bytes - byteStart);
  1572.                 decoder.lastChar = lastChar;
  1573.                 decoder.lastByte = lastByte;
  1574.             }
  1575.            
  1576.             // Used to do this the old way
  1577.             // System.IO.__UnmanagedMemoryStream.memcpyimpl((byte*)chars, bytes, byteCount);
  1578.            
  1579.             // Shouldn't have anything in fallback buffer for GetChars
  1580.             // (don't have to check m_throwOnOverflow for count or chars)
  1581.             BCLDebug.Assert(fallbackBuffer == null || fallbackBuffer.Remaining == 0, "[UnicodeEncoding.GetChars]Expected empty fallback buffer at end");
  1582.            
  1583.             return (int)(chars - charStart);
  1584.         }
  1585.        
  1586.        
  1587.         [System.Runtime.InteropServices.ComVisible(false)]
  1588.         public override System.Text.Encoder GetEncoder()
  1589.         {
  1590.             return new EncoderNLS(this);
  1591.         }
  1592.        
  1593.        
  1594.         public override System.Text.Decoder GetDecoder()
  1595.         {
  1596.             return new UnicodeEncoding.Decoder(this);
  1597.         }
  1598.        
  1599.        
  1600.         public override byte[] GetPreamble()
  1601.         {
  1602.             if (byteOrderMark) {
  1603.                 // Note - we must allocate new byte[]'s here to prevent someone
  1604.                 // from modifying a cached byte[].
  1605.                 if (bigEndian)
  1606.                     return new byte[2] {254, 255};
  1607.                 else
  1608.                     return new byte[2] {255, 254};
  1609.             }
  1610.             return emptyByteArray;
  1611.         }
  1612.        
  1613.        
  1614.         public override int GetMaxByteCount(int charCount)
  1615.         {
  1616.             if (charCount < 0)
  1617.                 throw new ArgumentOutOfRangeException("charCount", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
  1618.            
  1619.             // Characters would be # of characters + 1 in case left over high surrogate is ? * max fallback
  1620.             long byteCount = (long)charCount + 1;
  1621.            
  1622.             if (EncoderFallback.MaxCharCount > 1)
  1623.                 byteCount *= EncoderFallback.MaxCharCount;
  1624.            
  1625.             // 2 bytes per char
  1626.             byteCount <<= 1;
  1627.            
  1628.             if (byteCount > 2147483647)
  1629.                 throw new ArgumentOutOfRangeException("charCount", Environment.GetResourceString("ArgumentOutOfRange_GetByteCountOverflow"));
  1630.            
  1631.             return (int)byteCount;
  1632.         }
  1633.        
  1634.        
  1635.         public override int GetMaxCharCount(int byteCount)
  1636.         {
  1637.             if (byteCount < 0)
  1638.                 throw new ArgumentOutOfRangeException("byteCount", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
  1639.            
  1640.             // long because byteCount could be biggest int.
  1641.             // 1 char per 2 bytes. Round up in case 1 left over in decoder.
  1642.             // Round up using &1 in case byteCount is max size
  1643.             // Might also need an extra 1 if there's a left over high surrogate in the decoder.
  1644.             long charCount = (long)(byteCount >> 1) + (byteCount & 1) + 1;
  1645.            
  1646.             // Don't forget fallback (in case they have a bunch of lonely surrogates or something bizzare like that)
  1647.             if (DecoderFallback.MaxCharCount > 1)
  1648.                 charCount *= DecoderFallback.MaxCharCount;
  1649.            
  1650.             if (charCount > 2147483647)
  1651.                 throw new ArgumentOutOfRangeException("byteCount", Environment.GetResourceString("ArgumentOutOfRange_GetCharCountOverflow"));
  1652.            
  1653.             return (int)charCount;
  1654.         }
  1655.        
  1656.        
  1657.         public override bool Equals(object value)
  1658.         {
  1659.             UnicodeEncoding that = value as UnicodeEncoding;
  1660.             if (that != null) {
  1661.                 //
  1662.                 // Big Endian Unicode has different code page (1201) than small Endian one (1200),
  1663.                 // so we still have to check m_codePage here.
  1664.                 //
  1665.                     // isThrowException == that.isThrowException && // Same as Encoder/Decoder being exception fallbacks
  1666.                 return (CodePage == that.CodePage) && byteOrderMark == that.byteOrderMark && bigEndian == that.bigEndian && (EncoderFallback.Equals(that.EncoderFallback)) && (DecoderFallback.Equals(that.DecoderFallback));
  1667.             }
  1668.             return (false);
  1669.         }
  1670.        
  1671.         public override int GetHashCode()
  1672.         {
  1673.             return CodePage + this.EncoderFallback.GetHashCode() + this.DecoderFallback.GetHashCode() + (byteOrderMark ? 4 : 0) + (bigEndian ? 8 : 0);
  1674.         }
  1675.        
  1676.         [Serializable()]
  1677.         private class Decoder : System.Text.DecoderNLS, ISerializable
  1678.         {
  1679.             internal int lastByte = -1;
  1680.             internal char lastChar = '\0';
  1681.            
  1682.             public Decoder(UnicodeEncoding encoding) : base(encoding)
  1683.             {
  1684.                 // base calls reset
  1685.             }
  1686.            
  1687.             internal Decoder(SerializationInfo info, StreamingContext context)
  1688.             {
  1689.                 // Any info?
  1690.                 if (info == null)
  1691.                     throw new ArgumentNullException("info");
  1692.                
  1693.                 // Get Common Info
  1694.                 this.lastByte = (int)info.GetValue("lastByte", typeof(int));
  1695.                
  1696.                 try {
  1697.                     this.m_encoding = (Encoding)info.GetValue("m_encoding", typeof(Encoding));
  1698.                     this.lastChar = (char)info.GetValue("lastChar", typeof(char));
  1699.                     this.m_fallback = (DecoderFallback)info.GetValue("m_fallback", typeof(DecoderFallback));
  1700.                 }
  1701.                 catch (SerializationException) {
  1702.                     bool bigEndian = (bool)info.GetValue("bigEndian", typeof(bool));
  1703.                     this.m_encoding = new UnicodeEncoding(bigEndian, false);
  1704.                 }
  1705.             }
  1706.            
  1707.             // ISerializable implementation, get data for this object
  1708.             [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
  1709.             void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
  1710.             {
  1711.                 // Any info?
  1712.                 if (info == null)
  1713.                     throw new ArgumentNullException("info");
  1714.                
  1715.                 info.AddValue("m_encoding", this.m_encoding);
  1716.                 info.AddValue("m_fallback", this.m_fallback);
  1717.                 info.AddValue("lastChar", this.lastChar);
  1718.                 info.AddValue("lastByte", this.lastByte);
  1719.                
  1720.                 info.AddValue("bigEndian", ((UnicodeEncoding)(this.m_encoding)).bigEndian);
  1721.             }
  1722.            
  1723.             public override void Reset()
  1724.             {
  1725.                 lastByte = -1;
  1726.                 lastChar = '\0';
  1727.                 if (m_fallbackBuffer != null)
  1728.                     m_fallbackBuffer.Reset();
  1729.             }
  1730.            
  1731.             // Anything left in our decoder?
  1732.             internal override bool HasState {
  1733.                 get { return (this.lastByte != -1 || this.lastChar != '\0'); }
  1734.             }
  1735.         }
  1736.     }
  1737. }

Developer Fusion