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

  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.Collections;
  19.     using System.IO;
  20.     using System.Runtime.Remoting;
  21.     using System.Runtime.InteropServices;
  22.     using System.Runtime.CompilerServices;
  23.     using System.Threading;
  24.     using System.Security.Permissions;
  25.     using System.Runtime.Versioning;
  26.    
  27.     ////////////////////////////////////////////////////////////////////////
  28.     //
  29.     // Base class used to read NLS+ data tables for culture/region/calendar data
  30.     //
  31.     //
  32.     // Data types supported in this version:
  33.     // 0: WORD A WORD value. It is returend as signed int. The interpretation of sign is left to caller.
  34.     // 1: String A string value. The first WORD is the size of the string.
  35.     // 2: WORD[] A WORD array. The first DWORD is the size of the array, and it is followed by the DWORD values.
  36.     // 3: String[] A string array. The first WORD is the size of the string array. And it is folowed by offsets to counted string values.
  37.     //
  38.     ////////////////////////////////////////////////////////////////////////
  39.     internal abstract class BaseInfoTable
  40.     {
  41.         // The base pointer of the data table (beginning of the data file)
  42.         unsafe internal byte* m_pDataFileStart;
  43.        
  44.         protected MemoryMapFile memoryMapFile = null;
  45.        
  46.         // The pointer to the main header
  47.         unsafe protected CultureTableHeader* m_pCultureHeader;
  48.        
  49.         // The pointer to where the item data begins.
  50.         unsafe internal byte* m_pItemData;
  51.        
  52.         // The total number of data items.
  53.         internal uint m_numItem;
  54.        
  55.         // The size of each data item. This is the total size (in bytes) of each calendar or culture record.
  56.         internal uint m_itemSize;
  57.        
  58.         unsafe internal ushort* m_pDataPool;
  59.        
  60.         // Where we came from
  61.         internal bool fromAssembly;
  62.         internal string fileName;
  63.        
  64.         protected bool m_valid = true;
  65.        
  66.         //private static String m_InternationalRegKey = "Control Panel\\International";
  67.        
  68.         ////////////////////////////////////////////////////////////////////////
  69.         //
  70.         // Read the table and set up pointers pointing to different parts of
  71.         // the table.
  72.         // Parameters:
  73.         // fromAssembly When true, we will load data table from mscorlib assemlby.
  74.         //
  75.         ////////////////////////////////////////////////////////////////////////
  76.        
  77.         [ResourceExposure(ResourceScope.Machine)]
  78.         [ResourceConsumption(ResourceScope.Machine)]
  79.         unsafe internal BaseInfoTable(string fileName, bool fromAssembly)
  80.         {
  81.             this.fileName = fileName;
  82.             this.fromAssembly = fromAssembly;
  83.             InitializeBaseInfoTablePointers(fileName, fromAssembly);
  84.         }
  85.        
  86.         [ResourceExposure(ResourceScope.Machine)]
  87.         [ResourceConsumption(ResourceScope.Machine)]
  88.         unsafe internal void InitializeBaseInfoTablePointers(string fileName, bool fromAssembly)
  89.         {
  90.             if (fromAssembly) {
  91.                 m_pDataFileStart = GlobalizationAssembly.GetGlobalizationResourceBytePtr(typeof(BaseInfoTable).Assembly, fileName);
  92.             }
  93.             else {
  94.                 this.memoryMapFile = new MemoryMapFile(fileName);
  95.                
  96.                 if (this.memoryMapFile.FileSize == 0) {
  97.                     m_valid = false;
  98.                     return;
  99.                 }
  100.                
  101.                 this.m_pDataFileStart = this.memoryMapFile.GetBytePtr();
  102.             }
  103.             EndianessHeader* pEndianHeader = (EndianessHeader*)m_pDataFileStart;
  104.            
  105.             // Set up pointer to the CultureTableHeader
  106.            
  107.             #if BIGENDIAN
  108.             BCLDebug.Assert(pEndianHeader->beOffset != 0, "Big-Endian data is expected.");
  109.             m_pCultureHeader = (CultureTableHeader*)(m_pDataFileStart + pEndianHeader->beOffset);
  110.             #else
  111.             BCLDebug.Assert(pEndianHeader->leOffset != 0, "Little-Endian data is expected.");
  112.             m_pCultureHeader = (CultureTableHeader*)(m_pDataFileStart + pEndianHeader->leOffset);
  113.             #endif
  114.            
  115.             // Set up misc pointers and variables.
  116.             // Different data items for calendar and culture, so they each have their own setting thingy.
  117.             SetDataItemPointers();
  118.         }
  119.        
  120.         //
  121.         // IsValid
  122.         // tell if the current object is valid to use or not. note the only cases this object br invalid is
  123.         // when we have corrupted custom culture file.
  124.         //
  125.        
  126.         internal bool IsValid {
  127.             get { return m_valid; }
  128.         }
  129.        
  130.         unsafe public override bool Equals(object value)
  131.         {
  132.             BaseInfoTable that = value as BaseInfoTable;
  133.             return (that != null) && (this.fromAssembly == that.fromAssembly && CultureInfo.InvariantCulture.CompareInfo.Compare(this.fileName, that.fileName, CompareOptions.IgnoreCase) == 0);
  134.         }
  135.        
  136.         public override int GetHashCode()
  137.         {
  138.             return (this.fileName.GetHashCode());
  139.         }
  140.        
  141.         ////////////////////////////////////////////////////////////////////////
  142.         //
  143.         // Set Data Item Pointers that are unique to calendar or culture table
  144.         //
  145.         ////////////////////////////////////////////////////////////////////////
  146.         unsafe internal abstract void SetDataItemPointers();
  147.        
  148.         ////////////////////////////////////////////////////////////////////////
  149.         //
  150.         // Read a string from the string pool using the given string offset
  151.         //
  152.         ////////////////////////////////////////////////////////////////////////
  153.         unsafe internal string GetStringPoolString(uint offset)
  154.         {
  155.             char* pCharValues = unchecked((char*)(m_pDataPool + offset));
  156.             // In the case of empty string, pCharValues[0] will have a size of 1, so we should check pCharValues[1] for empty string.
  157.             if (pCharValues[1] == 0)
  158.                 return (String.Empty);
  159.             return (new string(pCharValues + 1, 0, (int)pCharValues[0]));
  160.         }
  161.        
  162.         ////////////////////////////////////////////////////////////////////////
  163.         //
  164.         // Read a string array from the pool using the given offset
  165.         //
  166.         ////////////////////////////////////////////////////////////////////////
  167.         unsafe internal string[] GetStringArray(uint iOffset)
  168.         {
  169.             // If its empty return null
  170.             if (iOffset == 0)
  171.                 return new string[0];
  172.            
  173.             // The offset value is in char, and is related to the begining of string pool.
  174.             ushort* pCount = m_pDataPool + iOffset;
  175.             int count = (int)pCount[0];
  176.             // The number of strings in the array
  177.             string[] values = new string[count];
  178.            
  179.             // Get past count and cast to uint
  180.             uint* pStringArray = (uint*)(pCount + 1);
  181.            
  182.             // Get our strings
  183.             for (int i = 0; i < count; i++)
  184.                 values[i] = GetStringPoolString(pStringArray[i]);
  185.            
  186.             return (values);
  187.         }
  188.        
  189.         ////////////////////////////////////////////////////////////////////////
  190.         //
  191.         // Return multiple WORD field arrays values for the specified data item in the data table.
  192.         // The result is retured as an array of int since that's what most CI/NFI/DTFI properties return.
  193.         //
  194.         ////////////////////////////////////////////////////////////////////////
  195.         unsafe internal int[][] GetWordArrayArray(uint iOffset)
  196.         {
  197.             // if its empty return null
  198.             if (iOffset == 0)
  199.                 return new int[0][];
  200.            
  201.             // The offset value is in char, and is related to the begining of string pool.
  202.             // Need short* to get proper negative numbers for negative eras.
  203.             short* pCount = (short*)(m_pDataPool + iOffset);
  204.             int countArrays = (int)pCount[0];
  205.             // The number of word arrays in the array
  206.             int[][] values = new int[countArrays][];
  207.            
  208.             // Get past count and cast to uint to get the pointers to the word arrays
  209.             uint* pWordArrays = (uint*)(pCount + 1);
  210.            
  211.             // Get our word arrays
  212.             for (int i = 0; i < countArrays; i++) {
  213.                 pCount = (short*)(m_pDataPool + pWordArrays[i]);
  214.                 int count = pCount[0];
  215.                 pCount++;
  216.                 // Advance past count and reuse for word pointer
  217.                 values[i] = new int[count];
  218.                 for (int j = 0; j < count; j++) {
  219.                     values[i][j] = pCount[j];
  220.                 }
  221.             }
  222.            
  223.             return (values);
  224.         }
  225.        
  226.         ////////////////////////////////////////////////////////////////////////
  227.         //
  228.         // Compare a managed string to a string pool using the given string offset.
  229.         // Does binary comparisons. This is a bit better for perf. and reources than
  230.         // creating a string object and making an f-call.
  231.         //
  232.         // Parameters
  233.         // name: The name to be compared.
  234.         // offset: an offset into the string table.
  235.         //
  236.         // Note
  237.         // name should be in lowercase when this is called.
  238.         //
  239.         ////////////////////////////////////////////////////////////////////////
  240.         unsafe internal int CompareStringToStringPoolStringBinary(string name, int offset)
  241.         {
  242.             int test = 0;
  243.             char* pCharValues = unchecked((char*)(m_pDataPool + offset));
  244.             // In the case of empty string, pCharValues[0] will have a size of 1, so we should check pCharValues[1] for empty string.
  245.             if (pCharValues[1] == 0) {
  246.                 if (name.Length == 0) {
  247.                     return (0);
  248.                 }
  249.                 return (1);
  250.             }
  251.            
  252.             for (int i = 0; (i < (int)pCharValues[0]) && (i < name.Length); i++) {
  253.                 BCLDebug.Assert(!(name[i] >= 'A' && name[i] <= 'Z'), "name should be in lowercase");
  254.                 // A little case insensitivity, for ASCII only.
  255.                 test = name[i] - ((pCharValues[i + 1] <= 'Z' && pCharValues[i + 1] >= 'A') ? (pCharValues[i + 1] + 'a' - 'A') : (pCharValues[i + 1]));
  256.                
  257.                 if (test != 0) {
  258.                     break;
  259.                 }
  260.             }
  261.            
  262.             return (test == 0 ? name.Length - (int)pCharValues[0] : test);
  263.         }
  264.     }
  265. }

Developer Fusion