The Labs \ Source Viewer \ SSCLI \ System.Xml.Serialization \ CodeIdentifier

  1. //------------------------------------------------------------------------------
  2. // <copyright file="CodeIdentifier.cs" company="Microsoft">
  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. // </copyright>
  14. // <owner current="true" primary="true">ElenaK</owner>
  15. //------------------------------------------------------------------------------
  16. namespace System.Xml.Serialization
  17. {
  18.    
  19.     using System;
  20.     using System.Text;
  21.     using System.Collections;
  22.     using System.IO;
  23.     using System.Globalization;
  24.     using System.Diagnostics;
  25.     using System.CodeDom;
  26.     using System.CodeDom.Compiler;
  27.     using Microsoft.CSharp;
  28.    
  29.     /// <include file='doc\CodeIdentifier.uex' path='docs/doc[@for="CodeIdentifier"]/*' />
  30.     ///<internalonly/>
  31.     /// <devdoc>
  32.     /// <para>[To be supplied.]</para>
  33.     /// </devdoc>
  34.     public class CodeIdentifier
  35.     {
  36.         static internal CodeDomProvider csharp = new CSharpCodeProvider();
  37.         internal const int MaxIdentifierLength = 511;
  38.        
  39.         [Obsolete("This class should never get constructed as it contains only static methods.")]
  40.         public CodeIdentifier()
  41.         {
  42.         }
  43.        
  44.         /// <include file='doc\CodeIdentifier.uex' path='docs/doc[@for="CodeIdentifier.MakePascal"]/*' />
  45.         /// <devdoc>
  46.         /// <para>[To be supplied.]</para>
  47.         /// </devdoc>
  48.         public static string MakePascal(string identifier)
  49.         {
  50.             identifier = MakeValid(identifier);
  51.             if (identifier.Length <= 2)
  52.                 return identifier.ToUpper(CultureInfo.InvariantCulture);
  53.             else if (char.IsLower(identifier[0]))
  54.                 return char.ToUpper(identifier[0], CultureInfo.InvariantCulture).ToString(CultureInfo.InvariantCulture) + identifier.Substring(1);
  55.             else
  56.                 return identifier;
  57.         }
  58.        
  59.         /// <include file='doc\CodeIdentifier.uex' path='docs/doc[@for="CodeIdentifier.MakeCamel"]/*' />
  60.         /// <devdoc>
  61.         /// <para>[To be supplied.]</para>
  62.         /// </devdoc>
  63.         public static string MakeCamel(string identifier)
  64.         {
  65.             identifier = MakeValid(identifier);
  66.             if (identifier.Length <= 2)
  67.                 return identifier.ToLower(CultureInfo.InvariantCulture);
  68.             else if (char.IsUpper(identifier[0]))
  69.                 return char.ToLower(identifier[0], CultureInfo.InvariantCulture).ToString(CultureInfo.InvariantCulture) + identifier.Substring(1);
  70.             else
  71.                 return identifier;
  72.         }
  73.        
  74.         /// <include file='doc\CodeIdentifier.uex' path='docs/doc[@for="CodeIdentifier.MakeValid"]/*' />
  75.         /// <devdoc>
  76.         /// <para>[To be supplied.]</para>
  77.         /// </devdoc>
  78.         public static string MakeValid(string identifier)
  79.         {
  80.             StringBuilder builder = new StringBuilder();
  81.             for (int i = 0; i < identifier.Length && builder.Length < MaxIdentifierLength; i++) {
  82.                 char c = identifier[i];
  83.                 if (IsValid(c)) {
  84.                     if (builder.Length == 0 && !IsValidStart(c)) {
  85.                         builder.Append("Item");
  86.                     }
  87.                     builder.Append(c);
  88.                 }
  89.             }
  90.             if (builder.Length == 0)
  91.                 return "Item";
  92.             return builder.ToString();
  93.         }
  94.        
  95.         static internal string MakeValidInternal(string identifier)
  96.         {
  97.             if (identifier.Length > 30) {
  98.                 return "Item";
  99.             }
  100.             return MakeValid(identifier);
  101.         }
  102.        
  103.         static bool IsValidStart(char c)
  104.         {
  105.            
  106.             // the given char is already a valid name character
  107.             #if DEBUG
  108.             // use exception in the place of Debug.Assert to avoid throwing asserts from a server process such as aspnet_ewp.exe
  109.             if (!IsValid(c))
  110.                 throw new ArgumentException(Res.GetString(Res.XmlInternalErrorDetails, "Invalid identifier character " + ((Int16)c).ToString(CultureInfo.InvariantCulture)), "c");
  111.             #endif
  112.            
  113.             // First char cannot be a number
  114.             if (Char.GetUnicodeCategory(c) == UnicodeCategory.DecimalDigitNumber)
  115.                 return false;
  116.             return true;
  117.         }
  118.        
  119.         static bool IsValid(char c)
  120.         {
  121.             UnicodeCategory uc = Char.GetUnicodeCategory(c);
  122.             // each char must be Lu, Ll, Lt, Lm, Lo, Nd, Mn, Mc, Pc
  123.             //
  124.             switch (uc) {
  125.                 case UnicodeCategory.UppercaseLetter:
  126.                 case UnicodeCategory.LowercaseLetter:
  127.                 case UnicodeCategory.TitlecaseLetter:
  128.                 case UnicodeCategory.ModifierLetter:
  129.                 case UnicodeCategory.OtherLetter:
  130.                 case UnicodeCategory.DecimalDigitNumber:
  131.                 case UnicodeCategory.NonSpacingMark:
  132.                 case UnicodeCategory.SpacingCombiningMark:
  133.                 case UnicodeCategory.ConnectorPunctuation:
  134.                     // Lu
  135.                     // Ll
  136.                     // Lt
  137.                     // Lm
  138.                     // Lo
  139.                     // Nd
  140.                     // Mn
  141.                     // Mc
  142.                     // Pc
  143.                     break;
  144.                 case UnicodeCategory.LetterNumber:
  145.                 case UnicodeCategory.OtherNumber:
  146.                 case UnicodeCategory.EnclosingMark:
  147.                 case UnicodeCategory.SpaceSeparator:
  148.                 case UnicodeCategory.LineSeparator:
  149.                 case UnicodeCategory.ParagraphSeparator:
  150.                 case UnicodeCategory.Control:
  151.                 case UnicodeCategory.Format:
  152.                 case UnicodeCategory.Surrogate:
  153.                 case UnicodeCategory.PrivateUse:
  154.                 case UnicodeCategory.DashPunctuation:
  155.                 case UnicodeCategory.OpenPunctuation:
  156.                 case UnicodeCategory.ClosePunctuation:
  157.                 case UnicodeCategory.InitialQuotePunctuation:
  158.                 case UnicodeCategory.FinalQuotePunctuation:
  159.                 case UnicodeCategory.OtherPunctuation:
  160.                 case UnicodeCategory.MathSymbol:
  161.                 case UnicodeCategory.CurrencySymbol:
  162.                 case UnicodeCategory.ModifierSymbol:
  163.                 case UnicodeCategory.OtherSymbol:
  164.                 case UnicodeCategory.OtherNotAssigned:
  165.                     return false;
  166.                 default:
  167.                     #if DEBUG
  168.                     // use exception in the place of Debug.Assert to avoid throwing asserts from a server process such as aspnet_ewp.exe
  169.                     throw new ArgumentException(Res.GetString(Res.XmlInternalErrorDetails, "Unhandled category " + uc), "c");
  170.                     #else
  171.                     return false;
  172.                 #endif
  173.             }
  174.             return true;
  175.         }
  176.        
  177.         static internal void CheckValidIdentifier(string ident)
  178.         {
  179.             if (!CodeGenerator.IsValidLanguageIndependentIdentifier(ident))
  180.                 throw new ArgumentException(Res.GetString(Res.XmlInvalidIdentifier, ident), "ident");
  181.         }
  182.        
  183.         static internal string GetCSharpName(string name)
  184.         {
  185.             return EscapeKeywords(name.Replace('+', '.'), csharp);
  186.         }
  187.        
  188.         static int GetCSharpName(Type t, Type[] parameters, int index, StringBuilder sb)
  189.         {
  190.             if (t.DeclaringType != null && t.DeclaringType != t) {
  191.                 index = GetCSharpName(t.DeclaringType, parameters, index, sb);
  192.                 sb.Append(".");
  193.             }
  194.             string name = t.Name;
  195.             int nameEnd = name.IndexOf('`');
  196.             if (nameEnd < 0) {
  197.                 nameEnd = name.IndexOf('!');
  198.             }
  199.             if (nameEnd > 0) {
  200.                 EscapeKeywords(name.Substring(0, nameEnd), csharp, sb);
  201.                 sb.Append("<");
  202.                 int arguments = Int32.Parse(name.Substring(nameEnd + 1), CultureInfo.InvariantCulture) + index;
  203.                 for (; index < arguments; index++) {
  204.                     sb.Append(GetCSharpName(parameters[index]));
  205.                     if (index < arguments - 1) {
  206.                         sb.Append(",");
  207.                     }
  208.                 }
  209.                 sb.Append(">");
  210.             }
  211.             else {
  212.                 EscapeKeywords(name, csharp, sb);
  213.             }
  214.             return index;
  215.         }
  216.        
  217.         static internal string GetCSharpName(Type t)
  218.         {
  219.             int rank = 0;
  220.             while (t.IsArray) {
  221.                 t = t.GetElementType();
  222.                 rank++;
  223.             }
  224.             StringBuilder sb = new StringBuilder();
  225.             sb.Append("global::");
  226.             string ns = t.Namespace;
  227.             if (ns != null && ns.Length > 0) {
  228.                 string[] parts = ns.Split(new char[] {'.'});
  229.                 for (int i = 0; i < parts.Length; i++) {
  230.                     EscapeKeywords(parts[i], csharp, sb);
  231.                     sb.Append(".");
  232.                 }
  233.             }
  234.            
  235.             Type[] arguments = t.IsGenericType || t.ContainsGenericParameters ? t.GetGenericArguments() : new Type[0];
  236.             GetCSharpName(t, arguments, 0, sb);
  237.             for (int i = 0; i < rank; i++) {
  238.                 sb.Append("[]");
  239.             }
  240.             return sb.ToString();
  241.         }
  242.        
  243. /*
  244.         internal static string GetTypeName(string name, CodeDomProvider codeProvider) {
  245.             return codeProvider.GetTypeOutput(new CodeTypeReference(name));
  246.         }
  247.         */       
  248.        
  249.         static void EscapeKeywords(string identifier, CodeDomProvider codeProvider, StringBuilder sb)
  250.         {
  251.             if (identifier == null || identifier.Length == 0)
  252.                 return;
  253.             string originalIdentifier = identifier;
  254.             int arrayCount = 0;
  255.             while (identifier.EndsWith("[]", StringComparison.Ordinal)) {
  256.                 arrayCount++;
  257.                 identifier = identifier.Substring(0, identifier.Length - 2);
  258.             }
  259.             if (identifier.Length > 0) {
  260.                 CheckValidIdentifier(identifier);
  261.                 identifier = codeProvider.CreateEscapedIdentifier(identifier);
  262.                 sb.Append(identifier);
  263.             }
  264.             for (int i = 0; i < arrayCount; i++) {
  265.                 sb.Append("[]");
  266.             }
  267.         }
  268.        
  269.         static string EscapeKeywords(string identifier, CodeDomProvider codeProvider)
  270.         {
  271.             if (identifier == null || identifier.Length == 0)
  272.                 return identifier;
  273.             string originalIdentifier = identifier;
  274.             string[] names = identifier.Split(new char[] {'.', ',', '<', '>'});
  275.             StringBuilder sb = new StringBuilder();
  276.             int separator = -1;
  277.             for (int i = 0; i < names.Length; i++) {
  278.                 if (separator >= 0) {
  279.                     sb.Append(originalIdentifier.Substring(separator, 1));
  280.                 }
  281.                 separator++;
  282.                 separator += names[i].Length;
  283.                 string escapedName = names[i].Trim();
  284.                 EscapeKeywords(escapedName, codeProvider, sb);
  285.             }
  286.             if (sb.Length != originalIdentifier.Length)
  287.                 return sb.ToString();
  288.             return originalIdentifier;
  289.         }
  290.     }
  291. }

Developer Fusion