The Labs \ Source Viewer \ SSCLI \ System.Globalization \ GlobalizationAssembly

  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.Globalization
  16. {
  17.     using System;
  18.     using System.Reflection;
  19.     using System.Collections;
  20.     using System.Threading;
  21.     using System.Runtime.CompilerServices;
  22.     using System.Runtime.ConstrainedExecution;
  23.     using System.IO;
  24.    
  25.    
  26. /*=================================GlobalizationAssembly==========================
  27.     **
  28.     ** This class manages the assemblies used in the NLS+ classes.
  29.     ** Assembly contains the data tables used by NLS+ classes.  An aseembly will carry a version
  30.     ** of all the NLS+ data tables.  The default assembly is provided by
  31.     ** Assembly.GetAssembly(typeof(GlobalizationAssembly)).
  32.     **
  33.     ** We use assembly to support versioning of NLS+ data tables.  Take CompareInfo for example.
  34.     ** In CompareInfo.GetCompareInfo(int culture, Assembly),
  35.     ** you can pass an assembly which contains the different NLS+ data tables.  By doing this, the constructed CompareInfo
  36.     ** will read the sorting tables from the specified Assembly, instead of from the default assembly shipped with the runtime.
  37.     **
  38.     ** For every assembly used, we will create one corresponding GlobalizationAssembly. 
  39.     ** Within the GlobalizationAssembly, we will hold the following information:
  40.     **      1. the 32-bit pointer value pointing to the corresponding native C++ NativeGlobalizationAssembly object for it.  This pointer
  41.     **        is needed when we create SortingTable.  See CompareInfo ctor for an example.
  42.     **      2. the caches for different type of objects. For instances, we will have caches for CompareInfo, CultureInfo, RegionInfo, etc.
  43.     **        The idea is to create one instance of CompareInfo for a specific culture.
  44.     **
  45.     ** For only, only CompareInfo versioning is supported.  However, this class can be expanded to support the versioning of
  46.     ** CultureInfo, RegionInfo, etc.
  47.     **
  48.     ============================================================================*/   
  49.    
  50.     internal sealed class GlobalizationAssembly
  51.     {
  52.         // ----------------------------------------------------------------------------------------------------
  53.         //
  54.         // Static data members and static methods.
  55.         //
  56.         // ----------------------------------------------------------------------------------------------------
  57.        
  58.         //
  59.         // Hash to store Globalization assembly.
  60.         //
  61.         private static Hashtable m_assemblyHash = new Hashtable(4);
  62.        
  63.         //
  64.         // The pointer to the default C++ native NativeGlobalizationAssembly object for the class library.
  65.         // We use default native NativeGlobalizationAssembly to access NLS+ data table shipped with the runtime.
  66.         //
  67.         // Classes like CompareInfo will access this data member directly when the default assembly is used.
  68.         //
  69.         static internal GlobalizationAssembly m_defaultInstance = GetGlobalizationAssembly(Assembly.GetAssembly(typeof(GlobalizationAssembly)));
  70.        
  71.         static internal GlobalizationAssembly DefaultInstance {
  72.             //
  73.             // In case the GlobalizationAssembly class failed during the type initilaization then we'll have m_defaultInstance = null.
  74.             // to be reliable we throw exception instead of getting access violation.
  75.             //
  76.             get {
  77.                 if (m_defaultInstance == null)
  78.                     throw new TypeLoadException(CultureTable.TypeLoadExceptionMessage);
  79.                
  80.                 return m_defaultInstance;
  81.             }
  82.         }
  83.        
  84. /*=================================GetGlobalizationAssembly==========================
  85.         **Action: Return the GlobalizationAssembly instance for the specified assembly.
  86.         **  Every assembly should have one and only one instance of GlobalizationAssembly.
  87.         **Returns: An instance of GlobalizationAssembly.
  88.         **Arguments:
  89.         **Exceptions:
  90.         ============================================================================*/       
  91.         static internal GlobalizationAssembly GetGlobalizationAssembly(Assembly assembly)
  92.         {
  93.             GlobalizationAssembly ga;
  94.            
  95.             if ((ga = (GlobalizationAssembly)m_assemblyHash[assembly]) == null) {
  96.                 // This is intentionally taking a process-global lock on an
  97.                 // internal Type, using ExecuteCodeWithLock to guarantee we
  98.                 // release the lock in a stack overflow safe way.
  99.                 RuntimeHelpers.TryCode createGlobalizationAssem = new RuntimeHelpers.TryCode(CreateGlobalizationAssembly);
  100.                 RuntimeHelpers.ExecuteCodeWithLock(typeof(CultureTableRecord), createGlobalizationAssem, assembly);
  101.                 ga = (GlobalizationAssembly)m_assemblyHash[assembly];
  102.             }
  103.             BCLDebug.Assert(ga != null, "GlobalizationAssembly was not created");
  104.             return (ga);
  105.         }
  106.        
  107.         [PrePrepareMethod()]
  108.         unsafe private static void CreateGlobalizationAssembly(object assem)
  109.         {
  110.             GlobalizationAssembly ga;
  111.             Assembly assembly = (Assembly)assem;
  112.             if ((ga = (GlobalizationAssembly)m_assemblyHash[assembly]) == null) {
  113.                 // This assembly is not used before, create a corresponding native NativeGlobalizationAssembly object for it.
  114.                 ga = new GlobalizationAssembly();
  115.                 ga.pNativeGlobalizationAssembly = nativeCreateGlobalizationAssembly(assembly);
  116.                 System.Threading.Thread.MemoryBarrier();
  117.                 m_assemblyHash[assembly] = ga;
  118.             }
  119.         }
  120.        
  121.         // This method requires synchonization because class global data member is used
  122.         // in the native side.
  123.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  124.         unsafe private static extern void* nativeCreateGlobalizationAssembly(Assembly assembly);
  125.        
  126.        
  127.         // ----------------------------------------------------------------------------------------------------
  128.         //
  129.         // Instance data members and instance methods.
  130.         //
  131.         // ----------------------------------------------------------------------------------------------------
  132.        
  133.         // This is the cache to store CompareInfo for a particular culture.
  134.         // The key is culture, and the content is an instance of CompareInfo.
  135.         internal Hashtable compareInfoCache;
  136.         // We will have more caches here for CultureInfo, RegionInfo, etc. if we want to versioning in
  137.         // these classes.
  138.        
  139.         // The pointer to C++ native NativeGlobalizationAssembly
  140.         unsafe internal void* pNativeGlobalizationAssembly;
  141.        
  142.         internal GlobalizationAssembly()
  143.         {
  144.             // Create cache for CompareInfo instances.
  145.             compareInfoCache = new Hashtable(4);
  146.         }
  147.        
  148.         unsafe static internal byte* GetGlobalizationResourceBytePtr(Assembly assembly, string tableName)
  149.         {
  150.             BCLDebug.Assert(assembly != null, "assembly can not be null. This should be generally the mscorlib.dll assembly.");
  151.             BCLDebug.Assert(tableName != null, "table name can not be null");
  152.            
  153.             Stream stream = assembly.GetManifestResourceStream(tableName);
  154.             UnmanagedMemoryStream bytesStream = stream as UnmanagedMemoryStream;
  155.             if (bytesStream != null) {
  156.                 byte* bytes = bytesStream.PositionPointer;
  157.                 if (bytes != null) {
  158.                     return (bytes);
  159.                 }
  160.             }
  161.            
  162.             BCLDebug.Assert(false, String.Format(CultureInfo.CurrentCulture, "Didn't get the resource table {0} for System.Globalization from {1}", tableName, assembly));
  163.             // We can not continue if we can't get the resource.
  164.             throw new ExecutionEngineException();
  165.         }
  166.        
  167.     }
  168. }

Developer Fusion