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

  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. using System;
  17. using System.Threading;
  18. using System.Globalization;
  19. namespace System.Text
  20. {
  21.     [Serializable()]
  22.     public abstract class DecoderFallback
  23.     {
  24.         internal bool bIsMicrosoftBestFitFallback = false;
  25.        
  26.         private static DecoderFallback replacementFallback;
  27.         // Default fallback, uses no best fit & "?"
  28.         private static DecoderFallback exceptionFallback;
  29.        
  30.         // Private object for locking instead of locking on a internal type for SQL reliability work.
  31.         private static object s_InternalSyncObject;
  32.         private static object InternalSyncObject {
  33.             get {
  34.                 if (s_InternalSyncObject == null) {
  35.                     object o = new object();
  36.                     Interlocked.CompareExchange(ref s_InternalSyncObject, o, null);
  37.                 }
  38.                 return s_InternalSyncObject;
  39.             }
  40.         }
  41.        
  42.         // Get each of our generic fallbacks.
  43.        
  44.         public static DecoderFallback ReplacementFallback {
  45.             get {
  46.                 if (replacementFallback == null)
  47.                     lock (InternalSyncObject)
  48.                         if (replacementFallback == null)
  49.                             replacementFallback = new DecoderReplacementFallback();
  50.                
  51.                 return replacementFallback;
  52.             }
  53.         }
  54.        
  55.        
  56.         public static DecoderFallback ExceptionFallback {
  57.             get {
  58.                 if (exceptionFallback == null)
  59.                     lock (InternalSyncObject)
  60.                         if (exceptionFallback == null)
  61.                             exceptionFallback = new DecoderExceptionFallback();
  62.                
  63.                 return exceptionFallback;
  64.             }
  65.         }
  66.        
  67.         // Fallback
  68.         //
  69.         // Return the appropriate unicode string alternative to the character that need to fall back.
  70.         // Most implimentations will be:
  71.         // return new MyCustomDecoderFallbackBuffer(this);
  72.        
  73.         public abstract DecoderFallbackBuffer CreateFallbackBuffer();
  74.        
  75.         // Maximum number of characters that this instance of this fallback could return
  76.        
  77.         public abstract int MaxCharCount {
  78.             get;
  79.         }
  80.        
  81.         internal bool IsMicrosoftBestFitFallback {
  82.             get { return bIsMicrosoftBestFitFallback; }
  83.         }
  84.     }
  85.    
  86.    
  87.     public abstract class DecoderFallbackBuffer
  88.     {
  89.        
  90.        
  91.         public abstract bool Fallback(byte[] bytesUnknown, int index);
  92.        
  93.         // Get next character
  94.        
  95.         public abstract char GetNextChar();
  96.        
  97.         // Back up a character
  98.        
  99.         public abstract bool MovePrevious();
  100.        
  101.         // How many chars left in this fallback?
  102.        
  103.         public abstract int Remaining {
  104.             get;
  105.         }
  106.        
  107.         // Clear the buffer
  108.        
  109.         public virtual void Reset()
  110.         {
  111.             while (GetNextChar() != (char)0)
  112.                 ;
  113.         }
  114.        
  115.         // Internal items to help us figure out what we're doing as far as error messages, etc.
  116.         // These help us with our performance and messages internally
  117.         unsafe internal byte* byteStart = null;
  118.         unsafe internal char* charEnd = null;
  119.        
  120.         // Internal Reset
  121.         unsafe internal void InternalReset()
  122.         {
  123.             byteStart = null;
  124.             Reset();
  125.         }
  126.        
  127.         // Set the above values
  128.         // This can't be part of the constructor because DecoderFallbacks would have to know how to impliment these.
  129.         unsafe internal void InternalInitialize(byte* byteStart, char* charEnd)
  130.         {
  131.             this.byteStart = byteStart;
  132.             this.charEnd = charEnd;
  133.         }
  134.        
  135.         unsafe internal virtual bool InternalFallback(byte[] bytes, byte* pBytes, ref char* chars)
  136.         {
  137.             // Copy bytes to array (slow, but right now that's what we get to do.
  138.             // byte[] bytesUnknown = new byte[count];
  139.             // for (int i = 0; i < count; i++)
  140.             // bytesUnknown[i] = *(bytes++);
  141.            
  142.             BCLDebug.Assert(byteStart != null, "[DecoderFallback.InternalFallback]Used InternalFallback without calling InternalInitialize");
  143.            
  144.             // See if there's a fallback character and we have an output buffer then copy our string.
  145.             if (this.Fallback(bytes, (int)(pBytes - byteStart - bytes.Length))) {
  146.                 // Copy the chars to our output
  147.                 char ch;
  148.                 char* charTemp = chars;
  149.                 bool bHighSurrogate = false;
  150.                 while ((ch = GetNextChar()) != 0) {
  151.                     // Make sure no mixed up surrogates
  152.                     if (Char.IsSurrogate(ch)) {
  153.                         if (Char.IsHighSurrogate(ch)) {
  154.                             // High Surrogate
  155.                             if (bHighSurrogate)
  156.                                 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidCharSequenceNoIndex"));
  157.                             bHighSurrogate = true;
  158.                         }
  159.                         else {
  160.                             // Low surrogate
  161.                             if (bHighSurrogate == false)
  162.                                 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidCharSequenceNoIndex"));
  163.                             bHighSurrogate = false;
  164.                         }
  165.                     }
  166.                    
  167.                     if (charTemp >= charEnd) {
  168.                         // No buffer space
  169.                         return false;
  170.                     }
  171.                    
  172.                     *(charTemp++) = ch;
  173.                 }
  174.                
  175.                 // Need to make sure that bHighSurrogate isn't true
  176.                 if (bHighSurrogate)
  177.                     throw new ArgumentException(Environment.GetResourceString("Argument_InvalidCharSequenceNoIndex"));
  178.                
  179.                 // Now we aren't going to be false, so its OK to update chars
  180.                 chars = charTemp;
  181.             }
  182.            
  183.             return true;
  184.         }
  185.        
  186.         // This version just counts the fallback and doesn't actually copy anything.
  187.         unsafe internal virtual int InternalFallback(byte[] bytes, byte* pBytes)
  188.         {
  189.             // Copy bytes to array (slow, but right now that's what we get to do.
  190.             // byte[] bytesUnknown = new byte[count];
  191.             // for (int i = 0; i < count; i++)
  192.             // bytesUnknown[i] = *(bytes++);
  193.            
  194.             BCLDebug.Assert(byteStart != null, "[DecoderFallback.InternalFallback]Used InternalFallback without calling InternalInitialize");
  195.            
  196.             // See if there's a fallback character and we have an output buffer then copy our string.
  197.             if (this.Fallback(bytes, (int)(pBytes - byteStart - bytes.Length))) {
  198.                 int count = 0;
  199.                
  200.                 char ch;
  201.                 bool bHighSurrogate = false;
  202.                 while ((ch = GetNextChar()) != 0) {
  203.                     // Make sure no mixed up surrogates
  204.                     if (Char.IsSurrogate(ch)) {
  205.                         if (Char.IsHighSurrogate(ch)) {
  206.                             // High Surrogate
  207.                             if (bHighSurrogate)
  208.                                 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidCharSequenceNoIndex"));
  209.                             bHighSurrogate = true;
  210.                         }
  211.                         else {
  212.                             // Low surrogate
  213.                             if (bHighSurrogate == false)
  214.                                 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidCharSequenceNoIndex"));
  215.                             bHighSurrogate = false;
  216.                         }
  217.                     }
  218.                    
  219.                     count++;
  220.                 }
  221.                
  222.                 // Need to make sure that bHighSurrogate isn't true
  223.                 if (bHighSurrogate)
  224.                     throw new ArgumentException(Environment.GetResourceString("Argument_InvalidCharSequenceNoIndex"));
  225.                
  226.                 return count;
  227.             }
  228.            
  229.             // If no fallback return 0
  230.             return 0;
  231.         }
  232.        
  233.         // private helper methods
  234.         internal void ThrowLastBytesRecursive(byte[] bytesUnknown)
  235.         {
  236.             // Create a string representation of our bytes.
  237.             StringBuilder strBytes = new StringBuilder(bytesUnknown.Length * 3);
  238.             int i;
  239.             for (i = 0; i < bytesUnknown.Length && i < 20; i++) {
  240.                 if (strBytes.Length > 0)
  241.                     strBytes.Append(" ");
  242.                 strBytes.Append(String.Format(CultureInfo.InvariantCulture, "\\x{0:X2}", bytesUnknown[i]));
  243.             }
  244.             // In case the string's really long
  245.             if (i == 20)
  246.                 strBytes.Append(" ...");
  247.            
  248.             // Throw it, using our complete bytes
  249.             throw new ArgumentException(Environment.GetResourceString("Argument_RecursiveFallbackBytes", strBytes.ToString()), "bytesUnknown");
  250.         }
  251.        
  252.     }
  253. }

Developer Fusion