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

  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. namespace System.Text
  16. {
  17.     using System;
  18.     using System.Runtime.Serialization;
  19.     using System.Security.Permissions;
  20.    
  21.     // ASCIIEncoding
  22.     //
  23.     // Note that ASCIIEncoding is optomized with no best fit and ? for fallback.
  24.     // It doesn't come in other flavors.
  25.     //
  26.     // Note: ASCIIEncoding is the only encoding that doesn't do best fit (windows has best fit).
  27.     //
  28.     // Note: IsAlwaysNormalized remains false because 1/2 the code points are unassigned, so they'd
  29.     // use fallbacks, and we cannot guarantee that fallbacks are normalized.
  30.     //
  31.    
  32.     [Serializable()]
  33.     [System.Runtime.InteropServices.ComVisible(true)]
  34.     public class ASCIIEncoding : Encoding
  35.     {
  36.        
  37.         public ASCIIEncoding() : base(Encoding.CodePageASCII)
  38.         {
  39.         }
  40.        
  41.         internal override void SetDefaultFallbacks()
  42.         {
  43.             // For ASCIIEncoding we just use default replacement fallback
  44.             this.encoderFallback = EncoderFallback.ReplacementFallback;
  45.             this.decoderFallback = DecoderFallback.ReplacementFallback;
  46.         }
  47.        
  48.         //
  49.         //
  50.        
  51.         //
  52.        
  53.         unsafe public override int GetByteCount(char[] chars, int index, int count)
  54.         {
  55.             // Validate input parameters
  56.             if (chars == null)
  57.                 throw new ArgumentNullException("chars", Environment.GetResourceString("ArgumentNull_Array"));
  58.            
  59.             if (index < 0 || count < 0)
  60.                 throw new ArgumentOutOfRangeException((index < 0 ? "index" : "count"), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
  61.            
  62.             if (chars.Length - index < count)
  63.                 throw new ArgumentOutOfRangeException("chars", Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
  64.            
  65.             // If no input, return 0, avoid fixed empty array problem
  66.             if (chars.Length == 0)
  67.                 return 0;
  68.            
  69.             // Just call the pointer version
  70.             fixed (char* pChars = chars)
  71.                 return GetByteCount(pChars + index, count, null);
  72.         }
  73.        
  74.         // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
  75.         // So if you fix this, fix the others. Currently those include:
  76.         // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
  77.         // parent method is safe
  78.        
  79.         unsafe public override int GetByteCount(string chars)
  80.         {
  81.             // Validate input
  82.             if (chars == null)
  83.                 throw new ArgumentNullException("chars");
  84.            
  85.             fixed (char* pChars = chars)
  86.                 return GetByteCount(pChars, chars.Length, null);
  87.         }
  88.        
  89.         // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
  90.         // So if you fix this, fix the others. Currently those include:
  91.         // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
  92.        
  93.         [CLSCompliant(false)]
  94.         [System.Runtime.InteropServices.ComVisible(false)]
  95.         unsafe public override int GetByteCount(char* chars, int count)
  96.         {
  97.             // Validate Parameters
  98.             if (chars == null)
  99.                 throw new ArgumentNullException("chars", Environment.GetResourceString("ArgumentNull_Array"));
  100.            
  101.             if (count < 0)
  102.                 throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
  103.            
  104.             // Call it with empty encoder
  105.             return GetByteCount(chars, count, null);
  106.         }
  107.        
  108.         // Parent method is safe.
  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.        
  113.         unsafe public override int GetBytes(string chars, int charIndex, int charCount, byte[] bytes, int byteIndex)
  114.         {
  115.             if (chars == null || bytes == null)
  116.                 throw new ArgumentNullException((chars == null ? "chars" : "bytes"), Environment.GetResourceString("ArgumentNull_Array"));
  117.            
  118.             if (charIndex < 0 || charCount < 0)
  119.                 throw new ArgumentOutOfRangeException((charIndex < 0 ? "charIndex" : "charCount"), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
  120.            
  121.             if (chars.Length - charIndex < charCount)
  122.                 throw new ArgumentOutOfRangeException("chars", Environment.GetResourceString("ArgumentOutOfRange_IndexCount"));
  123.            
  124.             if (byteIndex < 0 || byteIndex > bytes.Length)
  125.                 throw new ArgumentOutOfRangeException("byteIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
  126.            
  127.             int byteCount = bytes.Length - byteIndex;
  128.            
  129.             // Fixed doesn't like empty byte arrays
  130.             if (bytes.Length == 0)
  131.                 bytes = new byte[1];
  132.            
  133.             fixed (char* pChars = chars)
  134.                 fixed (byte* pBytes = bytes)
  135.                     return GetBytes(pChars + charIndex, charCount, pBytes + byteIndex, byteCount, null);
  136.         }
  137.        
  138.         // Encodes a range of characters in a character array into a range of bytes
  139.         // in a byte array. An exception occurs if the byte array is not large
  140.         // enough to hold the complete encoding of the characters. The
  141.         // GetByteCount method can be used to determine the exact number of
  142.         // bytes that will be produced for a given range of characters.
  143.         // Alternatively, the GetMaxByteCount method can be used to
  144.         // determine the maximum number of bytes that will be produced for a given
  145.         // number of characters, regardless of the actual character values.
  146.         //
  147.         // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
  148.         // So if you fix this, fix the others. Currently those include:
  149.         // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
  150.         // parent method is safe
  151.        
  152.         unsafe public override int GetBytes(char[] chars, int charIndex, int charCount, byte[] bytes, int byteIndex)
  153.         {
  154.             // Validate parameters
  155.             if (chars == null || bytes == null)
  156.                 throw new ArgumentNullException((chars == null ? "chars" : "bytes"), Environment.GetResourceString("ArgumentNull_Array"));
  157.            
  158.             if (charIndex < 0 || charCount < 0)
  159.                 throw new ArgumentOutOfRangeException((charIndex < 0 ? "charIndex" : "charCount"), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
  160.            
  161.             if (chars.Length - charIndex < charCount)
  162.                 throw new ArgumentOutOfRangeException("chars", Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
  163.            
  164.             if (byteIndex < 0 || byteIndex > bytes.Length)
  165.                 throw new ArgumentOutOfRangeException("byteIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
  166.            
  167.             // If nothing to encode return 0, avoid fixed problem
  168.             if (chars.Length == 0)
  169.                 return 0;
  170.            
  171.             // Just call pointer version
  172.             int byteCount = bytes.Length - byteIndex;
  173.            
  174.             // Fixed doesn't like empty byte arrays
  175.             if (bytes.Length == 0)
  176.                 bytes = new byte[1];
  177.            
  178.             fixed (char* pChars = chars)
  179.                 fixed (byte* pBytes = bytes)
  180.                 // Remember that byteCount is # to decode, not size of array.
  181.                     return GetBytes(pChars + charIndex, charCount, pBytes + byteIndex, byteCount, null);
  182.         }
  183.        
  184.         // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
  185.         // So if you fix this, fix the others. Currently those include:
  186.         // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
  187.        
  188.         [CLSCompliant(false)]
  189.         [System.Runtime.InteropServices.ComVisible(false)]
  190.         unsafe public override int GetBytes(char* chars, int charCount, byte* bytes, int byteCount)
  191.         {
  192.             // Validate Parameters
  193.             if (bytes == null || chars == null)
  194.                 throw new ArgumentNullException(bytes == null ? "bytes" : "chars", Environment.GetResourceString("ArgumentNull_Array"));
  195.            
  196.             if (charCount < 0 || byteCount < 0)
  197.                 throw new ArgumentOutOfRangeException((charCount < 0 ? "charCount" : "byteCount"), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
  198.            
  199.             return GetBytes(chars, charCount, bytes, byteCount, null);
  200.         }
  201.        
  202.         // Returns the number of characters produced by decoding a range of bytes
  203.         // in a byte array.
  204.         //
  205.         // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
  206.         // So if you fix this, fix the others. Currently those include:
  207.         // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
  208.         // parent method is safe
  209.        
  210.         unsafe public override int GetCharCount(byte[] bytes, int index, int count)
  211.         {
  212.             // Validate Parameters
  213.             if (bytes == null)
  214.                 throw new ArgumentNullException("bytes", Environment.GetResourceString("ArgumentNull_Array"));
  215.            
  216.             if (index < 0 || count < 0)
  217.                 throw new ArgumentOutOfRangeException((index < 0 ? "index" : "count"), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
  218.            
  219.             if (bytes.Length - index < count)
  220.                 throw new ArgumentOutOfRangeException("bytes", Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
  221.            
  222.             // If no input just return 0, fixed doesn't like 0 length arrays
  223.             if (bytes.Length == 0)
  224.                 return 0;
  225.            
  226.             // Just call pointer version
  227.             fixed (byte* pBytes = bytes)
  228.                 return GetCharCount(pBytes + index, count, null);
  229.         }
  230.        
  231.         // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
  232.         // So if you fix this, fix the others. Currently those include:
  233.         // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
  234.        
  235.         [CLSCompliant(false)]
  236.         [System.Runtime.InteropServices.ComVisible(false)]
  237.         unsafe public override int GetCharCount(byte* bytes, int count)
  238.         {
  239.             // Validate Parameters
  240.             if (bytes == null)
  241.                 throw new ArgumentNullException("bytes", Environment.GetResourceString("ArgumentNull_Array"));
  242.            
  243.             if (count < 0)
  244.                 throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
  245.            
  246.             return GetCharCount(bytes, count, null);
  247.         }
  248.        
  249.         // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
  250.         // So if you fix this, fix the others. Currently those include:
  251.         // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
  252.         // parent method is safe
  253.        
  254.         unsafe public override int GetChars(byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex)
  255.         {
  256.             // Validate Parameters
  257.             if (bytes == null || chars == null)
  258.                 throw new ArgumentNullException(bytes == null ? "bytes" : "chars", Environment.GetResourceString("ArgumentNull_Array"));
  259.            
  260.             if (byteIndex < 0 || byteCount < 0)
  261.                 throw new ArgumentOutOfRangeException((byteIndex < 0 ? "byteIndex" : "byteCount"), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
  262.            
  263.             if (bytes.Length - byteIndex < byteCount)
  264.                 throw new ArgumentOutOfRangeException("bytes", Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
  265.            
  266.             if (charIndex < 0 || charIndex > chars.Length)
  267.                 throw new ArgumentOutOfRangeException("charIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
  268.            
  269.             // If no input, return 0 & avoid fixed problem
  270.             if (bytes.Length == 0)
  271.                 return 0;
  272.            
  273.             // Just call pointer version
  274.             int charCount = chars.Length - charIndex;
  275.            
  276.             // Fixed doesn't like empty char arrays
  277.             if (chars.Length == 0)
  278.                 chars = new char[1];
  279.            
  280.             fixed (byte* pBytes = bytes)
  281.                 fixed (char* pChars = chars)
  282.                 // Remember that charCount is # to decode, not size of array
  283.                     return GetChars(pBytes + byteIndex, byteCount, pChars + charIndex, charCount, null);
  284.         }
  285.        
  286.         // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
  287.         // So if you fix this, fix the others. Currently those include:
  288.         // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
  289.        
  290.         [CLSCompliant(false)]
  291.         [System.Runtime.InteropServices.ComVisible(false)]
  292.         unsafe public override int GetChars(byte* bytes, int byteCount, char* chars, int charCount)
  293.         {
  294.             // Validate Parameters
  295.             if (bytes == null || chars == null)
  296.                 throw new ArgumentNullException(bytes == null ? "bytes" : "chars", Environment.GetResourceString("ArgumentNull_Array"));
  297.            
  298.             if (charCount < 0 || byteCount < 0)
  299.                 throw new ArgumentOutOfRangeException((charCount < 0 ? "charCount" : "byteCount"), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
  300.            
  301.             return GetChars(bytes, byteCount, chars, charCount, null);
  302.         }
  303.        
  304.         // Returns a string containing the decoded representation of a range of
  305.         // bytes in a byte array.
  306.         //
  307.         // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
  308.         // So if you fix this, fix the others. Currently those include:
  309.         // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
  310.         // parent method is safe
  311.        
  312.         unsafe public override string GetString(byte[] bytes, int byteIndex, int byteCount)
  313.         {
  314.             // Validate Parameters
  315.             if (bytes == null)
  316.                 throw new ArgumentNullException("bytes", Environment.GetResourceString("ArgumentNull_Array"));
  317.            
  318.             if (byteIndex < 0 || byteCount < 0)
  319.                 throw new ArgumentOutOfRangeException((byteIndex < 0 ? "byteIndex" : "byteCount"), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
  320.            
  321.            
  322.             if (bytes.Length - byteIndex < byteCount)
  323.                 throw new ArgumentOutOfRangeException("bytes", Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
  324.            
  325.             // Avoid problems with empty input buffer
  326.             if (bytes.Length == 0)
  327.                 return String.Empty;
  328.            
  329.             fixed (byte* pBytes = bytes)
  330.                 return String.CreateStringFromEncoding(pBytes + byteIndex, byteCount, this);
  331.         }
  332.        
  333.         //
  334.         // End of standard methods copied from EncodingNLS.cs
  335.         //
  336.        
  337.         // GetByteCount
  338.         // Note: We start by assuming that the output will be the same as count. Having
  339.         // an encoder or fallback may change that assumption
  340.         unsafe internal override int GetByteCount(char* chars, int charCount, EncoderNLS encoder)
  341.         {
  342.             // Just need to ASSERT, this is called by something else internal that checked parameters already
  343.             BCLDebug.Assert(charCount >= 0, "[ASCIIEncoding.GetByteCount]count is negative");
  344.             BCLDebug.Assert(chars != null, "[ASCIIEncoding.GetByteCount]chars is null");
  345.            
  346.             // Assert because we shouldn't be able to have a null encoder.
  347.             BCLDebug.Assert(encoderFallback != null, "[ASCIIEncoding.GetByteCount]Attempting to use null fallback encoder");
  348.            
  349.             char charLeftOver = (char)0;
  350.             EncoderReplacementFallback fallback = null;
  351.            
  352.             // Start by assuming default count, then +/- for fallback characters
  353.             char* charEnd = chars + charCount;
  354.            
  355.             // For fallback we may need a fallback buffer, we know we aren't default fallback.
  356.             EncoderFallbackBuffer fallbackBuffer = null;
  357.            
  358.             if (encoder != null) {
  359.                 charLeftOver = encoder.charLeftOver;
  360.                 BCLDebug.Assert(charLeftOver == 0 || Char.IsHighSurrogate(charLeftOver), "[ASCIIEncoding.GetByteCount]leftover character should be high surrogate");
  361.                
  362.                 fallback = encoder.Fallback as EncoderReplacementFallback;
  363.                
  364.                 // We mustn't have left over fallback data when counting
  365.                 if (encoder.InternalHasFallbackBuffer) {
  366.                     // We always need the fallback buffer in get bytes so we can flush any remaining ones if necessary
  367.                     fallbackBuffer = encoder.FallbackBuffer;
  368.                     if (fallbackBuffer.Remaining > 0 && encoder.m_throwOnOverflow)
  369.                         throw new ArgumentException(Environment.GetResourceString("Argument_EncoderFallbackNotEmpty", this.EncodingName, encoder.Fallback.GetType()));
  370.                    
  371.                     // Set our internal fallback interesting things.
  372.                     fallbackBuffer.InternalInitialize(chars, charEnd, encoder, false);
  373.                 }
  374.                
  375.                 // Verify that we have no fallbackbuffer, for ASCII its always empty, so just assert
  376.                 BCLDebug.Assert(!encoder.m_throwOnOverflow || !encoder.InternalHasFallbackBuffer || encoder.FallbackBuffer.Remaining == 0, "[ASCIICodePageEncoding.GetByteCount]Expected empty fallback buffer");
  377.                 // if (encoder.InternalHasFallbackBuffer && encoder.FallbackBuffer.Remaining > 0)
  378.                 // throw new ArgumentException(Environment.GetResourceString("Argument_EncoderFallbackNotEmpty",
  379.                 // this.EncodingName, encoder.Fallback.GetType()));
  380.             }
  381.             else {
  382.                 fallback = this.EncoderFallback as EncoderReplacementFallback;
  383.             }
  384.            
  385.             // If we have an encoder AND we aren't using default fallback,
  386.             // then we may have a complicated count.
  387.             if (fallback != null && fallback.MaxCharCount == 1) {
  388.                 // Replacement fallback encodes surrogate pairs as two ?? (or two whatever), so return size is always
  389.                 // same as input size.
  390.                 // Note that no existing SBCS code pages map code points to supplimentary characters, so this is easy.
  391.                
  392.                 // We could however have 1 extra byte if the last call had an encoder and a funky fallback and
  393.                 // if we don't use the funky fallback this time.
  394.                
  395.                 // Do we have an extra char left over from last time?
  396.                 if (charLeftOver > 0)
  397.                     charCount++;
  398.                
  399.                 return (charCount);
  400.             }
  401.            
  402.             // Count is more complicated if you have a funky fallback
  403.             // For fallback we may need a fallback buffer, we know we're not default fallback
  404.             int byteCount = 0;
  405.            
  406.             // We may have a left over character from last time, try and process it.
  407.             if (charLeftOver > 0) {
  408.                 BCLDebug.Assert(Char.IsHighSurrogate(charLeftOver), "[ASCIIEncoding.GetByteCount]leftover character should be high surrogate");
  409.                 BCLDebug.Assert(encoder != null, "[ASCIIEncoding.GetByteCount]Expected encoder");
  410.                
  411.                 // Since left over char was a surrogate, it'll have to be fallen back.
  412.                 // Get Fallback
  413.                 fallbackBuffer = encoder.FallbackBuffer;
  414.                 fallbackBuffer.InternalInitialize(chars, charEnd, encoder, false);
  415.                
  416.                 // This will fallback a pair if *chars is a low surrogate
  417.                 fallbackBuffer.InternalFallback(charLeftOver, ref chars);
  418.             }
  419.            
  420.             // Now we may have fallback char[] already from the encoder
  421.            
  422.             // Go ahead and do it, including the fallback.
  423.             char ch;
  424.             while ((ch = (fallbackBuffer == null) ? '\0' : fallbackBuffer.InternalGetNextChar()) != 0 || chars < charEnd) {
  425.                
  426.                 // First unwind any fallback
  427.                 if (ch == 0) {
  428.                     // No fallback, just get next char
  429.                     ch = *chars;
  430.                     chars++;
  431.                 }
  432.                
  433.                 // Check for fallback, this'll catch surrogate pairs too.
  434.                 // no chars >= 0x80 are allowed.
  435.                 if (ch > 127) {
  436.                     if (fallbackBuffer == null) {
  437.                         // Initialize the buffer
  438.                         if (encoder == null)
  439.                             fallbackBuffer = this.encoderFallback.CreateFallbackBuffer();
  440.                         else
  441.                             fallbackBuffer = encoder.FallbackBuffer;
  442.                         fallbackBuffer.InternalInitialize(charEnd - charCount, charEnd, encoder, false);
  443.                     }
  444.                    
  445.                     // Get Fallback
  446.                     fallbackBuffer.InternalFallback(ch, ref chars);
  447.                     continue;
  448.                 }
  449.                
  450.                 // We'll use this one
  451.                 byteCount++;
  452.             }
  453.            
  454.             BCLDebug.Assert(fallbackBuffer == null || fallbackBuffer.Remaining == 0, "[ASCIIEncoding.GetByteCount]Expected Empty fallback buffer");
  455.            
  456.             return byteCount;
  457.         }
  458.        
  459.         unsafe internal override int GetBytes(char* chars, int charCount, byte* bytes, int byteCount, EncoderNLS encoder)
  460.         {
  461.             // Just need to ASSERT, this is called by something else internal that checked parameters already
  462.             BCLDebug.Assert(bytes != null, "[ASCIIEncoding.GetBytes]bytes is null");
  463.             BCLDebug.Assert(byteCount >= 0, "[ASCIIEncoding.GetBytes]byteCount is negative");
  464.             BCLDebug.Assert(chars != null, "[ASCIIEncoding.GetBytes]chars is null");
  465.             BCLDebug.Assert(charCount >= 0, "[ASCIIEncoding.GetBytes]charCount is negative");
  466.            
  467.             // Assert because we shouldn't be able to have a null encoder.
  468.             BCLDebug.Assert(encoderFallback != null, "[ASCIIEncoding.GetBytes]Attempting to use null encoder fallback");
  469.            
  470.             // Get any left over characters
  471.             char charLeftOver = (char)0;
  472.             EncoderReplacementFallback fallback = null;
  473.            
  474.             // For fallback we may need a fallback buffer, we know we aren't default fallback.
  475.             EncoderFallbackBuffer fallbackBuffer = null;
  476.            
  477.             // prepare our end
  478.             char* charEnd = chars + charCount;
  479.             byte* byteStart = bytes;
  480.             char* charStart = chars;
  481.            
  482.             if (encoder != null) {
  483.                 charLeftOver = encoder.charLeftOver;
  484.                 fallback = encoder.Fallback as EncoderReplacementFallback;
  485.                
  486.                 // We mustn't have left over fallback data when counting
  487.                 if (encoder.InternalHasFallbackBuffer) {
  488.                     // We always need the fallback buffer in get bytes so we can flush any remaining ones if necessary
  489.                     fallbackBuffer = encoder.FallbackBuffer;
  490.                     if (fallbackBuffer.Remaining > 0 && encoder.m_throwOnOverflow)
  491.                         throw new ArgumentException(Environment.GetResourceString("Argument_EncoderFallbackNotEmpty", this.EncodingName, encoder.Fallback.GetType()));
  492.                    
  493.                     // Set our internal fallback interesting things.
  494.                     fallbackBuffer.InternalInitialize(charStart, charEnd, encoder, true);
  495.                 }
  496.                
  497.                 BCLDebug.Assert(charLeftOver == 0 || Char.IsHighSurrogate(charLeftOver), "[ASCIIEncoding.GetBytes]leftover character should be high surrogate");
  498.                
  499.                 // Verify that we have no fallbackbuffer, for ASCII its always empty, so just assert
  500.                 BCLDebug.Assert(!encoder.m_throwOnOverflow || !encoder.InternalHasFallbackBuffer || encoder.FallbackBuffer.Remaining == 0, "[ASCIICodePageEncoding.GetBytes]Expected empty fallback buffer");
  501.                 // if (encoder.m_throwOnOverflow && encoder.InternalHasFallbackBuffer &&
  502.                 // encoder.FallbackBuffer.Remaining > 0)
  503.                 // throw new ArgumentException(Environment.GetResourceString("Argument_EncoderFallbackNotEmpty",
  504.                 // this.EncodingName, encoder.Fallback.GetType()));
  505.             }
  506.             else {
  507.                 fallback = this.EncoderFallback as EncoderReplacementFallback;
  508.             }
  509.            
  510.            
  511.             // See if we do the fast default or slightly slower fallback
  512.             if (fallback != null && fallback.MaxCharCount == 1) {
  513.                 // Fast version
  514.                 char cReplacement = fallback.DefaultString[0];
  515.                
  516.                 // Check for replacements in range, otherwise fall back to slow version.
  517.                 if (cReplacement <= (char)127) {
  518.                     // We should have exactly as many output bytes as input bytes, unless there's a left
  519.                     // over character, in which case we may need one more.
  520.                     // If we had a left over character will have to add a ? (This happens if they had a funky
  521.                     // fallback last time, but not this time.) (We can't spit any out though
  522.                     // because with fallback encoder each surrogate is treated as a seperate code point)
  523.                     if (charLeftOver > 0) {
  524.                         // Have to have room
  525.                         // Throw even if doing no throw version because this is just 1 char,
  526.                         // so buffer will never be big enough
  527.                         if (byteCount == 0)
  528.                             ThrowBytesOverflow(encoder, true);
  529.                        
  530.                         // This'll make sure we still have more room and also make sure our return value is correct.
  531.                         *(bytes++) = (byte)cReplacement;
  532.                         byteCount--;
  533.                         // We used one of the ones we were counting.
  534.                     }
  535.                    
  536.                     // This keeps us from overrunning our output buffer
  537.                     if (byteCount < charCount) {
  538.                         // Throw or make buffer smaller?
  539.                         ThrowBytesOverflow(encoder, byteCount < 1);
  540.                        
  541.                         // Just use what we can
  542.                         charEnd = chars + byteCount;
  543.                     }
  544.                    
  545.                     // We just do a quick copy
  546.                     while (chars < charEnd) {
  547.                         char ch2 = *(chars++);
  548.                         if (ch2 >= 128)
  549.                             *(bytes++) = (byte)cReplacement;
  550.                         else
  551.                             *(bytes++) = unchecked((byte)(ch2));
  552.                     }
  553.                    
  554.                     // Clear encoder
  555.                     if (encoder != null) {
  556.                         encoder.charLeftOver = (char)0;
  557.                         encoder.m_charsUsed = (int)(chars - charStart);
  558.                     }
  559.                    
  560.                     return (int)(bytes - byteStart);
  561.                 }
  562.             }
  563.            
  564.             // Slower version, have to do real fallback.
  565.            
  566.             // prepare our end
  567.             byte* byteEnd = bytes + byteCount;
  568.            
  569.             // We may have a left over character from last time, try and process it.
  570.             if (charLeftOver > 0) {
  571.                 // Initialize the buffer
  572.                 BCLDebug.Assert(encoder != null, "[ASCIIEncoding.GetBytes]Expected non null encoder if we have surrogate left over");
  573.                 fallbackBuffer = encoder.FallbackBuffer;
  574.                 fallbackBuffer.InternalInitialize(chars, charEnd, encoder, true);
  575.                
  576.                 // Since left over char was a surrogate, it'll have to be fallen back.
  577.                 // Get Fallback
  578.                 // This will fallback a pair if *chars is a low surrogate
  579.                 fallbackBuffer.InternalFallback(charLeftOver, ref chars);
  580.             }
  581.            
  582.             // Now we may have fallback char[] already from the encoder
  583.            
  584.             // Go ahead and do it, including the fallback.
  585.             char ch;
  586.             while ((ch = (fallbackBuffer == null) ? '\0' : fallbackBuffer.InternalGetNextChar()) != 0 || chars < charEnd) {
  587.                 // First unwind any fallback
  588.                 if (ch == 0) {
  589.                     // No fallback, just get next char
  590.                     ch = *chars;
  591.                     chars++;
  592.                 }
  593.                
  594.                 // Check for fallback, this'll catch surrogate pairs too.
  595.                 // All characters >= 0x80 must fall back.
  596.                 if (ch > 127) {
  597.                     // Initialize the buffer
  598.                     if (fallbackBuffer == null) {
  599.                         if (encoder == null)
  600.                             fallbackBuffer = this.encoderFallback.CreateFallbackBuffer();
  601.                         else
  602.                             fallbackBuffer = encoder.FallbackBuffer;
  603.                         fallbackBuffer.InternalInitialize(charEnd - charCount, charEnd, encoder, true);
  604.                     }
  605.                    
  606.                     // Get Fallback
  607.                     fallbackBuffer.InternalFallback(ch, ref chars);
  608.                    
  609.                     // Go ahead & continue (& do the fallback)
  610.                     continue;
  611.                 }
  612.                
  613.                 // We'll use this one
  614.                 // Bounds check
  615.                 if (bytes >= byteEnd) {
  616.                     // didn't use this char, we'll throw or use buffer
  617.                     if (fallbackBuffer == null || fallbackBuffer.bFallingBack == false) {
  618.                         BCLDebug.Assert(chars > charStart || bytes == byteStart, "[ASCIIEncoding.GetBytes]Expected chars to have advanced already.");
  619.                         chars--;
  620.                         // don't use last char
  621.                     }
  622.                     else
  623.                         fallbackBuffer.MovePrevious();
  624.                    
  625.                     // Are we throwing or using buffer?
  626.                     ThrowBytesOverflow(encoder, bytes == byteStart);
  627.                     // throw?
  628.                     break;
  629.                     // don't throw, stop
  630.                 }
  631.                
  632.                 // Go ahead and add it
  633.                 *bytes = unchecked((byte)ch);
  634.                 bytes++;
  635.             }
  636.            
  637.             // Need to do encoder stuff
  638.             if (encoder != null) {
  639.                 // Fallback stuck it in encoder if necessary, but we have to clear MustFlush cases
  640.                 if (fallbackBuffer != null && !fallbackBuffer.bUsedEncoder)
  641.                     // Clear it in case of MustFlush
  642.                     encoder.charLeftOver = (char)0;
  643.                
  644.                 // Set our chars used count
  645.                 encoder.m_charsUsed = (int)(chars - charStart);
  646.             }
  647.            
  648.             BCLDebug.Assert(fallbackBuffer == null || fallbackBuffer.Remaining == 0 || (encoder != null && !encoder.m_throwOnOverflow), "[ASCIIEncoding.GetBytes]Expected Empty fallback buffer at end");
  649.            
  650.             return (int)(bytes - byteStart);
  651.         }
  652.        
  653.         // This is internal and called by something else,
  654.         unsafe internal override int GetCharCount(byte* bytes, int count, DecoderNLS decoder)
  655.         {
  656.             // Just assert, we're called internally so these should be safe, checked already
  657.             BCLDebug.Assert(bytes != null, "[ASCIIEncoding.GetCharCount]bytes is null");
  658.             BCLDebug.Assert(count >= 0, "[ASCIIEncoding.GetCharCount]byteCount is negative");
  659.            
  660.             // ASCII doesn't do best fit, so don't have to check for it, find out which decoder fallback we're using
  661.             DecoderReplacementFallback fallback = null;
  662.            
  663.             if (decoder == null)
  664.                 fallback = this.DecoderFallback as DecoderReplacementFallback;
  665.             else {
  666.                 fallback = decoder.Fallback as DecoderReplacementFallback;
  667.                 BCLDebug.Assert(!decoder.m_throwOnOverflow || !decoder.InternalHasFallbackBuffer || decoder.FallbackBuffer.Remaining == 0, "[ASCIICodePageEncoding.GetCharCount]Expected empty fallback buffer");
  668.             }
  669.            
  670.             if (fallback != null && fallback.MaxCharCount == 1) {
  671.                 // Just return length, SBCS stay the same length because they don't map to surrogate
  672.                 // pairs and we don't have a decoder fallback.
  673.                
  674.                 return count;
  675.             }
  676.            
  677.             // Only need decoder fallback buffer if not using default replacement fallback, no best fit for ASCII
  678.             DecoderFallbackBuffer fallbackBuffer = null;
  679.            
  680.             // Have to do it the hard way.
  681.             // Assume charCount will be == count
  682.             int charCount = count;
  683.             byte[] byteBuffer = new byte[1];
  684.            
  685.             // Do it our fast way
  686.             byte* byteEnd = bytes + count;
  687.            
  688.             // Quick loop
  689.             while (bytes < byteEnd) {
  690.                 // Faster if don't use *bytes++;
  691.                 byte b = *bytes;
  692.                 bytes++;
  693.                
  694.                 // If unknown we have to do fallback count
  695.                 if (b >= 128) {
  696.                     if (fallbackBuffer == null) {
  697.                         if (decoder == null)
  698.                             fallbackBuffer = this.DecoderFallback.CreateFallbackBuffer();
  699.                         else
  700.                             fallbackBuffer = decoder.FallbackBuffer;
  701.                         fallbackBuffer.InternalInitialize(byteEnd - count, null);
  702.                     }
  703.                    
  704.                     // Use fallback buffer
  705.                     byteBuffer[0] = b;
  706.                     charCount--;
  707.                     // Have to unreserve the one we already allocated for b
  708.                     charCount += fallbackBuffer.InternalFallback(byteBuffer, bytes);
  709.                 }
  710.             }
  711.            
  712.             // Fallback buffer must be empty
  713.             BCLDebug.Assert(fallbackBuffer == null || fallbackBuffer.Remaining == 0, "[ASCIIEncoding.GetCharCount]Expected Empty fallback buffer");
  714.            
  715.             // Converted sequence is same length as input
  716.             return charCount;
  717.         }
  718.        
  719.         unsafe internal override int GetChars(byte* bytes, int byteCount, char* chars, int charCount, DecoderNLS decoder)
  720.         {
  721.             // Just need to ASSERT, this is called by something else internal that checked parameters already
  722.             BCLDebug.Assert(bytes != null, "[ASCIIEncoding.GetChars]bytes is null");
  723.             BCLDebug.Assert(byteCount >= 0, "[ASCIIEncoding.GetChars]byteCount is negative");
  724.             BCLDebug.Assert(chars != null, "[ASCIIEncoding.GetChars]chars is null");
  725.             BCLDebug.Assert(charCount >= 0, "[ASCIIEncoding.GetChars]charCount is negative");
  726.            
  727.             // Do it fast way if using ? replacement fallback
  728.             byte* byteEnd = bytes + byteCount;
  729.             byte* byteStart = bytes;
  730.             char* charStart = chars;
  731.            
  732.             // Note: ASCII doesn't do best fit, but we have to fallback if they use something > 0x7f
  733.             // Only need decoder fallback buffer if not using ? fallback.
  734.             // ASCII doesn't do best fit, so don't have to check for it, find out which decoder fallback we're using
  735.             DecoderReplacementFallback fallback = null;
  736.            
  737.             if (decoder == null)
  738.                 fallback = this.DecoderFallback as DecoderReplacementFallback;
  739.             else {
  740.                 fallback = decoder.Fallback as DecoderReplacementFallback;
  741.                 BCLDebug.Assert(!decoder.m_throwOnOverflow || !decoder.InternalHasFallbackBuffer || decoder.FallbackBuffer.Remaining == 0, "[ASCIICodePageEncoding.GetChars]Expected empty fallback buffer");
  742.             }
  743.            
  744.             if (fallback != null && fallback.MaxCharCount == 1) {
  745.                 // Try it the fast way
  746.                 char replacementChar = fallback.DefaultString[0];
  747.                
  748.                 // Need byteCount chars, otherwise too small buffer
  749.                 if (charCount < byteCount) {
  750.                     // Need at least 1 output byte, throw if must throw
  751.                     ThrowCharsOverflow(decoder, charCount < 1);
  752.                    
  753.                     // Not throwing, use what we can
  754.                     byteEnd = bytes + charCount;
  755.                 }
  756.                
  757.                 // Quick loop, just do '?' replacement because we don't have fallbacks for decodings.
  758.                 while (bytes < byteEnd) {
  759.                     byte b = *(bytes++);
  760.                     if (b >= 128)
  761.                         *(chars++) = replacementChar;
  762.                     else
  763.                         // This is an invalid byte in the ASCII encoding.
  764.                         *(chars++) = unchecked((char)b);
  765.                 }
  766.                
  767.                 // bytes & chars used are the same
  768.                 if (decoder != null)
  769.                     decoder.m_bytesUsed = (int)(bytes - byteStart);
  770.                 return (int)(chars - charStart);
  771.             }
  772.            
  773.             // Slower way's going to need a fallback buffer
  774.             DecoderFallbackBuffer fallbackBuffer = null;
  775.             byte[] byteBuffer = new byte[1];
  776.             char* charEnd = chars + charCount;
  777.            
  778.             // Not quite so fast loop
  779.             while (bytes < byteEnd) {
  780.                 // Faster if don't use *bytes++;
  781.                 byte b = *(bytes);
  782.                 bytes++;
  783.                
  784.                 if (b >= 128) {
  785.                     // This is an invalid byte in the ASCII encoding.
  786.                     if (fallbackBuffer == null) {
  787.                         if (decoder == null)
  788.                             fallbackBuffer = this.DecoderFallback.CreateFallbackBuffer();
  789.                         else
  790.                             fallbackBuffer = decoder.FallbackBuffer;
  791.                         fallbackBuffer.InternalInitialize(byteEnd - byteCount, charEnd);
  792.                     }
  793.                    
  794.                     // Use fallback buffer
  795.                     byteBuffer[0] = b;
  796.                    
  797.                     // Note that chars won't get updated unless this succeeds
  798.                     if (!fallbackBuffer.InternalFallback(byteBuffer, bytes, ref chars)) {
  799.                         // May or may not throw, but we didn't get this byte
  800.                         BCLDebug.Assert(bytes > byteStart || chars == charStart, "[ASCIIEncoding.GetChars]Expected bytes to have advanced already (fallback case)");
  801.                         bytes--;
  802.                         // unused byte
  803.                         fallbackBuffer.InternalReset();
  804.                         // Didn't fall this back
  805.                         ThrowCharsOverflow(decoder, chars == charStart);
  806.                         // throw?
  807.                         break;
  808.                         // don't throw, but stop loop
  809.                     }
  810.                 }
  811.                 else {
  812.                     // Make sure we have buffer space
  813.                     if (chars >= charEnd) {
  814.                         BCLDebug.Assert(bytes > byteStart || chars == charStart, "[ASCIIEncoding.GetChars]Expected bytes to have advanced already (normal case)");
  815.                         bytes--;
  816.                         // unused byte
  817.                         ThrowCharsOverflow(decoder, chars == charStart);
  818.                         // throw?
  819.                         break;
  820.                         // don't throw, but stop loop
  821.                     }
  822.                    
  823.                     *(chars) = unchecked((char)b);
  824.                     chars++;
  825.                 }
  826.             }
  827.            
  828.             // Might have had decoder fallback stuff.
  829.             if (decoder != null)
  830.                 decoder.m_bytesUsed = (int)(bytes - byteStart);
  831.            
  832.             // Expect Empty fallback buffer for GetChars
  833.             BCLDebug.Assert(fallbackBuffer == null || fallbackBuffer.Remaining == 0, "[ASCIIEncoding.GetChars]Expected Empty fallback buffer");
  834.            
  835.             return (int)(chars - charStart);
  836.         }
  837.        
  838.        
  839.         public override int GetMaxByteCount(int charCount)
  840.         {
  841.             if (charCount < 0)
  842.                 throw new ArgumentOutOfRangeException("charCount", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
  843.            
  844.             // Characters would be # of characters + 1 in case high surrogate is ? * max fallback
  845.             long byteCount = (long)charCount + 1;
  846.            
  847.             if (EncoderFallback.MaxCharCount > 1)
  848.                 byteCount *= EncoderFallback.MaxCharCount;
  849.            
  850.             // 1 to 1 for most characters. Only surrogates with fallbacks have less.
  851.            
  852.             if (byteCount > 2147483647)
  853.                 throw new ArgumentOutOfRangeException("charCount", Environment.GetResourceString("ArgumentOutOfRange_GetByteCountOverflow"));
  854.             return (int)byteCount;
  855.         }
  856.        
  857.        
  858.         public override int GetMaxCharCount(int byteCount)
  859.         {
  860.             if (byteCount < 0)
  861.                 throw new ArgumentOutOfRangeException("byteCount", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
  862.            
  863.             // Just return length, SBCS stay the same length because they don't map to surrogate
  864.             long charCount = (long)byteCount;
  865.            
  866.             // 1 to 1 for most characters. Only surrogates with fallbacks have less, unknown fallbacks could be longer.
  867.             if (DecoderFallback.MaxCharCount > 1)
  868.                 charCount *= DecoderFallback.MaxCharCount;
  869.            
  870.             if (charCount > 2147483647)
  871.                 throw new ArgumentOutOfRangeException("byteCount", Environment.GetResourceString("ArgumentOutOfRange_GetCharCountOverflow"));
  872.            
  873.             return (int)charCount;
  874.         }
  875.        
  876.         // True if and only if the encoding only uses single byte code points. (Ie, ASCII, 1252, etc)
  877.        
  878.         [System.Runtime.InteropServices.ComVisible(false)]
  879.         public override bool IsSingleByte {
  880.             get { return true; }
  881.         }
  882.        
  883.         [System.Runtime.InteropServices.ComVisible(false)]
  884.         public override Decoder GetDecoder()
  885.         {
  886.             return new DecoderNLS(this);
  887.         }
  888.        
  889.        
  890.         [System.Runtime.InteropServices.ComVisible(false)]
  891.         public override Encoder GetEncoder()
  892.         {
  893.             return new EncoderNLS(this);
  894.         }
  895.     }
  896. }

Developer Fusion