context: //---------------------------------------------------------------------------
  //
  // Copyright (c) Microsoft Corporation.  All rights reserved.
  // 
  // Description: BamlLocalizabilityResolver class
  //              It resolves localizabilities of a class/element 
  //
  //---------------------------------------------------------------------------
  
  using System;
  using System.Windows;
  using System.Windows.Markup.Localizer;
  using System.Diagnostics;
  using System.Globalization;
  using System.Reflection;
  using System.Collections.Generic;
  using System.Security.Permissions;
  
  namespace TranslationApi.Baml
  {
      /// <summary>
      /// </summary>
      public class BamlLocalizabilityByReflection : BamlLocalizabilityResolver
      {
  
          //---------------------------
          // private members
          //---------------------------     
          private Dictionary<string, Assembly> __Assemblies;   // the _assemblies table
          private Dictionary<string, Type> __TypeCache;    // the types cache
  
          // well know assembly names, keep them sorted.
          private static readonly string[] __WellKnownAssemblyNames = new string[] { 
                  "presentationcore", 
                  "presentationframework",
                  "windowsbase"
               };
  
          // the well known assemblies
          private static Assembly[] __WellKnownAssemblies = new Assembly[__WellKnownAssemblyNames.Length];
  
          private static Type TypeOfLocalizabilityAttribute = typeof(LocalizabilityAttribute);
  
          // supported elements that are formatted inline		
          private static string[] FormattedElements = new string[]{
              "System.Windows.Documents.Bold",
              "System.Windows.Documents.Hyperlink", 
              "System.Windows.Documents.Inline", 
              "System.Windows.Documents.Italic", 
              "System.Windows.Documents.SmallCaps", 
              "System.Windows.Documents.Subscript", 
              "System.Windows.Documents.Superscript", 
              "System.Windows.Documents.Underline"
              };
  
          // corresponding tag
          private static string[] FormattingTag = new string[] {
              "b",
              "a",
              "in", 
              "i",
              "small",
              "sub",
              "sup",
              "u"
              };
  
  
          /// Take in an optional list of assemblies in addition to the 
          /// default well-known WPF assemblies. The assemblies will be searched first
          /// in order before the well-known WPF assemblies.
          /// </summary>
          /// <param name="assemblies">additinal list of assemblies to search for Type information</param>
          public BamlLocalizabilityByReflection(Assembly[] assemblies)
          {
              if (assemblies != null)
              {
                  // create the table
                  __Assemblies = new Dictionary<string, Assembly>(assemblies.Length);
  
                  try
                  {                    
                      // Assert security permissions
                      FileIOPermission permobj = new FileIOPermission(PermissionState.None);
                      permobj.AllFiles = FileIOPermissionAccess.PathDiscovery;
  
                      //CASRemoval:permobj.Assert();
                      
                      for (int i = 0; i < assemblies.Length; i++)
                      {
                          // skip the null ones. 
                          if (assemblies[i] != null)
                          {
                              // index it by the name;
                              __Assemblies[assemblies[i].GetName().FullName] = assemblies[i];
                          }
                      }
                  }
                  finally
                  {
                     // revert assert permission
                     //CASRemoval:FileIOPermission.RevertAssert();
                  }
              }           
  
              // create the cache for Type here
              __TypeCache = new Dictionary<string, Type>(32);
          }        
  
          /// <summary>
          /// Return the localizability of an element to the BamlLocalizer
          /// </summary>
          public override ElementLocalizability GetElementLocalizability(
              string assembly,
              string className
              )
          {
              ElementLocalizability loc = new ElementLocalizability();
  
              Type type = GetType(assembly, className);            
              if (type != null)
              {
                  // We found the type, now try to get the localizability attribte from the type
                  loc.Attribute = GetLocalizabilityFromType(type);
              }            
              
              // fill in the formatting tag
              int index = Array.IndexOf(FormattedElements, className);
              if (index >= 0)
              {
                  loc.FormattingTag = FormattingTag[index];
              }
  
              return loc;
          }
  
          /// <summary>
          /// return localizability of a property to the BamlLocalizer
          /// </summary>
          public override LocalizabilityAttribute GetPropertyLocalizability(
              string assembly,
              string className,
              string property           
              )
          {
              LocalizabilityAttribute attribute = null;
  
              Type type =  GetType(assembly, className);
           
              if (type != null)
              {
                  // type of the property. The type can be retrieved from CLR property, or Attached property.
                  Type clrPropertyType = null, attachedPropertyType = null;     
                      
                  // we found the type. try to get to the property as Clr property                    
                  GetLocalizabilityForClrProperty(
                      property, 
                      type,
                      out attribute,
                      out clrPropertyType
                      );
  
                  if (attribute == null)
                  {
                      // we didn't find localizability as a Clr property on the type,
                      // try to get the property as attached property
                      GetLocalizabilityForAttachedProperty(
                              property, 
                              type,
                              out attribute,
                              out attachedPropertyType
                              );
                  }
  
                  if (attribute == null)
                  {
                      // if attached property doesn't have [LocalizabilityAttribute] defined,
                      // we get it from the type of the property.
                      attribute =(clrPropertyType != null) ?
                            GetLocalizabilityFromType(clrPropertyType)
                          : GetLocalizabilityFromType(attachedPropertyType);
                  }
              }
  
              return attribute;
          }
  
          /// <summary>
          /// Resolve a formatting tag back to the actual class name
          /// </summary>
          public override string ResolveFormattingTagToClass(
              string formattingTag
              )
          {
              int index = Array.IndexOf(FormattingTag, formattingTag);
              if (index >= 0)
                  return FormattedElements[index];
              else
                  return null;   
          }
  
          /// <summary>
          /// Resolve a class name back to its containing assembly 
          /// </summary>
          public override string ResolveAssemblyFromClass(
              string className
              )
          {
              // search through the well-known assemblies
              for (int i = 0; i < __WellKnownAssemblies.Length; i++)
              {
                  if (__WellKnownAssemblies[i] == null)
                  {
                      __WellKnownAssemblies[i] = Assembly.Load(
                          GetCompatibleAssemblyName(__WellKnownAssemblyNames[i])
                          );
                  }
  
                  if (__WellKnownAssemblies[i] != null && __WellKnownAssemblies[i].GetType(className) != null)
                  {
                      return __WellKnownAssemblies[i].GetName().FullName;
                  }
              }
  
              // search through the custom assemblies
              if (__Assemblies != null)
              {
                  foreach (KeyValuePair<string, Assembly> pair in __Assemblies)
                  {
                      if (pair.Value.GetType(className) != null)
                      {
                          return pair.Value.GetName().FullName;
                      }
                  }
              }
  
              return null;
          }
  
          //-----------------------------------------------
          // Private methods
          //-----------------------------------------------
          // get the type in a specified assembly
          private Type GetType(string assemblyName, string className)
          {
              Debug.Assert(className != null, "classname can't be null");
              Debug.Assert(assemblyName != null, "Assembly name can't be null");
  
              // combine assembly name and class name for unique indexing
              string fullName = assemblyName + ":" + className;
              Type type;
  
              if (__TypeCache.ContainsKey(fullName))
              {
                  // we found it in the cache, so just return
                  return __TypeCache[fullName];
              }            
  
              // we didn't find it in the table. So let's get to the assembly first
              Assembly assembly = null;
              if (__Assemblies != null && __Assemblies.ContainsKey(assemblyName))
              {
                  // find the assembly in the hash table first
                  assembly = __Assemblies[assemblyName];
              }
  
              if (assembly == null)
              {
                  // we don't find the assembly in the hashtable
                  // try to use the default well known assemblies
                  int index;                
                  if ( (index = Array.BinarySearch(
                           __WellKnownAssemblyNames, 
                           GetAssemblyShortName(assemblyName).ToLower(CultureInfo.InvariantCulture)
                           )
                        ) >= 0
                     )
                  {
                      // see if we already loaded the assembly
                      if (__WellKnownAssemblies[index] == null)
                      {
                          // it is a well known name, load it from the gac
                          __WellKnownAssemblies[index] = Assembly.Load(assemblyName);
                      }         
                      
                      assembly = __WellKnownAssemblies[index];                                                            
                  }                
              }
  
              if (assembly != null) 
              {
                  // So, we found the assembly. Now get the type from the assembly
                  type = assembly.GetType(className);   
              }
              else
              {
                  // Couldn't find the assembly. We will try to load it
                  type = null;
              }
  
              // remember what we found out.
              __TypeCache[fullName] = type;
              return type;    // return
          }
  
          // returns the short name for the assembly
          private static string GetAssemblyShortName(string assemblyFullName)
          {
              int commaIndex = assemblyFullName.IndexOf(',');
              if (commaIndex > 0)
              {
                  return assemblyFullName.Substring(0, commaIndex);
              }
  
              return assemblyFullName;
          }    
  
          private static string GetCompatibleAssemblyName(string shortName)
          {
              AssemblyName asmName = null;
              for (int i = 0; i < __WellKnownAssemblies.Length; i++)
              {                
                  if (__WellKnownAssemblies[i] != null)
                  {
                      // create an assembly name with the same version and token info
                      // as the WPF assembilies
                      asmName = __WellKnownAssemblies[i].GetName();
                      asmName.Name = shortName;
                      break;
                  }
              }
  
              if (asmName == null)
              {
                  // there is no WPF assembly loaded yet. We will just get the compatible version 
                  // of the current PresentationFramework
                  Assembly presentationFramework = typeof(BamlLocalizer).Assembly;
                  asmName = presentationFramework.GetName();
                  asmName.Name = shortName;                
              }
  
              return asmName.ToString();
          }       
  
          /// <summary>
          /// gets the localizabiity attribute of a given the type
          /// </summary>        
          private LocalizabilityAttribute GetLocalizabilityFromType(Type type)
          {                 
             if (type == null) return null;
             
             // let's get to its localizability attribute.
             object[] locAttributes = type.GetCustomAttributes(
                 TypeOfLocalizabilityAttribute, // type of localizability
                 true                           // search for inherited value
                 );
                      
             if (locAttributes.Length == 0)
             {
                 return DefaultAttributes.GetDefaultAttribute(type);
             }                    
             else                
             {
                 Debug.Assert(locAttributes.Length == 1, "Should have only 1 localizability attribute");
                     
                 // use the one defined on the class
                 return (LocalizabilityAttribute) locAttributes[0];
             }         
                 
          }
  
          /// <summary>
          /// Get the localizability of a CLR property
          /// </summary>
          private void GetLocalizabilityForClrProperty(
              string                      propertyName, 
              Type                        owner,
              out LocalizabilityAttribute localizability,
              out Type                    propertyType
              )
          {
              localizability = null;
              propertyType   = null;
              
              PropertyInfo info = owner.GetProperty(propertyName);
              if (info == null)
              {
                  return; // couldn't find the Clr property
              }
  
              // we found the CLR property, set the type of the property
              propertyType = info.PropertyType;
  
  
gt:             object[] locAttributes = info.GetCustomAttributes(