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

  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.Runtime.Remoting;
  18.     using System;
  19.     using System.Text;
  20.     using System.Threading;
  21.     using System.Collections;
  22.     using System.Runtime.InteropServices;
  23.     using System.Runtime.CompilerServices;
  24.     using System.Security;
  25.     using System.Security.Permissions;
  26.     using System.IO;
  27.     using Microsoft.Win32;
  28.     using System.Runtime.Versioning;
  29.    
  30. /*=============================================================================
  31.     *
  32.     * Data table for CultureInfo classes.  Used by System.Globalization.CultureInfo.
  33.     *
  34.     ==============================================================================*/   
  35.     // Only statics, does not need to be marked with the serializable attribute
  36.     internal class CultureTable : BaseInfoTable
  37.     {
  38.        
  39.         // WARNING!
  40.         //
  41.         // This value must be the kept in sync with the field order in the file or everything'll die
  42.         // This is currently copied from culture.h which is generated by nlpgen.pl
  43.         // Currently ILANGUAGE is the first field in the record
  44.         internal const int ILANGUAGE = 0;
  45.         // Currently we need to know offset into record (in words) of ILANGUAGE to look up records by LCID
  46.         //
  47.         // This is the mask used to check if the flags for GetCultures() is valid.
  48.         //
  49.         private const CultureTypes CultureTypesMask = ~(CultureTypes.NeutralCultures | CultureTypes.SpecificCultures | CultureTypes.InstalledWin32Cultures | CultureTypes.UserCustomCulture | CultureTypes.ReplacementCultures | CultureTypes.WindowsOnlyCultures | CultureTypes.FrameworkCultures);
  50.        
  51.         // Hashtable for indexing name to get nDataItem.
  52.         private Hashtable hashByName;
  53.         private Hashtable hashByRegionName;
  54.         private Hashtable hashByLcid;
  55.        
  56.         unsafe private CultureNameOffsetItem* m_pCultureNameIndex;
  57.         unsafe private RegionNameOffsetItem* m_pRegionNameIndex;
  58.         unsafe private IetfNameOffsetItem* m_pIetfNameIndex;
  59.         unsafe private IDOffsetItem* m_pCultureIDIndex;
  60.        
  61.         private static CultureTable m_defaultInstance;
  62.        
  63.         [ResourceExposure(ResourceScope.Machine)]
  64.         [ResourceConsumption(ResourceScope.Machine)]
  65.         static CultureTable()
  66.         {
  67.             m_defaultInstance = new CultureTable("culture.nlp", true);
  68.         }
  69.        
  70.         [ResourceExposure(ResourceScope.Machine)]
  71.         [ResourceConsumption(ResourceScope.Machine)]
  72.         unsafe internal CultureTable(string fileName, bool fromAssembly) : base(fileName, fromAssembly)
  73.         {
  74.             if (!IsValid)
  75.                 // intialized in SetDataItemPointers
  76.                 return;
  77.            
  78.             hashByName = new Hashtable();
  79.             hashByLcid = new Hashtable();
  80.             hashByRegionName = new Hashtable();
  81.            
  82.             // Set up index table for finding data item from culture or region name.
  83.             m_pCultureNameIndex = (CultureNameOffsetItem*)(m_pDataFileStart + m_pCultureHeader->cultureNameTableOffset);
  84.             m_pRegionNameIndex = (RegionNameOffsetItem*)(m_pDataFileStart + m_pCultureHeader->regionNameTableOffset);
  85.             m_pIetfNameIndex = (IetfNameOffsetItem*)(m_pDataFileStart + m_pCultureHeader->ietfNameTableOffset);
  86.            
  87.             // Set up index table for finding data item from LCID.
  88.             m_pCultureIDIndex = (IDOffsetItem*)(m_pDataFileStart + m_pCultureHeader->cultureIDTableOffset);
  89.         }
  90.        
  91.        
  92.         // TypeLoadExceptionMessage is going to be used at the time of failing to load CultureTable type and
  93.         // then m_defaultInstance will be null and we cannot call any NLS+ code. so we cannot call the resource
  94.         // manager to get any string because resource manager will call culture info code again. So we had to
  95.         // use non resource string for throwing this exception.
  96.         // Note, failing to load CUltureTable is rare to happen and we just got it when injecting OOM fault
  97.         // to the CLR while trying loading some types.
  98.         internal const string TypeLoadExceptionMessage = "Failure has occurred while loading a type.";
  99.        
  100.         static internal CultureTable Default {
  101.             get {
  102.                 //
  103.                 // In case the CultureTable class failed during the type initilaization then we'll have m_defaultInstance = null.
  104.                 // to be reliable we throw exception instead of getting access violation.
  105.                 //
  106.                
  107.                 if (m_defaultInstance == null)
  108.                     throw new TypeLoadException(TypeLoadExceptionMessage);
  109.                
  110.                 return (m_defaultInstance);
  111.             }
  112.         }
  113.        
  114.         ////////////////////////////////////////////////////////////////////////
  115.         //
  116.         // Set Data Item Pointers that are unique to culture table
  117.         //
  118.         ////////////////////////////////////////////////////////////////////////
  119.         unsafe internal override void SetDataItemPointers()
  120.         {
  121.             if (Validate()) {
  122.                 m_itemSize = m_pCultureHeader->sizeCultureItem;
  123.                 m_numItem = m_pCultureHeader->numCultureItems;
  124.                 m_pDataPool = (ushort*)(m_pDataFileStart + m_pCultureHeader->offsetToDataPool);
  125.                 m_pItemData = m_pDataFileStart + m_pCultureHeader->offsetToCultureItemData;
  126.             }
  127.             else {
  128.                 m_valid = false;
  129.             }
  130.         }
  131.        
  132.         #region CustomCultureValidation
  133.        
  134.         //
  135.         // ValidateString catch the buffer overrun.
  136.         // Note, offsets and sizes here are in characters not in bytes.
  137.         //
  138.         unsafe private static string CheckAndGetTheString(ushort* pDataPool, uint offsetInPool, int poolSize)
  139.         {
  140.             if (offsetInPool + 2 > poolSize)
  141.                 // string offset + string length + null termination.
  142.                 return null;
  143.            
  144.             char* pCharValues = unchecked((char*)(pDataPool + offsetInPool));
  145.             int stringLength = (int)pCharValues[0];
  146.             if (offsetInPool + stringLength + 2 > poolSize)
  147.                 // string length + string + null termination
  148.                 return null;
  149.            
  150.             return new string(pCharValues + 1, 0, stringLength);
  151.         }
  152.        
  153.        
  154.         //
  155.         // ValidateString catch the buffer overrun.
  156.         // Note, offsets and sizes here are in characters not in bytes.
  157.         //
  158.        
  159.         unsafe private static bool ValidateString(ushort* pDataPool, uint offsetInPool, int poolSize)
  160.         {
  161.             if (offsetInPool + 2 > poolSize)
  162.                 // string offset + string length + null termination.
  163.                 return false;
  164.            
  165.             char* pCharValues = unchecked((char*)(pDataPool + offsetInPool));
  166.             int stringLength = (int)pCharValues[0];
  167.             if (offsetInPool + stringLength + 2 > poolSize)
  168.                 // string length + string + null termination
  169.                 return false;
  170.            
  171.             return true;
  172.         }
  173.        
  174.         //
  175.         // ValidateString catch the buffer overrun.
  176.         // Note, offsets and sizes here are in characters not in bytes.
  177.         //
  178.        
  179.         unsafe private static bool ValidateUintArray(ushort* pDataPool, uint offsetInPool, int poolSize)
  180.         {
  181.             if (offsetInPool == 0)
  182.                 return true;
  183.            
  184.             if (offsetInPool + 2 > poolSize)
  185.                 // string offset + string length + null termination.
  186.                 return false;
  187.            
  188.             // Get location of count and make sure its on an odd word
  189.             // (odd words would end in 2 as pointers, we want pCount%4 to be 2 so that
  190.             // when we get past the count our uints are uint aligned)
  191.             ushort* pCount = pDataPool + offsetInPool;
  192.             if (((int)(pCount)&2) != 2)
  193.                 return false;
  194.            
  195.             int arrayLength = pCount[0];
  196.             if (offsetInPool + (arrayLength * 2) + 2 > poolSize)
  197.                 // array length * 2 (words/dword) + string + null termination
  198.                 return false;
  199.            
  200.             return true;
  201.         }
  202.        
  203.         //
  204.         // ValidateStringArray catch the buffer overrun.
  205.         // Note, offsets and sizes here are in characters not in bytes.
  206.         //
  207.        
  208.         unsafe private static bool ValidateStringArray(ushort* pDataPool, uint offsetInPool, int poolSize)
  209.         {
  210.             if (!ValidateUintArray(pDataPool, offsetInPool, poolSize))
  211.                 return false;
  212.            
  213.             // Get our count
  214.             ushort* pCount = pDataPool + offsetInPool;
  215.             int arrayLength = pCount[0];
  216.            
  217.             if (arrayLength == 0)
  218.                 return true;
  219.            
  220.             // Get our dword *
  221.             uint* uints = (uint*)(pCount + 1);
  222.            
  223.             for (int i = 0; i < arrayLength; i++) {
  224.                 if (!ValidateString(pDataPool, uints[i], poolSize))
  225.                     return false;
  226.             }
  227.            
  228.             return true;
  229.         }
  230.        
  231.         //
  232.         // IsValidLcid
  233.         // Lcid is valid if it is built in lcid or synthetic one.
  234.         //
  235.        
  236.         private static bool IsValidLcid(int lcid, bool canBeCustomLcid)
  237.         {
  238.             if (canBeCustomLcid && CultureTableRecord.IsCustomCultureId(lcid))
  239.                 return true;
  240.            
  241.             if (CultureTable.Default.IsExistingCulture(lcid))
  242.                 return true;
  243.            
  244.            
  245.             return false;
  246.         }
  247.        
  248.         const uint sizeofNameOffsetItem = 8;
  249.         // NameOffsetItem is 8 bytes.
  250.         //
  251.         // Validate
  252.         // this method used to do shallow validation for the custom culture file. it checks for the buffer overrun
  253.         // also it validate some other fields like parent, lcid, text info, and compare info.
  254.         //
  255.         [ResourceExposure(ResourceScope.None)]
  256.         [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
  257.         unsafe internal bool Validate()
  258.         {
  259.             if (memoryMapFile == null)
  260.                 // we only validate custom cultures.
  261.                 return true;
  262.            
  263.             long fileSize = memoryMapFile.FileSize;
  264.            
  265.             if (sizeof(EndianessHeader) + sizeof(CultureTableHeader) + sizeof(CultureTableData) + 2 * sizeof(int) > fileSize)
  266.                 return false;
  267.            
  268.             // EndianessHeader
  269.             EndianessHeader* pEndianHeader = (EndianessHeader*)m_pDataFileStart;
  270.             #if BIGENDIAN
  271.             if (pEndianHeader->beOffset > fileSize)
  272.                 return false;
  273.             #else
  274.             if (pEndianHeader->leOffset > fileSize)
  275.                 return false;
  276.             #endif // BIGENDIAN
  277.            
  278.             // CultureTableHeader
  279.             if (m_pCultureHeader->offsetToCultureItemData + m_pCultureHeader->sizeCultureItem > fileSize) {
  280.                 return false;
  281.             }
  282.             if (m_pCultureHeader->cultureIDTableOffset > fileSize) {
  283.                 return false;
  284.             }
  285.             if (m_pCultureHeader->cultureNameTableOffset + sizeofNameOffsetItem > fileSize) {
  286.                 return false;
  287.             }
  288.             if (m_pCultureHeader->regionNameTableOffset > fileSize) {
  289.                 return false;
  290.             }
  291.             if (m_pCultureHeader->offsetToCalendarItemData + m_pCultureHeader->sizeCalendarItem > fileSize) {
  292.                 return false;
  293.             }
  294.             if (m_pCultureHeader->ietfNameTableOffset > fileSize) {
  295.                 return false;
  296.             }
  297.             if (m_pCultureHeader->offsetToDataPool > fileSize) {
  298.                 return false;
  299.             }
  300.            
  301.             ushort* pDataPool = (ushort*)(m_pDataFileStart + m_pCultureHeader->offsetToDataPool);
  302.            
  303.             int poolSizeInChar = (int)(fileSize - ((long)pDataPool - (long)m_pDataFileStart)) / 2;
  304.             // number of characters in the pool
  305.             if (poolSizeInChar <= 0)
  306.                 return false;
  307.            
  308.             // SNAME
  309.             uint sNameOffset = (uint)((char*)(m_pDataFileStart + m_pCultureHeader->cultureNameTableOffset))[0];
  310.            
  311.             // CultureTableData
  312.             CultureTableData* cultureData = (CultureTableData*)(m_pDataFileStart + m_pCultureHeader->offsetToCultureItemData);
  313.            
  314.             if (cultureData->iLanguage == 127 || !IsValidLcid(cultureData->iLanguage, true))
  315.                 return false;
  316.            
  317.             string cultureName = CheckAndGetTheString(pDataPool, cultureData->sName, poolSizeInChar);
  318.             if (String.IsNullOrEmpty(cultureName))
  319.                 return false;
  320.            
  321.             if (sNameOffset != cultureData->sName) {
  322.                 if (!cultureName.Equals(CheckAndGetTheString(pDataPool, sNameOffset, poolSizeInChar)))
  323.                     return false;
  324.             }
  325.            
  326.             string parentName = CheckAndGetTheString(pDataPool, cultureData->sParent, poolSizeInChar);
  327.             if (parentName == null || parentName.Equals(cultureName, StringComparison.OrdinalIgnoreCase))
  328.                 return false;
  329.            
  330.             if (!IsValidLcid((int)cultureData->iTextInfo, false) || !IsValidLcid((int)cultureData->iCompareInfo, false))
  331.                 return false;
  332.            
  333.             // We could use the reflection instead of checking each field manually but this was hurting
  334.             // the performance (almost 35% from the creation time)
  335.            
  336.             if (!ValidateString(pDataPool, cultureData->waGrouping, poolSizeInChar)) {
  337.                 return false;
  338.             }
  339.             if (!ValidateString(pDataPool, cultureData->waMonetaryGrouping, poolSizeInChar)) {
  340.                 return false;
  341.             }
  342.             if (!ValidateString(pDataPool, cultureData->sListSeparator, poolSizeInChar)) {
  343.                 return false;
  344.             }
  345.             if (!ValidateString(pDataPool, cultureData->sDecimalSeparator, poolSizeInChar)) {
  346.                 return false;
  347.             }
  348.             if (!ValidateString(pDataPool, cultureData->sThousandSeparator, poolSizeInChar)) {
  349.                 return false;
  350.             }
  351.             if (!ValidateString(pDataPool, cultureData->sCurrency, poolSizeInChar)) {
  352.                 return false;
  353.             }
  354.             if (!ValidateString(pDataPool, cultureData->sMonetaryDecimal, poolSizeInChar)) {
  355.                 return false;
  356.             }
  357.             if (!ValidateString(pDataPool, cultureData->sMonetaryThousand, poolSizeInChar)) {
  358.                 return false;
  359.             }
  360.             if (!ValidateString(pDataPool, cultureData->sPositiveSign, poolSizeInChar)) {
  361.                 return false;
  362.             }
  363.             if (!ValidateString(pDataPool, cultureData->sNegativeSign, poolSizeInChar)) {
  364.                 return false;
  365.             }
  366.             if (!ValidateString(pDataPool, cultureData->sAM1159, poolSizeInChar)) {
  367.                 return false;
  368.             }
  369.             if (!ValidateString(pDataPool, cultureData->sPM2359, poolSizeInChar)) {
  370.                 return false;
  371.             }
  372.             if (!ValidateStringArray(pDataPool, cultureData->saNativeDigits, poolSizeInChar)) {
  373.                 return false;
  374.             }
  375.             if (!ValidateStringArray(pDataPool, cultureData->saTimeFormat, poolSizeInChar)) {
  376.                 return false;
  377.             }
  378.             if (!ValidateStringArray(pDataPool, cultureData->saShortDate, poolSizeInChar)) {
  379.                 return false;
  380.             }
  381.             if (!ValidateStringArray(pDataPool, cultureData->saLongDate, poolSizeInChar)) {
  382.                 return false;
  383.             }
  384.             if (!ValidateStringArray(pDataPool, cultureData->saYearMonth, poolSizeInChar)) {
  385.                 return false;
  386.             }
  387.             if (!ValidateStringArray(pDataPool, cultureData->saDuration, poolSizeInChar)) {
  388.                 return false;
  389.             }
  390.             if (!ValidateString(pDataPool, cultureData->waCalendars, poolSizeInChar)) {
  391.                 return false;
  392.             }
  393.             if (!ValidateString(pDataPool, cultureData->sAbbrevLang, poolSizeInChar)) {
  394.                 return false;
  395.             }
  396.             if (!ValidateString(pDataPool, cultureData->sISO639Language, poolSizeInChar)) {
  397.                 return false;
  398.             }
  399.             if (!ValidateString(pDataPool, cultureData->sEnglishLanguage, poolSizeInChar)) {
  400.                 return false;
  401.             }
  402.             if (!ValidateString(pDataPool, cultureData->sNativeLanguage, poolSizeInChar)) {
  403.                 return false;
  404.             }
  405.             if (!ValidateString(pDataPool, cultureData->sEnglishCountry, poolSizeInChar)) {
  406.                 return false;
  407.             }
  408.             if (!ValidateString(pDataPool, cultureData->sNativeCountry, poolSizeInChar)) {
  409.                 return false;
  410.             }
  411.             if (!ValidateString(pDataPool, cultureData->sAbbrevCountry, poolSizeInChar)) {
  412.                 return false;
  413.             }
  414.             if (!ValidateString(pDataPool, cultureData->sISO3166CountryName, poolSizeInChar)) {
  415.                 return false;
  416.             }
  417.             if (!ValidateString(pDataPool, cultureData->sIntlMonetarySymbol, poolSizeInChar)) {
  418.                 return false;
  419.             }
  420.             if (!ValidateString(pDataPool, cultureData->sEnglishCurrency, poolSizeInChar)) {
  421.                 return false;
  422.             }
  423.             if (!ValidateString(pDataPool, cultureData->sNativeCurrency, poolSizeInChar)) {
  424.                 return false;
  425.             }
  426.             if (!ValidateString(pDataPool, cultureData->waFontSignature, poolSizeInChar)) {
  427.                 return false;
  428.             }
  429.             if (!ValidateString(pDataPool, cultureData->sISO639Language2, poolSizeInChar)) {
  430.                 return false;
  431.             }
  432.             if (!ValidateString(pDataPool, cultureData->sISO3166CountryName2, poolSizeInChar)) {
  433.                 return false;
  434.             }
  435.             if (!ValidateStringArray(pDataPool, cultureData->saDayNames, poolSizeInChar)) {
  436.                 return false;
  437.             }
  438.             if (!ValidateStringArray(pDataPool, cultureData->saAbbrevDayNames, poolSizeInChar)) {
  439.                 return false;
  440.             }
  441.             if (!ValidateStringArray(pDataPool, cultureData->saMonthNames, poolSizeInChar)) {
  442.                 return false;
  443.             }
  444.             if (!ValidateStringArray(pDataPool, cultureData->saAbbrevMonthNames, poolSizeInChar)) {
  445.                 return false;
  446.             }
  447.             if (!ValidateStringArray(pDataPool, cultureData->saMonthGenitiveNames, poolSizeInChar)) {
  448.                 return false;
  449.             }
  450.             if (!ValidateStringArray(pDataPool, cultureData->saAbbrevMonthGenitiveNames, poolSizeInChar)) {
  451.                 return false;
  452.             }
  453.             if (!ValidateStringArray(pDataPool, cultureData->saNativeCalendarNames, poolSizeInChar)) {
  454.                 return false;
  455.             }
  456.             if (!ValidateStringArray(pDataPool, cultureData->saAltSortID, poolSizeInChar)) {
  457.                 return false;
  458.             }
  459.             if (!ValidateString(pDataPool, cultureData->sEnglishDisplayName, poolSizeInChar)) {
  460.                 return false;
  461.             }
  462.             if (!ValidateString(pDataPool, cultureData->sNativeDisplayName, poolSizeInChar)) {
  463.                 return false;
  464.             }
  465.             if (!ValidateString(pDataPool, cultureData->sPercent, poolSizeInChar)) {
  466.                 return false;
  467.             }
  468.             if (!ValidateString(pDataPool, cultureData->sNaN, poolSizeInChar)) {
  469.                 return false;
  470.             }
  471.             if (!ValidateString(pDataPool, cultureData->sPositiveInfinity, poolSizeInChar)) {
  472.                 return false;
  473.             }
  474.             if (!ValidateString(pDataPool, cultureData->sNegativeInfinity, poolSizeInChar)) {
  475.                 return false;
  476.             }
  477.             if (!ValidateString(pDataPool, cultureData->sMonthDay, poolSizeInChar)) {
  478.                 return false;
  479.             }
  480.             if (!ValidateString(pDataPool, cultureData->sAdEra, poolSizeInChar)) {
  481.                 return false;
  482.             }
  483.             if (!ValidateString(pDataPool, cultureData->sAbbrevAdEra, poolSizeInChar)) {
  484.                 return false;
  485.             }
  486.             if (!ValidateString(pDataPool, cultureData->sRegionName, poolSizeInChar)) {
  487.                 return false;
  488.             }
  489.             if (!ValidateString(pDataPool, cultureData->sConsoleFallbackName, poolSizeInChar)) {
  490.                 return false;
  491.             }
  492.             if (!ValidateStringArray(pDataPool, cultureData->saShortTime, poolSizeInChar)) {
  493.                 return false;
  494.             }
  495.             if (!ValidateStringArray(pDataPool, cultureData->saSuperShortDayNames, poolSizeInChar)) {
  496.                 return false;
  497.             }
  498.             if (!ValidateStringArray(pDataPool, cultureData->saDateWords, poolSizeInChar)) {
  499.                 return false;
  500.             }
  501.             if (!ValidateString(pDataPool, cultureData->sSpecificCulture, poolSizeInChar)) {
  502.                 return false;
  503.             }
  504.             if (!ValidateString(pDataPool, cultureData->sIetfLanguage, poolSizeInChar)) {
  505.                 return false;
  506.             }
  507.             /*           
  508.             Object cultureTableData = (object) *cultureData;
  509.             Type type = cultureTableData.GetType();
  510.             FieldInfo[] fields = type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
  511.             for (int i=0; i<fields.Length; i++)
  512.             {
  513.                 BCLDebug.Assert(
  514.                         fields[i].Name[0] == 'i' ||
  515.                         fields[i].Name[0] == 's' ||
  516.                         fields[i].Name[0] == 'w' , "Invalid structure field name.");
  517.                
  518.                 if (fields[i].Name.Length<2 || (fields[i].Name[0] != 's' && fields[i].Name[0] != 'w'))
  519.                     continue;
  520.                
  521.                 Object objectValue = type.InvokeMember(
  522.                                             fields[i].Name,
  523.                                             BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField,
  524.                                             null,
  525.                                             cultureTableData,
  526.                                             null,
  527.                                             CultureInfo.InvariantCulture);
  528.                 int value;
  529.                 if (fields[i].FieldType == typeof(System.UInt16))
  530.                     value = (int) (ushort) objectValue;
  531.                 else if (fields[i].FieldType == typeof(System.UInt32))
  532.                     value = (int) (uint) objectValue;
  533.                 else
  534.                     return false;
  535.                 bool result = false;
  536.                 if (fields[i].Name[0] == 's')
  537.                 {
  538.                     if (fields[i].Name[1] == 'a')
  539.                         result = ValidateStringArray(value, poolSizeInChar);
  540.                     else
  541.                         result = ValidateString(value, poolSizeInChar);
  542.                 }
  543.                 else
  544.                 {
  545.                     BCLDebug.Assert(fields[i].Name[1] == 'a', "Expected field starts with wa.");
  546.                     result = ValidateString(value, poolSizeInChar);
  547.                 }
  548.                
  549.                 if (!result)
  550.                     return false;
  551.             }
  552. */           
  553. return true;
  554.         }
  555.         #endregion CustomCultureValidation
  556.        
  557.        
  558. /*=================================GetDataItemFromName============================
  559.         **Action:  Given a culture name, return a index which points to a data item in
  560.         **          the Culture Data Table
  561.         **Returns:  the data item index. Or -1 if the culture name is invalid.
  562.         **Arguments:
  563.         **      name culture name
  564.         **Exceptions:
  565.         ==============================================================================*/       
  566.         unsafe internal int GetDataItemFromCultureName(string name, out int culture, out string actualName)
  567.         {
  568.             BCLDebug.Assert(name != null, "CultureTable.GetDataItemFromCultureName(): name!=null");
  569.             culture = -1;
  570.             actualName = "";
  571.            
  572.             CultureTableItem cti = (CultureTableItem)hashByName[name];
  573.             if (null != cti && 0 != cti.culture) {
  574.                 culture = cti.culture;
  575.                 actualName = cti.name;
  576.                 return (cti.dataItem);
  577.             }
  578.            
  579.             int left = 0;
  580.             int right = m_pCultureHeader->numCultureNames - 1;
  581.            
  582.             while (left <= right) {
  583.                 int mid = (left + right) / 2;
  584.                
  585.                 int result = CompareStringToStringPoolStringBinary(name, m_pCultureNameIndex[mid].strOffset);
  586.                
  587.                 if (result == 0) {
  588.                     cti = new CultureTableItem();
  589.                     int index = cti.dataItem = m_pCultureNameIndex[mid].dataItemIndex;
  590.                     culture = cti.culture = m_pCultureNameIndex[mid].actualCultureID;
  591.                     actualName = cti.name = GetStringPoolString(m_pCultureNameIndex[mid].strOffset);
  592.                    
  593.                     // m_pCultureNameIndex[i].dateItemIndex is the record number for
  594.                     // the information of a culture.
  595.                     // The trick that we play to remove es-ES-Ts is to put a duplicate entry
  596.                     // in the name offset table for es-ES, so that es-ES-Ts is not in the name offset table
  597.                     // Therefore, es-ES-Ts becomes an invalid name.
  598.                     // However, the data item for es-ES-Ts is still there. It is just that
  599.                     // you can not find it by calling GetDataItemFromName.
  600.                     hashByName[name] = cti;
  601.                     return (index);
  602.                 }
  603.                 if (result < 0) {
  604.                     right = mid - 1;
  605.                 }
  606.                 else {
  607.                     left = mid + 1;
  608.                 }
  609.             }
  610.            
  611.             culture = -1;
  612.             return (-1);
  613.         }
  614.        
  615.         //=================================GetDataItemFromRegionName============================
  616.         // Action: Given a region name, return a index which points to a data item in
  617.         // the Culture Data Table
  618.         // Returns: the data item index. Or -1 if the region name is invalid.
  619.         // Arguments:
  620.         // name region name
  621.         //
  622.         // Note: The input region name is expected to be lower case, however
  623.         // the names in the table may be mixed case. (So its case insensitive
  624.         // for the table names, but not for the input name which must be lower case)
  625.         // ==============================================================================
  626.        
  627.         unsafe internal int GetDataItemFromRegionName(string name)
  628.         {
  629.             BCLDebug.Assert(name != null, "CultureTable.GetDataItemFromRegionName(): name!=null");
  630.            
  631.             object dataItem;
  632.             if ((dataItem = hashByRegionName[name]) != null) {
  633.                 return (Int32)dataItem;
  634.             }
  635.            
  636.             int left = 0;
  637.             int right = m_pCultureHeader->numRegionNames - 1;
  638.            
  639.             while (left <= right) {
  640.                 int mid = (left + right) / 2;
  641.                
  642.                 int result = CompareStringToStringPoolStringBinary(name, m_pRegionNameIndex[mid].strOffset);
  643.                 if (result == 0) {
  644.                     int index = m_pRegionNameIndex[mid].dataItemIndex;
  645.                     hashByRegionName[name] = index;
  646.                     // m_pRegionNameIndex[i].dateItemIndex is the record number for
  647.                     // the information of a culture.
  648.                     return (index);
  649.                 }
  650.                 if (result < 0) {
  651.                     right = mid - 1;
  652.                 }
  653.                 else {
  654.                     left = mid + 1;
  655.                 }
  656.             }
  657.             return (-1);
  658.         }
  659.        
  660.         //======================== LookupIetfName ============================
  661.         // Action: Given an ietf name, get the corresponding culture name.
  662.         //
  663.         // Note: The input culture name is expected to be lower case, however
  664.         // the names in the table may be mixed case. (So its case insensitive
  665.         // for the table names, but not for the input name which must be lower case)
  666.         //
  667.         // Returns: The culture name or null if not valid.
  668.         // Arguments:
  669.         // name culture name
  670.         // Exceptions:
  671.         //==============================================================================
  672.         unsafe internal string LookupIetfName(string name)
  673.         {
  674.             BCLDebug.Assert(name != null, "CultureTable.LookupIetfName(): name!=null");
  675.            
  676.             // Get our culture table item, don't have to use cache because it should've
  677.             // been cached already in CultureInfo.GetCultureInfoByIetfLanguageTag().
  678.             int left = 0;
  679.             int right = m_pCultureHeader->numIetfNames - 1;
  680.            
  681.             while (left <= right) {
  682.                 int mid = (left + right) / 2;
  683.                 int result = CompareStringToStringPoolStringBinary(name, m_pIetfNameIndex[mid].strIetfNameOffset);
  684.                
  685.                 if (result == 0) {
  686.                     // They matched, return the real culture name
  687.                     return GetStringPoolString(m_pIetfNameIndex[mid].strCultureNameOffset);
  688.                 }
  689.                 if (result < 0)
  690.                     right = mid - 1;
  691.                 else
  692.                     left = mid + 1;
  693.             }
  694.            
  695.             // Not found, return null
  696.             return null;
  697.         }
  698.        
  699.        
  700. /*=================================GetDataItemFromCultureID============================
  701.         **Action:  Given a culture ID, return a index which points to a data item in
  702.         **          the Culture Data Table
  703.         **Returns:  the data item index.  Or -1 if the culture ID is invalid.
  704.         **Arguments:
  705.         **      cultureID
  706.         **Exceptions: None.
  707.         ==============================================================================*/       
  708.        
  709.         unsafe internal int GetDataItemFromCultureID(int cultureID, out string actualName)
  710.         {
  711.             BCLDebug.Assert(cultureID != 0, "CultureTable.GetDataItemFromCultureID(): cultureID!=0");
  712.            
  713.             CultureTableItem cti = (CultureTableItem)hashByLcid[cultureID];
  714.             if (null != cti && 0 != cti.culture) {
  715.                 actualName = cti.name;
  716.                 return (cti.dataItem);
  717.             }
  718.            
  719.             int left = 0;
  720.             int right = m_pCultureHeader->numCultureNames - 1;
  721.            
  722.             while (left <= right) {
  723.                 int mid = (left + right) / 2;
  724.                 int result = cultureID - this.m_pCultureIDIndex[mid].actualCultureID;
  725.                 if (result == 0) {
  726.                     cti = new CultureTableItem();
  727.                     int index = cti.dataItem = m_pCultureIDIndex[mid].dataItemIndex;
  728.                     int culture = cti.culture = cultureID;
  729.                    
  730.                     actualName = cti.name = GetStringPoolString(m_pCultureIDIndex[mid].strOffset);
  731.                    
  732.                     hashByLcid[cultureID] = cti;
  733.                     return (index);
  734.                 }
  735.                 if (result < 0) {
  736.                     right = mid - 1;
  737.                 }
  738.                 else {
  739.                     left = mid + 1;
  740.                 }
  741.             }
  742.            
  743.             actualName = "";
  744.             return (-1);
  745.         }
  746.        
  747. /*
  748.         internal static bool IsNeutralCulture(int cultureID) {
  749.             //BCLDebug.Assert(cultureID != -1, "-1 cultureID value passed to IsNeutralCulture.");
  750.             if (CultureInfo.GetSubLangID(cultureID) == 0) {
  751.                 return (true);
  752.             }
  753.             switch (cultureID) {
  754.                 case CultureInfo.zh_CHT_CultureID:
  755.                 case CultureInfo.sr_CultureID:
  756.                     return (true);
  757.             }
  758.             return (false);
  759.         }
  760. */       
  761.         static internal bool IsInstalledLCID(int cultureID)
  762.         {
  763.             {
  764.                 return CultureInfo.IsValidLCID(cultureID, CultureInfo.LCID_INSTALLED);
  765.             }
  766.         }
  767.        
  768.         // <SyntheticSupport/>
  769.         // IsExistingCulture is used when caching the name and lcid mapping to detect if it is
  770.         // a framework culture or synthetic cultures.
  771.         unsafe internal bool IsExistingCulture(int lcid)
  772.         {
  773.             if (lcid == 0)
  774.                 return false;
  775.            
  776.             string notUsed;
  777.             return (GetDataItemFromCultureID(lcid, out notUsed) >= 0);
  778.         }
  779.        
  780.         //
  781.         // Enumerate the cultures according the CultureTypes flags:
  782.         //
  783.         // o NeutralCultures
  784.         // Enumerate neutral custom and framework cultures.
  785.         //
  786.         // o SpecificCultures
  787.         // Enumerate specific custom and framework cultures. Also it includes the synthetic cultures.
  788.         //
  789.         // o InstalledWin32Cultures
  790.         // It enumerates the replacement cultures, framework culture, and synthetic cultures that are installed in the OS too.
  791.         //
  792.         // o UserCustomCulture
  793.         // It enumerates all custom cultures.
  794.         //
  795.         // o ReplacementCultures
  796.         // It enumerates all replacement custom cultures.
  797.         //
  798.         // o WindowsOnlyCultures
  799.         // It enumerates all synthetic and replacement synthetic cultures.
  800.         //
  801.         // o FrameworkCultures
  802.         // It enumerates all framework and replacement framework cultures.
  803.         //
  804.         // o AllCultures
  805.         // It enumerates all cultures.
  806.         //
  807.         [ResourceExposure(ResourceScope.None)]
  808.         [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
  809.         unsafe internal CultureInfo[] GetCultures(CultureTypes types)
  810.         {
  811.             if ((int)types <= 0 || ((int)types & (int)CultureTypesMask) != 0) {
  812.                 throw new ArgumentOutOfRangeException("types", String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("ArgumentOutOfRange_Range"), CultureTypes.NeutralCultures, CultureTypes.FrameworkCultures));
  813.             }
  814.            
  815.             ArrayList cultures = new ArrayList();
  816.            
  817.             bool isAddSpecific = ((types & CultureTypes.SpecificCultures) != 0);
  818.             bool isAddNeutral = ((types & CultureTypes.NeutralCultures) != 0);
  819.             bool isAddInstalled = ((types & CultureTypes.InstalledWin32Cultures) != 0);
  820.             bool isAddUserCustom = ((types & CultureTypes.UserCustomCulture) != 0);
  821.             bool isAddReplacement = ((types & CultureTypes.ReplacementCultures) != 0);
  822.             bool isAddFramework = ((types & CultureTypes.FrameworkCultures) != 0);
  823.             bool isAddWindowsOnly = ((types & CultureTypes.WindowsOnlyCultures) != 0);
  824.            
  825.            
  826.             if (isAddNeutral || isAddSpecific || isAddFramework || isAddInstalled) {
  827.                 for (int i = 0; i < m_pCultureHeader->numCultureNames; i++) {
  828.                     int cultureID = this.m_pCultureIDIndex[i].actualCultureID;
  829.                    
  830.                     if (CultureInfo.GetSortID(cultureID) != 0 || cultureID == CultureTableRecord.SPANISH_TRADITIONAL_SORT) {
  831.                         //
  832.                         // This is an alternate sort culture. For now, do nothing.
  833.                         // Eventually we may add a new CultureTypes flag.
  834.                         //
  835.                     }
  836.                     else {
  837.                         CultureInfo ci = new CultureInfo(cultureID);
  838.                         CultureTypes ciTypes = ci.CultureTypes;
  839.                         //
  840.                         // Invariant culture (ci.Name.Length = 0) will be returned with the Neutral cultures enumeration.
  841.                         // and will not be returned from specific cultures enumeration.
  842.                         //
  843.                        
  844.                         if (((ciTypes & CultureTypes.ReplacementCultures) == 0) && (isAddFramework || (isAddSpecific && ci.Name.Length > 0 && ((ciTypes & CultureTypes.SpecificCultures) != 0)) || (isAddNeutral && (((ciTypes & CultureTypes.NeutralCultures) != 0) || ci.Name.Length == 0)) || (isAddInstalled && ((ciTypes & CultureTypes.InstalledWin32Cultures) != 0))))
  845.                            
  846.                             cultures.Add(ci);
  847.                     }
  848.                 }
  849.             }
  850.            
  851.            
  852.             CultureInfo[] result = new CultureInfo[cultures.Count];
  853.             cultures.CopyTo(result, 0);
  854.             return (result);
  855.         }
  856.     }
  857.     // CultureTable class
  858.     // internal class for hashing culture table items (LCID/data item)
  859.     // Used since the dataItem's LANGID may not account for the additional
  860.     // sort ID information that may be needed.
  861.     internal class CultureTableItem
  862.     {
  863.         internal int dataItem;
  864.         internal int culture;
  865.         internal string name;
  866.     }
  867.    
  868. /*=============================================================================
  869.     *
  870.     * The native struct of a record in the Culture ID Offset Table.
  871.     * Every instance of this class will be mapped to a memory address in the native side.
  872.     * The memory address is memory mapped from culture.nlp.
  873.     *
  874.     * Every primary language will have its corresponding IDOffset record.  From the data
  875.     * in IDOffset, we can get the index which points to a record in Culture Data Table for
  876.     * a given culture ID.
  877.     *
  878.     * Used by GetDataItem(int cultureID) to retrieve the InternalDataItem for a given
  879.     * culture ID.
  880.     ==============================================================================*/   
  881.    
  882.     [StructLayout(LayoutKind.Sequential)]
  883.     internal struct IDOffsetItem
  884.     {
  885.         // DWORD: the LCID value to be used with the name
  886.         internal int actualCultureID;
  887.         // WORD: Index which points to a record in Culture Data Table (InternalDataItem*) for a primary language.
  888.         internal ushort dataItemIndex;
  889.         // WORD: Offset (in words) to a string in the String Pool Table.
  890.         internal ushort strOffset;
  891.     }
  892.    
  893. /*=============================================================================
  894.     **
  895.     ** The native struct of a record in the Culture Name Offset Table.
  896.     ** Every instance of this class will be mapped to a memory address in the native side.
  897.     ** The memory address is memory mapped from culture.nlp.
  898.     **
  899.     ** Every culture name will have its corresponding NameOffset record.  From the data
  900.     ** in NameOffset, we can get the index which points to a record in the Cutlure Data Table
  901.     ** for a given culture name.
  902.     **
  903.     ** Used by GetDataItem(String name) to retrieve the InteralDataItem for a given
  904.     ** culture name.
  905.     ==============================================================================*/   
  906.    
  907.     [StructLayout(LayoutKind.Sequential)]
  908.     internal struct CultureNameOffsetItem
  909.     {
  910.         // WORD: Offset (in words) to a string in the String Pool Table.
  911.         internal ushort strOffset;
  912.         // WORD: Index to a record in Culture Data Table.
  913.         internal ushort dataItemIndex;
  914.         // DWORD: the LCID value to be used with the name
  915.         internal int actualCultureID;
  916.     }
  917.    
  918.     [StructLayout(LayoutKind.Sequential)]
  919.     internal struct RegionNameOffsetItem
  920.     {
  921.         // WORD: Offset (in words) to a string in the String Pool Table.
  922.         internal ushort strOffset;
  923.         // WORD: Index to a record in Culture Data Table.
  924.         internal ushort dataItemIndex;
  925.     }
  926.    
  927.     [StructLayout(LayoutKind.Sequential)]
  928.     internal struct IetfNameOffsetItem
  929.     {
  930.         // WORD: Offset (in words) to an ietf name string in the String Pool Table.
  931.         internal ushort strIetfNameOffset;
  932.         // WORD: Offset (in words) to a culture name string in the String Pool Table.
  933.         internal ushort strCultureNameOffset;
  934.     }
  935. }

Developer Fusion