summaryrefslogtreecommitdiff
path: root/src/mscorlib/corefx
diff options
context:
space:
mode:
authorJiyoung Yun <jy910.yun@samsung.com>2016-11-23 19:09:09 +0900
committerJiyoung Yun <jy910.yun@samsung.com>2016-11-23 19:09:09 +0900
commit4b4aad7217d3292650e77eec2cf4c198ea9c3b4b (patch)
tree98110734c91668dfdbb126fcc0e15ddbd93738ca /src/mscorlib/corefx
parentfa45f57ed55137c75ac870356a1b8f76c84b229c (diff)
downloadcoreclr-4b4aad7217d3292650e77eec2cf4c198ea9c3b4b.tar.gz
coreclr-4b4aad7217d3292650e77eec2cf4c198ea9c3b4b.tar.bz2
coreclr-4b4aad7217d3292650e77eec2cf4c198ea9c3b4b.zip
Imported Upstream version 1.1.0upstream/1.1.0
Diffstat (limited to 'src/mscorlib/corefx')
-rw-r--r--src/mscorlib/corefx/Interop/Unix/Interop.Libraries.cs11
-rw-r--r--src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.Calendar.cs33
-rw-r--r--src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.Casing.cs26
-rw-r--r--src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.Collation.cs79
-rw-r--r--src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.Locale.cs37
-rw-r--r--src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.ResultCode.cs17
-rw-r--r--src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.TimeZoneInfo.cs31
-rw-r--r--src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.Utils.cs52
-rw-r--r--src/mscorlib/corefx/SR.cs247
-rw-r--r--src/mscorlib/corefx/System/Globalization/Calendar.cs854
-rw-r--r--src/mscorlib/corefx/System/Globalization/CalendarData.Unix.cs341
-rw-r--r--src/mscorlib/corefx/System/Globalization/CalendarData.Windows.cs469
-rw-r--r--src/mscorlib/corefx/System/Globalization/CalendarData.cs381
-rw-r--r--src/mscorlib/corefx/System/Globalization/CalendarWeekRule.cs19
-rw-r--r--src/mscorlib/corefx/System/Globalization/CalendricalCalculationsHelper.cs413
-rw-r--r--src/mscorlib/corefx/System/Globalization/CharUnicodeInfo.cs339
-rw-r--r--src/mscorlib/corefx/System/Globalization/CharUnicodeInfoData.cs1222
-rw-r--r--src/mscorlib/corefx/System/Globalization/ChineseLunisolarCalendar.cs399
-rw-r--r--src/mscorlib/corefx/System/Globalization/CompareInfo.Unix.cs315
-rw-r--r--src/mscorlib/corefx/System/Globalization/CompareInfo.Windows.cs395
-rw-r--r--src/mscorlib/corefx/System/Globalization/CompareInfo.cs925
-rw-r--r--src/mscorlib/corefx/System/Globalization/CultureData.Unix.cs304
-rw-r--r--src/mscorlib/corefx/System/Globalization/CultureData.Windows.cs561
-rw-r--r--src/mscorlib/corefx/System/Globalization/CultureData.cs2174
-rw-r--r--src/mscorlib/corefx/System/Globalization/CultureInfo.Unix.cs31
-rw-r--r--src/mscorlib/corefx/System/Globalization/CultureInfo.Windows.cs53
-rw-r--r--src/mscorlib/corefx/System/Globalization/CultureInfo.cs1144
-rw-r--r--src/mscorlib/corefx/System/Globalization/CultureNotFoundException.cs104
-rw-r--r--src/mscorlib/corefx/System/Globalization/DateTimeFormatInfo.cs2958
-rw-r--r--src/mscorlib/corefx/System/Globalization/DateTimeFormatInfoScanner.cs742
-rw-r--r--src/mscorlib/corefx/System/Globalization/DayLightTime.cs56
-rw-r--r--src/mscorlib/corefx/System/Globalization/EastAsianLunisolarCalendar.cs719
-rw-r--r--src/mscorlib/corefx/System/Globalization/GregorianCalendar.cs662
-rw-r--r--src/mscorlib/corefx/System/Globalization/GregorianCalendarHelper.cs668
-rw-r--r--src/mscorlib/corefx/System/Globalization/GregorianCalendarTypes.cs21
-rw-r--r--src/mscorlib/corefx/System/Globalization/HebrewCalendar.cs1123
-rw-r--r--src/mscorlib/corefx/System/Globalization/HebrewNumber.cs465
-rw-r--r--src/mscorlib/corefx/System/Globalization/HijriCalendar.Unix.cs15
-rw-r--r--src/mscorlib/corefx/System/Globalization/HijriCalendar.Windows.cs16
-rw-r--r--src/mscorlib/corefx/System/Globalization/HijriCalendar.cs675
-rw-r--r--src/mscorlib/corefx/System/Globalization/InternalGlobalizationHelper.cs50
-rw-r--r--src/mscorlib/corefx/System/Globalization/JapaneseCalendar.Unix.cs91
-rw-r--r--src/mscorlib/corefx/System/Globalization/JapaneseCalendar.Windows.cs62
-rw-r--r--src/mscorlib/corefx/System/Globalization/JapaneseCalendar.cs413
-rw-r--r--src/mscorlib/corefx/System/Globalization/JapaneseLunisolarCalendar.cs311
-rw-r--r--src/mscorlib/corefx/System/Globalization/JulianCalendar.cs452
-rw-r--r--src/mscorlib/corefx/System/Globalization/KoreanCalendar.cs264
-rw-r--r--src/mscorlib/corefx/System/Globalization/KoreanLunisolarCalendar.cs1329
-rw-r--r--src/mscorlib/corefx/System/Globalization/NumberFormatInfo.cs819
-rw-r--r--src/mscorlib/corefx/System/Globalization/PersianCalendar.cs613
-rw-r--r--src/mscorlib/corefx/System/Globalization/RegionInfo.cs324
-rw-r--r--src/mscorlib/corefx/System/Globalization/STUBS.cs180
-rw-r--r--src/mscorlib/corefx/System/Globalization/StringInfo.cs322
-rw-r--r--src/mscorlib/corefx/System/Globalization/TaiwanCalendar.cs282
-rw-r--r--src/mscorlib/corefx/System/Globalization/TaiwanLunisolarCalendar.cs330
-rw-r--r--src/mscorlib/corefx/System/Globalization/TextElementEnumerator.cs154
-rw-r--r--src/mscorlib/corefx/System/Globalization/TextInfo.Unix.cs127
-rw-r--r--src/mscorlib/corefx/System/Globalization/TextInfo.Windows.cs121
-rw-r--r--src/mscorlib/corefx/System/Globalization/TextInfo.cs457
-rw-r--r--src/mscorlib/corefx/System/Globalization/ThaiBuddhistCalendar.cs233
-rw-r--r--src/mscorlib/corefx/System/Globalization/TimeSpanStyles.cs13
-rw-r--r--src/mscorlib/corefx/System/Globalization/UmAlQuraCalendar.cs862
-rw-r--r--src/mscorlib/corefx/System/Globalization/UnicodeCategory.cs70
63 files changed, 26975 insertions, 0 deletions
diff --git a/src/mscorlib/corefx/Interop/Unix/Interop.Libraries.cs b/src/mscorlib/corefx/Interop/Unix/Interop.Libraries.cs
new file mode 100644
index 0000000000..f8c5b26e44
--- /dev/null
+++ b/src/mscorlib/corefx/Interop/Unix/Interop.Libraries.cs
@@ -0,0 +1,11 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+internal static partial class Interop
+{
+ private static partial class Libraries
+ {
+ internal const string GlobalizationInterop = "System.Globalization.Native"; // CoreFX wrappers for ICU
+ }
+}
diff --git a/src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.Calendar.cs b/src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.Calendar.cs
new file mode 100644
index 0000000000..7b3caeabdd
--- /dev/null
+++ b/src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.Calendar.cs
@@ -0,0 +1,33 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Globalization;
+using System.Runtime.InteropServices;
+using System.Text;
+
+internal static partial class Interop
+{
+ internal static partial class GlobalizationInterop
+ {
+ internal delegate void EnumCalendarInfoCallback(
+ [MarshalAs(UnmanagedType.LPWStr)] string calendarString,
+ IntPtr context);
+
+ [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetCalendars")]
+ internal static extern int GetCalendars(string localeName, CalendarId[] calendars, int calendarsCapacity);
+
+ [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetCalendarInfo")]
+ internal static extern ResultCode GetCalendarInfo(string localeName, CalendarId calendarId, CalendarDataType calendarDataType, [Out] StringBuilder result, int resultCapacity);
+
+ [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_EnumCalendarInfo")]
+ internal static extern bool EnumCalendarInfo(EnumCalendarInfoCallback callback, string localeName, CalendarId calendarId, CalendarDataType calendarDataType, IntPtr context);
+
+ [DllImport(Libraries.GlobalizationInterop, EntryPoint = "GlobalizationNative_GetLatestJapaneseEra")]
+ internal static extern int GetLatestJapaneseEra();
+
+ [DllImport(Libraries.GlobalizationInterop, EntryPoint = "GlobalizationNative_GetJapaneseEraStartDate")]
+ internal static extern bool GetJapaneseEraStartDate(int era, out int startYear, out int startMonth, out int startDay);
+ }
+}
diff --git a/src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.Casing.cs b/src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.Casing.cs
new file mode 100644
index 0000000000..115a8393be
--- /dev/null
+++ b/src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.Casing.cs
@@ -0,0 +1,26 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+using System.Security;
+using System.Text;
+
+internal static partial class Interop
+{
+ internal static partial class GlobalizationInterop
+ {
+ [SecurityCritical]
+ [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_ChangeCase")]
+ internal unsafe static extern void ChangeCase(char* src, int srcLen, char* dstBuffer, int dstBufferCapacity, bool bToUpper);
+
+ [SecurityCritical]
+ [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_ChangeCaseInvariant")]
+ internal unsafe static extern void ChangeCaseInvariant(char* src, int srcLen, char* dstBuffer, int dstBufferCapacity, bool bToUpper);
+
+ [SecurityCritical]
+ [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_ChangeCaseTurkish")]
+ internal unsafe static extern void ChangeCaseTurkish(char* src, int srcLen, char* dstBuffer, int dstBufferCapacity, bool bToUpper);
+ }
+}
diff --git a/src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.Collation.cs b/src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.Collation.cs
new file mode 100644
index 0000000000..6acf55e17b
--- /dev/null
+++ b/src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.Collation.cs
@@ -0,0 +1,79 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Globalization;
+using System.Runtime.InteropServices;
+using System.Security;
+
+internal static partial class Interop
+{
+ internal static partial class GlobalizationInterop
+ {
+ [SecurityCritical]
+ [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetSortHandle")]
+ internal unsafe static extern SafeSortHandle GetSortHandle(byte[] localeName);
+
+ [SecurityCritical]
+ [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_CloseSortHandle")]
+ internal unsafe static extern void CloseSortHandle(IntPtr handle);
+
+ [SecurityCritical]
+ [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_CompareString")]
+ internal unsafe static extern int CompareString(SafeSortHandle sortHandle, char* lpStr1, int cwStr1Len, char* lpStr2, int cwStr2Len, CompareOptions options);
+
+ [SecurityCritical]
+ [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_IndexOf")]
+ internal unsafe static extern int IndexOf(SafeSortHandle sortHandle, string target, int cwTargetLength, char* pSource, int cwSourceLength, CompareOptions options);
+
+ [SecurityCritical]
+ [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_LastIndexOf")]
+ internal unsafe static extern int LastIndexOf(SafeSortHandle sortHandle, string target, int cwTargetLength, char* pSource, int cwSourceLength, CompareOptions options);
+
+ [SecurityCritical]
+ [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_IndexOfOrdinalIgnoreCase")]
+ internal unsafe static extern int IndexOfOrdinalIgnoreCase(string target, int cwTargetLength, char* pSource, int cwSourceLength, bool findLast);
+
+ [SecurityCritical]
+ [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_StartsWith")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal unsafe static extern bool StartsWith(SafeSortHandle sortHandle, string target, int cwTargetLength, string source, int cwSourceLength, CompareOptions options);
+
+ [SecurityCritical]
+ [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_EndsWith")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal unsafe static extern bool EndsWith(SafeSortHandle sortHandle, string target, int cwTargetLength, string source, int cwSourceLength, CompareOptions options);
+
+ [SecurityCritical]
+ [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetSortKey")]
+ internal unsafe static extern int GetSortKey(SafeSortHandle sortHandle, string str, int strLength, byte* sortKey, int sortKeyLength, CompareOptions options);
+
+ [SecurityCritical]
+ [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_CompareStringOrdinalIgnoreCase")]
+ internal unsafe static extern int CompareStringOrdinalIgnoreCase(char* lpStr1, int cwStr1Len, char* lpStr2, int cwStr2Len);
+
+ [SecurityCritical]
+ internal class SafeSortHandle : SafeHandle
+ {
+ private SafeSortHandle() :
+ base(IntPtr.Zero, true)
+ {
+ }
+
+ public override bool IsInvalid
+ {
+ [SecurityCritical]
+ get { return handle == IntPtr.Zero; }
+ }
+
+ [SecurityCritical]
+ protected override bool ReleaseHandle()
+ {
+ CloseSortHandle(handle);
+ SetHandle(IntPtr.Zero);
+ return true;
+ }
+ }
+ }
+}
diff --git a/src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.Locale.cs b/src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.Locale.cs
new file mode 100644
index 0000000000..3912581c73
--- /dev/null
+++ b/src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.Locale.cs
@@ -0,0 +1,37 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+using System.Text;
+
+internal static partial class Interop
+{
+ internal static partial class GlobalizationInterop
+ {
+ [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetLocaleName")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal unsafe static extern bool GetLocaleName(string localeName, [Out] StringBuilder value, int valueLength);
+
+ [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetLocaleInfoString")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal unsafe static extern bool GetLocaleInfoString(string localeName, uint localeStringData, [Out] StringBuilder value, int valueLength);
+
+ [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetDefaultLocaleName")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal unsafe static extern bool GetDefaultLocaleName([Out] StringBuilder value, int valueLength);
+
+ [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetLocaleTimeFormat")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal unsafe static extern bool GetLocaleTimeFormat(string localeName, bool shortFormat, [Out] StringBuilder value, int valueLength);
+
+ [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetLocaleInfoInt")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal unsafe static extern bool GetLocaleInfoInt(string localeName, uint localeNumberData, ref int value);
+
+ [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetLocaleInfoGroupingSizes")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal unsafe static extern bool GetLocaleInfoGroupingSizes(string localeName, uint localeGroupingData, ref int primaryGroupSize, ref int secondaryGroupSize);
+ }
+}
diff --git a/src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.ResultCode.cs b/src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.ResultCode.cs
new file mode 100644
index 0000000000..4621580063
--- /dev/null
+++ b/src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.ResultCode.cs
@@ -0,0 +1,17 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+internal static partial class Interop
+{
+ internal static partial class GlobalizationInterop
+ {
+ // needs to be kept in sync with ResultCode in System.Globalization.Native
+ internal enum ResultCode
+ {
+ Success = 0,
+ UnknownError = 1,
+ InsufficentBuffer = 2,
+ }
+ }
+}
diff --git a/src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.TimeZoneInfo.cs b/src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.TimeZoneInfo.cs
new file mode 100644
index 0000000000..26a9fe0579
--- /dev/null
+++ b/src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.TimeZoneInfo.cs
@@ -0,0 +1,31 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.InteropServices;
+using System.Text;
+
+internal static partial class Interop
+{
+ internal static partial class GlobalizationInterop
+ {
+ [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Ansi, EntryPoint = "GlobalizationNative_ReadLink")] // readlink requires char*
+ internal static extern bool ReadLink(string filePath, [Out] StringBuilder result, uint resultCapacity);
+
+ // needs to be kept in sync with TimeZoneDisplayNameType in System.Globalization.Native
+ internal enum TimeZoneDisplayNameType
+ {
+ Generic = 0,
+ Standard = 1,
+ DaylightSavings = 2,
+ }
+
+ [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetTimeZoneDisplayName")]
+ internal static extern ResultCode GetTimeZoneDisplayName(
+ string localeName,
+ string timeZoneId,
+ TimeZoneDisplayNameType type,
+ [Out] StringBuilder result,
+ int resultLength);
+ }
+}
diff --git a/src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.Utils.cs b/src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.Utils.cs
new file mode 100644
index 0000000000..33b10c0d74
--- /dev/null
+++ b/src/mscorlib/corefx/Interop/Unix/System.Globalization.Native/Interop.Utils.cs
@@ -0,0 +1,52 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Text;
+
+internal static partial class Interop
+{
+ /// <summary>
+ /// Helper for making interop calls that return a string, but we don't know
+ /// the correct size of buffer to make. So invoke the interop call with an
+ /// increasing buffer until the size is big enough.
+ /// </summary>
+ internal static bool CallStringMethod<TArg1, TArg2, TArg3>(
+ Func<TArg1, TArg2, TArg3, StringBuilder, GlobalizationInterop.ResultCode> interopCall,
+ TArg1 arg1,
+ TArg2 arg2,
+ TArg3 arg3,
+ out string result)
+ {
+ const int initialStringSize = 80;
+ const int maxDoubleAttempts = 5;
+
+ StringBuilder stringBuilder = StringBuilderCache.Acquire(initialStringSize);
+
+ for (int i = 0; i < maxDoubleAttempts; i++)
+ {
+ GlobalizationInterop.ResultCode resultCode = interopCall(arg1, arg2, arg3, stringBuilder);
+
+ if (resultCode == GlobalizationInterop.ResultCode.Success)
+ {
+ result = StringBuilderCache.GetStringAndRelease(stringBuilder);
+ return true;
+ }
+ else if (resultCode == GlobalizationInterop.ResultCode.InsufficentBuffer)
+ {
+ // increase the string size and loop
+ stringBuilder.EnsureCapacity(stringBuilder.Capacity * 2);
+ }
+ else
+ {
+ // if there is an unknown error, don't proceed
+ break;
+ }
+ }
+
+ StringBuilderCache.Release(stringBuilder);
+ result = null;
+ return false;
+ }
+}
diff --git a/src/mscorlib/corefx/SR.cs b/src/mscorlib/corefx/SR.cs
new file mode 100644
index 0000000000..513bd9d94d
--- /dev/null
+++ b/src/mscorlib/corefx/SR.cs
@@ -0,0 +1,247 @@
+using System;
+
+namespace System.Globalization
+{
+ internal static class SR
+ {
+ public static string Arg_HexStyleNotSupported
+ {
+ get { return Environment.GetResourceString("Arg_HexStyleNotSupported"); }
+ }
+
+ public static string Arg_InvalidHexStyle
+ {
+ get { return Environment.GetResourceString("Arg_InvalidHexStyle"); }
+ }
+
+ public static string ArgumentNull_Array
+ {
+ get { return Environment.GetResourceString("ArgumentNull_Array"); }
+ }
+
+ public static string ArgumentNull_ArrayValue
+ {
+ get { return Environment.GetResourceString("ArgumentNull_ArrayValue"); }
+ }
+
+ public static string ArgumentNull_Obj
+ {
+ get { return Environment.GetResourceString("ArgumentNull_Obj"); }
+ }
+
+ public static string ArgumentNull_String
+ {
+ get { return Environment.GetResourceString("ArgumentNull_String"); }
+ }
+
+ public static string ArgumentOutOfRange_AddValue
+ {
+ get { return Environment.GetResourceString("ArgumentOutOfRange_AddValue"); }
+ }
+
+ public static string ArgumentOutOfRange_BadHourMinuteSecond
+ {
+ get { return Environment.GetResourceString("ArgumentOutOfRange_BadHourMinuteSecond"); }
+ }
+
+ public static string ArgumentOutOfRange_BadYearMonthDay
+ {
+ get { return Environment.GetResourceString("ArgumentOutOfRange_BadYearMonthDay"); }
+ }
+
+ public static string ArgumentOutOfRange_Bounds_Lower_Upper
+ {
+ get { return Environment.GetResourceString("ArgumentOutOfRange_Bounds_Lower_Upper"); }
+ }
+
+ public static string ArgumentOutOfRange_CalendarRange
+ {
+ get { return Environment.GetResourceString("ArgumentOutOfRange_CalendarRange"); }
+ }
+
+ public static string ArgumentOutOfRange_Count
+ {
+ get { return Environment.GetResourceString("ArgumentOutOfRange_Count"); }
+ }
+
+ public static string ArgumentOutOfRange_Day
+ {
+ get { return Environment.GetResourceString("ArgumentOutOfRange_Day"); }
+ }
+
+ public static string ArgumentOutOfRange_Enum
+ {
+ get { return Environment.GetResourceString("ArgumentOutOfRange_Enum"); }
+ }
+
+ public static string ArgumentOutOfRange_Era
+ {
+ get { return Environment.GetResourceString("ArgumentOutOfRange_Era"); }
+ }
+
+ public static string ArgumentOutOfRange_Index
+ {
+ get { return Environment.GetResourceString("ArgumentOutOfRange_Index"); }
+ }
+
+ public static string ArgumentOutOfRange_InvalidEraValue
+ {
+ get { return Environment.GetResourceString("ArgumentOutOfRange_InvalidEraValue"); }
+ }
+
+ public static string ArgumentOutOfRange_Month
+ {
+ get { return Environment.GetResourceString("ArgumentOutOfRange_Month"); }
+ }
+
+ public static string ArgumentOutOfRange_NeedNonNegNum
+ {
+ get { return Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"); }
+ }
+
+ public static string ArgumentOutOfRange_NeedPosNum
+ {
+ get { return Environment.GetResourceString("ArgumentOutOfRange_NeedPosNum"); }
+ }
+
+ public static string ArgumentOutOfRange_OffsetLength
+ {
+ get { return Environment.GetResourceString("ArgumentOutOfRange_OffsetLength"); }
+ }
+
+ public static string ArgumentOutOfRange_Range
+ {
+ get { return Environment.GetResourceString("ArgumentOutOfRange_Range"); }
+ }
+
+ public static string Argument_CompareOptionOrdinal
+ {
+ get { return Environment.GetResourceString("Argument_CompareOptionOrdinal"); }
+ }
+
+ public static string Argument_ConflictingDateTimeRoundtripStyles
+ {
+ get { return Environment.GetResourceString("Argument_ConflictingDateTimeRoundtripStyles"); }
+ }
+
+ public static string Argument_ConflictingDateTimeStyles
+ {
+ get { return Environment.GetResourceString("Argument_ConflictingDateTimeStyles"); }
+ }
+
+ public static string Argument_CultureInvalidIdentifier
+ {
+ get { return Environment.GetResourceString("Argument_CultureInvalidIdentifier"); }
+ }
+
+ public static string Argument_CultureNotSupported
+ {
+ get { return Environment.GetResourceString("Argument_CultureNotSupported"); }
+ }
+
+ public static string Argument_EmptyDecString
+ {
+ get { return Environment.GetResourceString("Argument_EmptyDecString"); }
+ }
+
+ public static string Argument_InvalidArrayLength
+ {
+ get { return Environment.GetResourceString("Argument_InvalidArrayLength"); }
+ }
+
+ public static string Argument_InvalidCalendar
+ {
+ get { return Environment.GetResourceString("Argument_InvalidCalendar"); }
+ }
+
+ public static string Argument_InvalidCultureName
+ {
+ get { return Environment.GetResourceString("Argument_InvalidCultureName"); }
+ }
+
+ public static string Argument_InvalidDateTimeStyles
+ {
+ get { return Environment.GetResourceString("Argument_InvalidDateTimeStyles"); }
+ }
+
+ public static string Argument_InvalidFlag
+ {
+ get { return Environment.GetResourceString("Argument_InvalidFlag"); }
+ }
+
+ public static string Argument_InvalidGroupSize
+ {
+ get { return Environment.GetResourceString("Argument_InvalidGroupSize"); }
+ }
+
+ public static string Argument_InvalidNeutralRegionName
+ {
+ get { return Environment.GetResourceString("Argument_InvalidNeutralRegionName"); }
+ }
+
+ public static string Argument_InvalidNumberStyles
+ {
+ get { return Environment.GetResourceString("Argument_InvalidNumberStyles"); }
+ }
+
+ public static string Argument_InvalidResourceCultureName
+ {
+ get { return Environment.GetResourceString("Argument_InvalidResourceCultureName"); }
+ }
+
+ public static string Argument_NoEra
+ {
+ get { return Environment.GetResourceString("Argument_NoEra"); }
+ }
+
+ public static string Argument_NoRegionInvariantCulture
+ {
+ get { return Environment.GetResourceString("Argument_NoRegionInvariantCulture"); }
+ }
+
+ public static string Argument_ResultCalendarRange
+ {
+ get { return Environment.GetResourceString("Argument_ResultCalendarRange"); }
+ }
+
+ public static string Format_BadFormatSpecifier
+ {
+ get { return Environment.GetResourceString("Format_BadFormatSpecifier"); }
+ }
+
+ public static string InvalidOperation_DateTimeParsing
+ {
+ get { return Environment.GetResourceString("InvalidOperation_DateTimeParsing"); }
+ }
+
+ public static string InvalidOperation_EnumEnded
+ {
+ get { return Environment.GetResourceString("InvalidOperation_EnumEnded"); }
+ }
+
+ public static string InvalidOperation_EnumNotStarted
+ {
+ get { return Environment.GetResourceString("InvalidOperation_EnumNotStarted"); }
+ }
+
+ public static string InvalidOperation_ReadOnly
+ {
+ get { return Environment.GetResourceString("InvalidOperation_ReadOnly"); }
+ }
+
+ public static string Overflow_TimeSpanTooLong
+ {
+ get { return Environment.GetResourceString("Overflow_TimeSpanTooLong"); }
+ }
+
+ public static string Serialization_MemberOutOfRange
+ {
+ get { return Environment.GetResourceString("Serialization_MemberOutOfRange"); }
+ }
+
+ public static string Format(string formatString, params object[] args)
+ {
+ return string.Format(CultureInfo.CurrentCulture, formatString, args);
+ }
+ }
+}
diff --git a/src/mscorlib/corefx/System/Globalization/Calendar.cs b/src/mscorlib/corefx/System/Globalization/Calendar.cs
new file mode 100644
index 0000000000..343682d156
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/Calendar.cs
@@ -0,0 +1,854 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.CompilerServices;
+using System.Globalization;
+using System.Diagnostics.Contracts;
+using System.Runtime.Serialization;
+
+namespace System.Globalization
+{
+ // This abstract class represents a calendar. A calendar reckons time in
+ // divisions such as weeks, months and years. The number, length and start of
+ // the divisions vary in each calendar.
+ //
+ // Any instant in time can be represented as an n-tuple of numeric values using
+ // a particular calendar. For example, the next vernal equinox occurs at (0.0, 0
+ // , 46, 8, 20, 3, 1999) in the Gregorian calendar. An implementation of
+ // Calendar can map any DateTime value to such an n-tuple and vice versa. The
+ // DateTimeFormat class can map between such n-tuples and a textual
+ // representation such as "8:46 AM March 20th 1999 AD".
+ //
+ // Most calendars identify a year which begins the current era. There may be any
+ // number of previous eras. The Calendar class identifies the eras as enumerated
+ // integers where the current era (CurrentEra) has the value zero.
+ //
+ // For consistency, the first unit in each interval, e.g. the first month, is
+ // assigned the value one.
+ // The calculation of hour/minute/second is moved to Calendar from GregorianCalendar,
+ // since most of the calendars (or all?) have the same way of calcuating hour/minute/second.
+
+ [Serializable]
+ [System.Runtime.InteropServices.ComVisible(true)]
+ public abstract partial class Calendar : ICloneable
+ {
+ // Number of 100ns (10E-7 second) ticks per time unit
+ internal const long TicksPerMillisecond = 10000;
+ internal const long TicksPerSecond = TicksPerMillisecond * 1000;
+ internal const long TicksPerMinute = TicksPerSecond * 60;
+ internal const long TicksPerHour = TicksPerMinute * 60;
+ internal const long TicksPerDay = TicksPerHour * 24;
+
+ // Number of milliseconds per time unit
+ internal const int MillisPerSecond = 1000;
+ internal const int MillisPerMinute = MillisPerSecond * 60;
+ internal const int MillisPerHour = MillisPerMinute * 60;
+ internal const int MillisPerDay = MillisPerHour * 24;
+
+ // Number of days in a non-leap year
+ internal const int DaysPerYear = 365;
+ // Number of days in 4 years
+ internal const int DaysPer4Years = DaysPerYear * 4 + 1;
+ // Number of days in 100 years
+ internal const int DaysPer100Years = DaysPer4Years * 25 - 1;
+ // Number of days in 400 years
+ internal const int DaysPer400Years = DaysPer100Years * 4 + 1;
+
+ // Number of days from 1/1/0001 to 1/1/10000
+ internal const int DaysTo10000 = DaysPer400Years * 25 - 366;
+
+ internal const long MaxMillis = (long)DaysTo10000 * MillisPerDay;
+
+
+ private int _currentEraValue = -1;
+
+ [OptionalField(VersionAdded = 2)]
+ private bool _isReadOnly = false;
+
+#if INSIDE_CLR
+ internal const CalendarId CAL_HEBREW = CalendarId.HEBREW;
+ internal const CalendarId CAL_HIJRI = CalendarId.HIJRI;
+ internal const CalendarId CAL_JAPAN = CalendarId.JAPAN;
+ internal const CalendarId CAL_JULIAN = CalendarId.JULIAN;
+ internal const CalendarId CAL_TAIWAN = CalendarId.TAIWAN;
+ internal const CalendarId CAL_UMALQURA = CalendarId.UMALQURA;
+ internal const CalendarId CAL_PERSIAN = CalendarId.PERSIAN;
+#endif
+
+ // The minimum supported DateTime range for the calendar.
+
+ [System.Runtime.InteropServices.ComVisible(false)]
+ public virtual DateTime MinSupportedDateTime
+ {
+ get
+ {
+ return (DateTime.MinValue);
+ }
+ }
+
+ // The maximum supported DateTime range for the calendar.
+
+ [System.Runtime.InteropServices.ComVisible(false)]
+ public virtual DateTime MaxSupportedDateTime
+ {
+ get
+ {
+ return (DateTime.MaxValue);
+ }
+ }
+
+
+
+
+ protected Calendar()
+ {
+ //Do-nothing constructor.
+ }
+
+ ///
+ // This can not be abstract, otherwise no one can create a subclass of Calendar.
+ //
+ internal virtual CalendarId ID
+ {
+ get
+ {
+ return CalendarId.UNINITIALIZED_VALUE;
+ }
+ }
+
+ ///
+ // Return the Base calendar ID for calendars that didn't have defined data in calendarData
+ //
+
+ internal virtual CalendarId BaseCalendarID
+ {
+ get { return ID; }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // IsReadOnly
+ //
+ // Detect if the object is readonly.
+ //
+ ////////////////////////////////////////////////////////////////////////
+ [System.Runtime.InteropServices.ComVisible(false)]
+ public bool IsReadOnly
+ {
+ get { return (_isReadOnly); }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Clone
+ //
+ // Is the implementation of ICloneable.
+ //
+ ////////////////////////////////////////////////////////////////////////
+ [System.Runtime.InteropServices.ComVisible(false)]
+ public virtual object Clone()
+ {
+ object o = MemberwiseClone();
+ ((Calendar)o).SetReadOnlyState(false);
+ return (o);
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // ReadOnly
+ //
+ // Create a cloned readonly instance or return the input one if it is
+ // readonly.
+ //
+ ////////////////////////////////////////////////////////////////////////
+ [System.Runtime.InteropServices.ComVisible(false)]
+ internal static Calendar ReadOnly(Calendar calendar)
+ {
+ if (calendar == null) { throw new ArgumentNullException("calendar"); }
+ Contract.EndContractBlock();
+ if (calendar.IsReadOnly) { return (calendar); }
+
+ Calendar clonedCalendar = (Calendar)(calendar.MemberwiseClone());
+ clonedCalendar.SetReadOnlyState(true);
+
+ return (clonedCalendar);
+ }
+
+ internal void VerifyWritable()
+ {
+ if (_isReadOnly)
+ {
+ throw new InvalidOperationException(SR.InvalidOperation_ReadOnly);
+ }
+ }
+
+ internal void SetReadOnlyState(bool readOnly)
+ {
+ _isReadOnly = readOnly;
+ }
+
+
+ /*=================================CurrentEraValue==========================
+ **Action: This is used to convert CurretEra(0) to an appropriate era value.
+ **Returns:
+ **Arguments:
+ **Exceptions:
+ **Notes:
+ ** The value is from calendar.nlp.
+ ============================================================================*/
+
+ internal virtual int CurrentEraValue
+ {
+ get
+ {
+ // The following code assumes that the current era value can not be -1.
+ if (_currentEraValue == -1)
+ {
+ Contract.Assert(BaseCalendarID != CalendarId.UNINITIALIZED_VALUE, "[Calendar.CurrentEraValue] Expected a real calendar ID");
+ _currentEraValue = CalendarData.GetCalendarData(BaseCalendarID).iCurrentEra;
+ }
+ return (_currentEraValue);
+ }
+ }
+
+ // The current era for a calendar.
+
+ public const int CurrentEra = 0;
+
+ internal int twoDigitYearMax = -1;
+
+ internal static void CheckAddResult(long ticks, DateTime minValue, DateTime maxValue)
+ {
+ if (ticks < minValue.Ticks || ticks > maxValue.Ticks)
+ {
+ throw new ArgumentException(
+ String.Format(CultureInfo.InvariantCulture, SR.Format(SR.Argument_ResultCalendarRange,
+ minValue, maxValue)));
+ }
+ Contract.EndContractBlock();
+ }
+
+ internal DateTime Add(DateTime time, double value, int scale)
+ {
+ // From ECMA CLI spec, Partition III, section 3.27:
+ //
+ // If overflow occurs converting a floating-point type to an integer, or if the floating-point value
+ // being converted to an integer is a NaN, the value returned is unspecified.
+ //
+ // Based upon this, this method should be performing the comparison against the double
+ // before attempting a cast. Otherwise, the result is undefined.
+ double tempMillis = (value * scale + (value >= 0 ? 0.5 : -0.5));
+ if (!((tempMillis > -(double)MaxMillis) && (tempMillis < (double)MaxMillis)))
+ {
+ throw new ArgumentOutOfRangeException("value", SR.ArgumentOutOfRange_AddValue);
+ }
+
+ long millis = (long)tempMillis;
+ long ticks = time.Ticks + millis * TicksPerMillisecond;
+ CheckAddResult(ticks, MinSupportedDateTime, MaxSupportedDateTime);
+ return (new DateTime(ticks));
+ }
+
+ // Returns the DateTime resulting from adding the given number of
+ // milliseconds to the specified DateTime. The result is computed by rounding
+ // the number of milliseconds given by value to the nearest integer,
+ // and adding that interval to the specified DateTime. The value
+ // argument is permitted to be negative.
+ //
+
+ public virtual DateTime AddMilliseconds(DateTime time, double milliseconds)
+ {
+ return (Add(time, milliseconds, 1));
+ }
+
+
+ // Returns the DateTime resulting from adding a fractional number of
+ // days to the specified DateTime. The result is computed by rounding the
+ // fractional number of days given by value to the nearest
+ // millisecond, and adding that interval to the specified DateTime. The
+ // value argument is permitted to be negative.
+ //
+
+ public virtual DateTime AddDays(DateTime time, int days)
+ {
+ return (Add(time, days, MillisPerDay));
+ }
+
+ // Returns the DateTime resulting from adding a fractional number of
+ // hours to the specified DateTime. The result is computed by rounding the
+ // fractional number of hours given by value to the nearest
+ // millisecond, and adding that interval to the specified DateTime. The
+ // value argument is permitted to be negative.
+ //
+
+ public virtual DateTime AddHours(DateTime time, int hours)
+ {
+ return (Add(time, hours, MillisPerHour));
+ }
+
+
+ // Returns the DateTime resulting from adding a fractional number of
+ // minutes to the specified DateTime. The result is computed by rounding the
+ // fractional number of minutes given by value to the nearest
+ // millisecond, and adding that interval to the specified DateTime. The
+ // value argument is permitted to be negative.
+ //
+
+ public virtual DateTime AddMinutes(DateTime time, int minutes)
+ {
+ return (Add(time, minutes, MillisPerMinute));
+ }
+
+
+ // Returns the DateTime resulting from adding the given number of
+ // months to the specified DateTime. The result is computed by incrementing
+ // (or decrementing) the year and month parts of the specified DateTime by
+ // value months, and, if required, adjusting the day part of the
+ // resulting date downwards to the last day of the resulting month in the
+ // resulting year. The time-of-day part of the result is the same as the
+ // time-of-day part of the specified DateTime.
+ //
+ // In more precise terms, considering the specified DateTime to be of the
+ // form y / m / d + t, where y is the
+ // year, m is the month, d is the day, and t is the
+ // time-of-day, the result is y1 / m1 / d1 + t,
+ // where y1 and m1 are computed by adding value months
+ // to y and m, and d1 is the largest value less than
+ // or equal to d that denotes a valid day in month m1 of year
+ // y1.
+ //
+
+ public abstract DateTime AddMonths(DateTime time, int months);
+
+ // Returns the DateTime resulting from adding a number of
+ // seconds to the specified DateTime. The result is computed by rounding the
+ // fractional number of seconds given by value to the nearest
+ // millisecond, and adding that interval to the specified DateTime. The
+ // value argument is permitted to be negative.
+ //
+
+ public virtual DateTime AddSeconds(DateTime time, int seconds)
+ {
+ return Add(time, seconds, MillisPerSecond);
+ }
+
+ // Returns the DateTime resulting from adding a number of
+ // weeks to the specified DateTime. The
+ // value argument is permitted to be negative.
+ //
+
+ public virtual DateTime AddWeeks(DateTime time, int weeks)
+ {
+ return (AddDays(time, weeks * 7));
+ }
+
+
+ // Returns the DateTime resulting from adding the given number of
+ // years to the specified DateTime. The result is computed by incrementing
+ // (or decrementing) the year part of the specified DateTime by value
+ // years. If the month and day of the specified DateTime is 2/29, and if the
+ // resulting year is not a leap year, the month and day of the resulting
+ // DateTime becomes 2/28. Otherwise, the month, day, and time-of-day
+ // parts of the result are the same as those of the specified DateTime.
+ //
+
+ public abstract DateTime AddYears(DateTime time, int years);
+
+ // Returns the day-of-month part of the specified DateTime. The returned
+ // value is an integer between 1 and 31.
+ //
+
+ public abstract int GetDayOfMonth(DateTime time);
+
+ // Returns the day-of-week part of the specified DateTime. The returned value
+ // is an integer between 0 and 6, where 0 indicates Sunday, 1 indicates
+ // Monday, 2 indicates Tuesday, 3 indicates Wednesday, 4 indicates
+ // Thursday, 5 indicates Friday, and 6 indicates Saturday.
+ //
+
+ public abstract DayOfWeek GetDayOfWeek(DateTime time);
+
+ // Returns the day-of-year part of the specified DateTime. The returned value
+ // is an integer between 1 and 366.
+ //
+
+ public abstract int GetDayOfYear(DateTime time);
+
+ // Returns the number of days in the month given by the year and
+ // month arguments.
+ //
+
+ public virtual int GetDaysInMonth(int year, int month)
+ {
+ return (GetDaysInMonth(year, month, CurrentEra));
+ }
+
+ // Returns the number of days in the month given by the year and
+ // month arguments for the specified era.
+ //
+
+ public abstract int GetDaysInMonth(int year, int month, int era);
+
+ // Returns the number of days in the year given by the year argument for the current era.
+ //
+
+ public virtual int GetDaysInYear(int year)
+ {
+ return (GetDaysInYear(year, CurrentEra));
+ }
+
+ // Returns the number of days in the year given by the year argument for the current era.
+ //
+
+ public abstract int GetDaysInYear(int year, int era);
+
+ // Returns the era for the specified DateTime value.
+
+ public abstract int GetEra(DateTime time);
+
+ /*=================================Eras==========================
+ **Action: Get the list of era values.
+ **Returns: The int array of the era names supported in this calendar.
+ ** null if era is not used.
+ **Arguments: None.
+ **Exceptions: None.
+ ============================================================================*/
+
+
+ public abstract int[] Eras
+ {
+ get;
+ }
+
+
+ // Returns the hour part of the specified DateTime. The returned value is an
+ // integer between 0 and 23.
+ //
+
+ public virtual int GetHour(DateTime time)
+ {
+ return ((int)((time.Ticks / TicksPerHour) % 24));
+ }
+
+ // Returns the millisecond part of the specified DateTime. The returned value
+ // is an integer between 0 and 999.
+ //
+
+ public virtual double GetMilliseconds(DateTime time)
+ {
+ return (double)((time.Ticks / TicksPerMillisecond) % 1000);
+ }
+
+ // Returns the minute part of the specified DateTime. The returned value is
+ // an integer between 0 and 59.
+ //
+
+ public virtual int GetMinute(DateTime time)
+ {
+ return ((int)((time.Ticks / TicksPerMinute) % 60));
+ }
+
+ // Returns the month part of the specified DateTime. The returned value is an
+ // integer between 1 and 12.
+ //
+
+ public abstract int GetMonth(DateTime time);
+
+ // Returns the number of months in the specified year in the current era.
+
+ public virtual int GetMonthsInYear(int year)
+ {
+ return (GetMonthsInYear(year, CurrentEra));
+ }
+
+ // Returns the number of months in the specified year and era.
+
+ public abstract int GetMonthsInYear(int year, int era);
+
+ // Returns the second part of the specified DateTime. The returned value is
+ // an integer between 0 and 59.
+ //
+
+ public virtual int GetSecond(DateTime time)
+ {
+ return ((int)((time.Ticks / TicksPerSecond) % 60));
+ }
+
+ /*=================================GetFirstDayWeekOfYear==========================
+ **Action: Get the week of year using the FirstDay rule.
+ **Returns: the week of year.
+ **Arguments:
+ ** time
+ ** firstDayOfWeek the first day of week (0=Sunday, 1=Monday, ... 6=Saturday)
+ **Notes:
+ ** The CalendarWeekRule.FirstDay rule: Week 1 begins on the first day of the year.
+ ** Assume f is the specifed firstDayOfWeek,
+ ** and n is the day of week for January 1 of the specified year.
+ ** Assign offset = n - f;
+ ** Case 1: offset = 0
+ ** E.g.
+ ** f=1
+ ** weekday 0 1 2 3 4 5 6 0 1
+ ** date 1/1
+ ** week# 1 2
+ ** then week of year = (GetDayOfYear(time) - 1) / 7 + 1
+ **
+ ** Case 2: offset < 0
+ ** e.g.
+ ** n=1 f=3
+ ** weekday 0 1 2 3 4 5 6 0
+ ** date 1/1
+ ** week# 1 2
+ ** This means that the first week actually starts 5 days before 1/1.
+ ** So week of year = (GetDayOfYear(time) + (7 + offset) - 1) / 7 + 1
+ ** Case 3: offset > 0
+ ** e.g.
+ ** f=0 n=2
+ ** weekday 0 1 2 3 4 5 6 0 1 2
+ ** date 1/1
+ ** week# 1 2
+ ** This means that the first week actually starts 2 days before 1/1.
+ ** So Week of year = (GetDayOfYear(time) + offset - 1) / 7 + 1
+ ============================================================================*/
+
+ internal int GetFirstDayWeekOfYear(DateTime time, int firstDayOfWeek)
+ {
+ int dayOfYear = GetDayOfYear(time) - 1; // Make the day of year to be 0-based, so that 1/1 is day 0.
+ // Calculate the day of week for the first day of the year.
+ // dayOfWeek - (dayOfYear % 7) is the day of week for the first day of this year. Note that
+ // this value can be less than 0. It's fine since we are making it positive again in calculating offset.
+ int dayForJan1 = (int)GetDayOfWeek(time) - (dayOfYear % 7);
+ int offset = (dayForJan1 - firstDayOfWeek + 14) % 7;
+ Contract.Assert(offset >= 0, "Calendar.GetFirstDayWeekOfYear(): offset >= 0");
+ return ((dayOfYear + offset) / 7 + 1);
+ }
+
+ private int GetWeekOfYearFullDays(DateTime time, int firstDayOfWeek, int fullDays)
+ {
+ int dayForJan1;
+ int offset;
+ int day;
+
+ int dayOfYear = GetDayOfYear(time) - 1; // Make the day of year to be 0-based, so that 1/1 is day 0.
+ //
+ // Calculate the number of days between the first day of year (1/1) and the first day of the week.
+ // This value will be a positive value from 0 ~ 6. We call this value as "offset".
+ //
+ // If offset is 0, it means that the 1/1 is the start of the first week.
+ // Assume the first day of the week is Monday, it will look like this:
+ // Sun Mon Tue Wed Thu Fri Sat
+ // 12/31 1/1 1/2 1/3 1/4 1/5 1/6
+ // +--> First week starts here.
+ //
+ // If offset is 1, it means that the first day of the week is 1 day ahead of 1/1.
+ // Assume the first day of the week is Monday, it will look like this:
+ // Sun Mon Tue Wed Thu Fri Sat
+ // 1/1 1/2 1/3 1/4 1/5 1/6 1/7
+ // +--> First week starts here.
+ //
+ // If offset is 2, it means that the first day of the week is 2 days ahead of 1/1.
+ // Assume the first day of the week is Monday, it will look like this:
+ // Sat Sun Mon Tue Wed Thu Fri Sat
+ // 1/1 1/2 1/3 1/4 1/5 1/6 1/7 1/8
+ // +--> First week starts here.
+
+
+
+ // Day of week is 0-based.
+ // Get the day of week for 1/1. This can be derived from the day of week of the target day.
+ // Note that we can get a negative value. It's ok since we are going to make it a positive value when calculating the offset.
+ dayForJan1 = (int)GetDayOfWeek(time) - (dayOfYear % 7);
+
+ // Now, calculate the offset. Subtract the first day of week from the dayForJan1. And make it a positive value.
+ offset = (firstDayOfWeek - dayForJan1 + 14) % 7;
+ if (offset != 0 && offset >= fullDays)
+ {
+ //
+ // If the offset is greater than the value of fullDays, it means that
+ // the first week of the year starts on the week where Jan/1 falls on.
+ //
+ offset -= 7;
+ }
+ //
+ // Calculate the day of year for specified time by taking offset into account.
+ //
+ day = dayOfYear - offset;
+ if (day >= 0)
+ {
+ //
+ // If the day of year value is greater than zero, get the week of year.
+ //
+ return (day / 7 + 1);
+ }
+ //
+ // Otherwise, the specified time falls on the week of previous year.
+ // Call this method again by passing the last day of previous year.
+ //
+ // the last day of the previous year may "underflow" to no longer be a valid date time for
+ // this calendar if we just subtract so we need the subclass to provide us with
+ // that information
+ if (time <= MinSupportedDateTime.AddDays(dayOfYear))
+ {
+ return GetWeekOfYearOfMinSupportedDateTime(firstDayOfWeek, fullDays);
+ }
+ return (GetWeekOfYearFullDays(time.AddDays(-(dayOfYear + 1)), firstDayOfWeek, fullDays));
+ }
+
+ private int GetWeekOfYearOfMinSupportedDateTime(int firstDayOfWeek, int minimumDaysInFirstWeek)
+ {
+ int dayOfYear = GetDayOfYear(MinSupportedDateTime) - 1; // Make the day of year to be 0-based, so that 1/1 is day 0.
+ int dayOfWeekOfFirstOfYear = (int)GetDayOfWeek(MinSupportedDateTime) - dayOfYear % 7;
+
+ // Calculate the offset (how many days from the start of the year to the start of the week)
+ int offset = (firstDayOfWeek + 7 - dayOfWeekOfFirstOfYear) % 7;
+ if (offset == 0 || offset >= minimumDaysInFirstWeek)
+ {
+ // First of year falls in the first week of the year
+ return 1;
+ }
+
+ int daysInYearBeforeMinSupportedYear = DaysInYearBeforeMinSupportedYear - 1; // Make the day of year to be 0-based, so that 1/1 is day 0.
+ int dayOfWeekOfFirstOfPreviousYear = dayOfWeekOfFirstOfYear - 1 - (daysInYearBeforeMinSupportedYear % 7);
+
+ // starting from first day of the year, how many days do you have to go forward
+ // before getting to the first day of the week?
+ int daysInInitialPartialWeek = (firstDayOfWeek - dayOfWeekOfFirstOfPreviousYear + 14) % 7;
+ int day = daysInYearBeforeMinSupportedYear - daysInInitialPartialWeek;
+ if (daysInInitialPartialWeek >= minimumDaysInFirstWeek)
+ {
+ // If the offset is greater than the minimum Days in the first week, it means that
+ // First of year is part of the first week of the year even though it is only a partial week
+ // add another week
+ day += 7;
+ }
+
+ return (day / 7 + 1);
+ }
+
+ // it would be nice to make this abstract but we can't since that would break previous implementations
+ protected virtual int DaysInYearBeforeMinSupportedYear
+ {
+ get
+ {
+ return 365;
+ }
+ }
+
+
+ // Returns the week of year for the specified DateTime. The returned value is an
+ // integer between 1 and 53.
+ //
+
+ public virtual int GetWeekOfYear(DateTime time, CalendarWeekRule rule, DayOfWeek firstDayOfWeek)
+ {
+ if ((int)firstDayOfWeek < 0 || (int)firstDayOfWeek > 6)
+ {
+ throw new ArgumentOutOfRangeException(
+ "firstDayOfWeek", SR.Format(SR.ArgumentOutOfRange_Range,
+ DayOfWeek.Sunday, DayOfWeek.Saturday));
+ }
+ Contract.EndContractBlock();
+ switch (rule)
+ {
+ case CalendarWeekRule.FirstDay:
+ return (GetFirstDayWeekOfYear(time, (int)firstDayOfWeek));
+ case CalendarWeekRule.FirstFullWeek:
+ return (GetWeekOfYearFullDays(time, (int)firstDayOfWeek, 7));
+ case CalendarWeekRule.FirstFourDayWeek:
+ return (GetWeekOfYearFullDays(time, (int)firstDayOfWeek, 4));
+ }
+ throw new ArgumentOutOfRangeException(
+ "rule", SR.Format(SR.ArgumentOutOfRange_Range,
+ CalendarWeekRule.FirstDay, CalendarWeekRule.FirstFourDayWeek));
+ }
+
+ // Returns the year part of the specified DateTime. The returned value is an
+ // integer between 1 and 9999.
+ //
+
+ public abstract int GetYear(DateTime time);
+
+ // Checks whether a given day in the current era is a leap day. This method returns true if
+ // the date is a leap day, or false if not.
+ //
+
+ public virtual bool IsLeapDay(int year, int month, int day)
+ {
+ return (IsLeapDay(year, month, day, CurrentEra));
+ }
+
+ // Checks whether a given day in the specified era is a leap day. This method returns true if
+ // the date is a leap day, or false if not.
+ //
+
+ public abstract bool IsLeapDay(int year, int month, int day, int era);
+
+ // Checks whether a given month in the current era is a leap month. This method returns true if
+ // month is a leap month, or false if not.
+ //
+
+ public virtual bool IsLeapMonth(int year, int month)
+ {
+ return (IsLeapMonth(year, month, CurrentEra));
+ }
+
+ // Checks whether a given month in the specified era is a leap month. This method returns true if
+ // month is a leap month, or false if not.
+ //
+
+ public abstract bool IsLeapMonth(int year, int month, int era);
+
+ // Returns the leap month in a calendar year of the specified era. This method returns 0
+ // if this calendar does not have leap month, or this year is not a leap year.
+ //
+
+ [System.Runtime.InteropServices.ComVisible(false)]
+ public virtual int GetLeapMonth(int year, int era)
+ {
+ if (!IsLeapYear(year, era))
+ return 0;
+
+ int monthsCount = GetMonthsInYear(year, era);
+ for (int month = 1; month <= monthsCount; month++)
+ {
+ if (IsLeapMonth(year, month, era))
+ return month;
+ }
+
+ return 0;
+ }
+
+ // Checks whether a given year in the current era is a leap year. This method returns true if
+ // year is a leap year, or false if not.
+ //
+
+ public virtual bool IsLeapYear(int year)
+ {
+ return (IsLeapYear(year, CurrentEra));
+ }
+
+ // Checks whether a given year in the specified era is a leap year. This method returns true if
+ // year is a leap year, or false if not.
+ //
+
+ public abstract bool IsLeapYear(int year, int era);
+
+ // Returns the date and time converted to a DateTime value. Throws an exception if the n-tuple is invalid.
+ //
+
+ public virtual DateTime ToDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond)
+ {
+ return (ToDateTime(year, month, day, hour, minute, second, millisecond, CurrentEra));
+ }
+
+ // Returns the date and time converted to a DateTime value. Throws an exception if the n-tuple is invalid.
+ //
+
+ public abstract DateTime ToDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int era);
+
+ internal virtual Boolean TryToDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int era, out DateTime result)
+ {
+ result = DateTime.MinValue;
+ try
+ {
+ result = ToDateTime(year, month, day, hour, minute, second, millisecond, era);
+ return true;
+ }
+ catch (ArgumentException)
+ {
+ return false;
+ }
+ }
+
+ internal virtual bool IsValidYear(int year, int era)
+ {
+ return (year >= GetYear(MinSupportedDateTime) && year <= GetYear(MaxSupportedDateTime));
+ }
+
+ internal virtual bool IsValidMonth(int year, int month, int era)
+ {
+ return (IsValidYear(year, era) && month >= 1 && month <= GetMonthsInYear(year, era));
+ }
+
+ internal virtual bool IsValidDay(int year, int month, int day, int era)
+ {
+ return (IsValidMonth(year, month, era) && day >= 1 && day <= GetDaysInMonth(year, month, era));
+ }
+
+
+ // Returns and assigns the maximum value to represent a two digit year. This
+ // value is the upper boundary of a 100 year range that allows a two digit year
+ // to be properly translated to a four digit year. For example, if 2029 is the
+ // upper boundary, then a two digit value of 30 should be interpreted as 1930
+ // while a two digit value of 29 should be interpreted as 2029. In this example
+ // , the 100 year range would be from 1930-2029. See ToFourDigitYear().
+
+ public virtual int TwoDigitYearMax
+ {
+ get
+ {
+ return (twoDigitYearMax);
+ }
+
+ set
+ {
+ VerifyWritable();
+ twoDigitYearMax = value;
+ }
+ }
+
+ // Converts the year value to the appropriate century by using the
+ // TwoDigitYearMax property. For example, if the TwoDigitYearMax value is 2029,
+ // then a two digit value of 30 will get converted to 1930 while a two digit
+ // value of 29 will get converted to 2029.
+
+ public virtual int ToFourDigitYear(int year)
+ {
+ if (year < 0)
+ {
+ throw new ArgumentOutOfRangeException("year",
+ SR.ArgumentOutOfRange_NeedNonNegNum);
+ }
+ Contract.EndContractBlock();
+ if (year < 100)
+ {
+ return ((TwoDigitYearMax / 100 - (year > TwoDigitYearMax % 100 ? 1 : 0)) * 100 + year);
+ }
+ // If the year value is above 100, just return the year value. Don't have to do
+ // the TwoDigitYearMax comparison.
+ return (year);
+ }
+
+ // Return the tick count corresponding to the given hour, minute, second.
+ // Will check the if the parameters are valid.
+ internal static long TimeToTicks(int hour, int minute, int second, int millisecond)
+ {
+ if (hour >= 0 && hour < 24 && minute >= 0 && minute < 60 && second >= 0 && second < 60)
+ {
+ if (millisecond < 0 || millisecond >= MillisPerSecond)
+ {
+ throw new ArgumentOutOfRangeException(
+ "millisecond",
+ String.Format(
+ CultureInfo.InvariantCulture,
+ SR.Format(SR.ArgumentOutOfRange_Range, 0, MillisPerSecond - 1)));
+ }
+ return InternalGloablizationHelper.TimeToTicks(hour, minute, second) + millisecond * TicksPerMillisecond;
+ }
+ throw new ArgumentOutOfRangeException(null, SR.ArgumentOutOfRange_BadHourMinuteSecond);
+ }
+
+ internal static int GetSystemTwoDigitYearSetting(CalendarId CalID, int defaultYearValue)
+ {
+ // Call nativeGetTwoDigitYearMax
+ int twoDigitYearMax = CalendarData.GetTwoDigitYearMax(CalID);
+ if (twoDigitYearMax < 0)
+ {
+ twoDigitYearMax = defaultYearValue;
+ }
+ return (twoDigitYearMax);
+ }
+ }
+}
diff --git a/src/mscorlib/corefx/System/Globalization/CalendarData.Unix.cs b/src/mscorlib/corefx/System/Globalization/CalendarData.Unix.cs
new file mode 100644
index 0000000000..6c6a18ec37
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/CalendarData.Unix.cs
@@ -0,0 +1,341 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.Diagnostics.Contracts;
+using System.Runtime.InteropServices;
+using System.Security;
+using System.Text;
+
+namespace System.Globalization
+{
+ // needs to be kept in sync with CalendarDataType in System.Globalization.Native
+ internal enum CalendarDataType
+ {
+ Uninitialized = 0,
+ NativeName = 1,
+ MonthDay = 2,
+ ShortDates = 3,
+ LongDates = 4,
+ YearMonths = 5,
+ DayNames = 6,
+ AbbrevDayNames = 7,
+ MonthNames = 8,
+ AbbrevMonthNames = 9,
+ SuperShortDayNames = 10,
+ MonthGenitiveNames = 11,
+ AbbrevMonthGenitiveNames = 12,
+ EraNames = 13,
+ AbbrevEraNames = 14,
+ }
+
+ internal partial class CalendarData
+ {
+ private bool LoadCalendarDataFromSystem(String localeName, CalendarId calendarId)
+ {
+ bool result = true;
+ result &= GetCalendarInfo(localeName, calendarId, CalendarDataType.NativeName, out this.sNativeName);
+ result &= GetCalendarInfo(localeName, calendarId, CalendarDataType.MonthDay, out this.sMonthDay);
+ this.sMonthDay = NormalizeDatePattern(this.sMonthDay);
+
+ result &= EnumDatePatterns(localeName, calendarId, CalendarDataType.ShortDates, out this.saShortDates);
+ result &= EnumDatePatterns(localeName, calendarId, CalendarDataType.LongDates, out this.saLongDates);
+ result &= EnumDatePatterns(localeName, calendarId, CalendarDataType.YearMonths, out this.saYearMonths);
+ result &= EnumCalendarInfo(localeName, calendarId, CalendarDataType.DayNames, out this.saDayNames);
+ result &= EnumCalendarInfo(localeName, calendarId, CalendarDataType.AbbrevDayNames, out this.saAbbrevDayNames);
+ result &= EnumCalendarInfo(localeName, calendarId, CalendarDataType.SuperShortDayNames, out this.saSuperShortDayNames);
+ result &= EnumMonthNames(localeName, calendarId, CalendarDataType.MonthNames, out this.saMonthNames);
+ result &= EnumMonthNames(localeName, calendarId, CalendarDataType.AbbrevMonthNames, out this.saAbbrevMonthNames);
+ result &= EnumMonthNames(localeName, calendarId, CalendarDataType.MonthGenitiveNames, out this.saMonthGenitiveNames);
+ result &= EnumMonthNames(localeName, calendarId, CalendarDataType.AbbrevMonthGenitiveNames, out this.saAbbrevMonthGenitiveNames);
+ result &= EnumEraNames(localeName, calendarId, CalendarDataType.EraNames, out this.saEraNames);
+ result &= EnumEraNames(localeName, calendarId, CalendarDataType.AbbrevEraNames, out this.saAbbrevEraNames);
+
+ return result;
+ }
+
+ internal static int GetTwoDigitYearMax(CalendarId calendarId)
+ {
+ // There is no user override for this value on Linux or in ICU.
+ // So just return -1 to use the hard-coded defaults.
+ return -1;
+ }
+
+ // Call native side to figure out which calendars are allowed
+ [SecuritySafeCritical]
+ internal static int GetCalendars(string localeName, bool useUserOverride, CalendarId[] calendars)
+ {
+ // NOTE: there are no 'user overrides' on Linux
+ int count = Interop.GlobalizationInterop.GetCalendars(localeName, calendars, calendars.Length);
+
+ // ensure there is at least 1 calendar returned
+ if (count == 0 && calendars.Length > 0)
+ {
+ calendars[0] = CalendarId.GREGORIAN;
+ count = 1;
+ }
+
+ return count;
+ }
+
+ private static bool SystemSupportsTaiwaneseCalendar()
+ {
+ return true;
+ }
+
+ // PAL Layer ends here
+
+ [SecuritySafeCritical]
+ private static bool GetCalendarInfo(string localeName, CalendarId calendarId, CalendarDataType dataType, out string calendarString)
+ {
+ return Interop.CallStringMethod(
+ (locale, calId, type, stringBuilder) =>
+ Interop.GlobalizationInterop.GetCalendarInfo(
+ locale,
+ calId,
+ type,
+ stringBuilder,
+ stringBuilder.Capacity),
+ localeName,
+ calendarId,
+ dataType,
+ out calendarString);
+ }
+
+ private static bool EnumDatePatterns(string localeName, CalendarId calendarId, CalendarDataType dataType, out string[] datePatterns)
+ {
+ datePatterns = null;
+
+ CallbackContext callbackContext = new CallbackContext();
+ callbackContext.DisallowDuplicates = true;
+ bool result = EnumCalendarInfo(localeName, calendarId, dataType, callbackContext);
+ if (result)
+ {
+ List<string> datePatternsList = callbackContext.Results;
+
+ datePatterns = new string[datePatternsList.Count];
+ for (int i = 0; i < datePatternsList.Count; i++)
+ {
+ datePatterns[i] = NormalizeDatePattern(datePatternsList[i]);
+ }
+ }
+
+ return result;
+ }
+
+ /// <summary>
+ /// The ICU date format characters are not exactly the same as the .NET date format characters.
+ /// NormalizeDatePattern will take in an ICU date pattern and return the equivalent .NET date pattern.
+ /// </summary>
+ /// <remarks>
+ /// see Date Field Symbol Table in http://userguide.icu-project.org/formatparse/datetime
+ /// and https://msdn.microsoft.com/en-us/library/8kb3ddd4(v=vs.110).aspx
+ /// </remarks>
+ private static string NormalizeDatePattern(string input)
+ {
+ StringBuilder destination = StringBuilderCache.Acquire(input.Length);
+
+ int index = 0;
+ while (index < input.Length)
+ {
+ switch (input[index])
+ {
+ case '\'':
+ // single quotes escape characters, like 'de' in es-SP
+ // so read verbatim until the next single quote
+ destination.Append(input[index++]);
+ while (index < input.Length)
+ {
+ char current = input[index++];
+ destination.Append(current);
+ if (current == '\'')
+ {
+ break;
+ }
+ }
+ break;
+ case 'E':
+ case 'e':
+ case 'c':
+ // 'E' in ICU is the day of the week, which maps to 3 or 4 'd's in .NET
+ // 'e' in ICU is the local day of the week, which has no representation in .NET, but
+ // maps closest to 3 or 4 'd's in .NET
+ // 'c' in ICU is the stand-alone day of the week, which has no representation in .NET, but
+ // maps closest to 3 or 4 'd's in .NET
+ NormalizeDayOfWeek(input, destination, ref index);
+ break;
+ case 'L':
+ case 'M':
+ // 'L' in ICU is the stand-alone name of the month,
+ // which maps closest to 'M' in .NET since it doesn't support stand-alone month names in patterns
+ // 'M' in both ICU and .NET is the month,
+ // but ICU supports 5 'M's, which is the super short month name
+ int occurrences = CountOccurrences(input, input[index], ref index);
+ if (occurrences > 4)
+ {
+ // 5 'L's or 'M's in ICU is the super short name, which maps closest to MMM in .NET
+ occurrences = 3;
+ }
+ destination.Append('M', occurrences);
+ break;
+ case 'G':
+ // 'G' in ICU is the era, which maps to 'g' in .NET
+ occurrences = CountOccurrences(input, 'G', ref index);
+
+ // it doesn't matter how many 'G's, since .NET only supports 'g' or 'gg', and they
+ // have the same meaning
+ destination.Append('g');
+ break;
+ case 'y':
+ // a single 'y' in ICU is the year with no padding or trimming.
+ // a single 'y' in .NET is the year with 1 or 2 digits
+ // so convert any single 'y' to 'yyyy'
+ occurrences = CountOccurrences(input, 'y', ref index);
+ if (occurrences == 1)
+ {
+ occurrences = 4;
+ }
+ destination.Append('y', occurrences);
+ break;
+ default:
+ const string unsupportedDateFieldSymbols = "YuUrQqwWDFg";
+ Contract.Assert(unsupportedDateFieldSymbols.IndexOf(input[index]) == -1,
+ string.Format(CultureInfo.InvariantCulture,
+ "Encountered an unexpected date field symbol '{0}' from ICU which has no known corresponding .NET equivalent.",
+ input[index]));
+
+ destination.Append(input[index++]);
+ break;
+ }
+ }
+
+ return StringBuilderCache.GetStringAndRelease(destination);
+ }
+
+ private static void NormalizeDayOfWeek(string input, StringBuilder destination, ref int index)
+ {
+ char dayChar = input[index];
+ int occurrences = CountOccurrences(input, dayChar, ref index);
+ occurrences = Math.Max(occurrences, 3);
+ if (occurrences > 4)
+ {
+ // 5 and 6 E/e/c characters in ICU is the super short names, which maps closest to ddd in .NET
+ occurrences = 3;
+ }
+
+ destination.Append('d', occurrences);
+ }
+
+ private static int CountOccurrences(string input, char value, ref int index)
+ {
+ int startIndex = index;
+ while (index < input.Length && input[index] == value)
+ {
+ index++;
+ }
+
+ return index - startIndex;
+ }
+
+ [SecuritySafeCritical]
+ private static bool EnumMonthNames(string localeName, CalendarId calendarId, CalendarDataType dataType, out string[] monthNames)
+ {
+ monthNames = null;
+
+ CallbackContext callbackContext = new CallbackContext();
+ bool result = EnumCalendarInfo(localeName, calendarId, dataType, callbackContext);
+ if (result)
+ {
+ // the month-name arrays are expected to have 13 elements. If ICU only returns 12, add an
+ // extra empty string to fill the array.
+ if (callbackContext.Results.Count == 12)
+ {
+ callbackContext.Results.Add(string.Empty);
+ }
+
+ monthNames = callbackContext.Results.ToArray();
+ }
+
+ return result;
+ }
+
+ [SecuritySafeCritical]
+ private static bool EnumEraNames(string localeName, CalendarId calendarId, CalendarDataType dataType, out string[] eraNames)
+ {
+ bool result = EnumCalendarInfo(localeName, calendarId, dataType, out eraNames);
+
+ // .NET expects that only the Japanese calendars have more than 1 era.
+ // So for other calendars, only return the latest era.
+ if (calendarId != CalendarId.JAPAN && calendarId != CalendarId.JAPANESELUNISOLAR && eraNames.Length > 0)
+ {
+ string[] latestEraName = new string[] { eraNames[eraNames.Length - 1] };
+ eraNames = latestEraName;
+ }
+
+ return result;
+ }
+
+ [SecuritySafeCritical]
+ internal static bool EnumCalendarInfo(string localeName, CalendarId calendarId, CalendarDataType dataType, out string[] calendarData)
+ {
+ calendarData = null;
+
+ CallbackContext callbackContext = new CallbackContext();
+ bool result = EnumCalendarInfo(localeName, calendarId, dataType, callbackContext);
+ if (result)
+ {
+ calendarData = callbackContext.Results.ToArray();
+ }
+
+ return result;
+ }
+
+ [SecuritySafeCritical]
+ private static bool EnumCalendarInfo(string localeName, CalendarId calendarId, CalendarDataType dataType, CallbackContext callbackContext)
+ {
+ GCHandle context = GCHandle.Alloc(callbackContext);
+ try
+ {
+ return Interop.GlobalizationInterop.EnumCalendarInfo(EnumCalendarInfoCallback, localeName, calendarId, dataType, (IntPtr)context);
+ }
+ finally
+ {
+ context.Free();
+ }
+ }
+
+ [SecuritySafeCritical]
+ private static void EnumCalendarInfoCallback(string calendarString, IntPtr context)
+ {
+ CallbackContext callbackContext = (CallbackContext)((GCHandle)context).Target;
+
+ if (callbackContext.DisallowDuplicates)
+ {
+ foreach (string existingResult in callbackContext.Results)
+ {
+ if (string.Equals(calendarString, existingResult, StringComparison.Ordinal))
+ {
+ // the value is already in the results, so don't add it again
+ return;
+ }
+ }
+ }
+
+ callbackContext.Results.Add(calendarString);
+ }
+
+ private class CallbackContext
+ {
+ private List<string> _results = new List<string>();
+
+ public CallbackContext()
+ {
+ }
+
+ public List<string> Results { get { return _results; } }
+
+ public bool DisallowDuplicates { get; set; }
+ }
+ }
+}
diff --git a/src/mscorlib/corefx/System/Globalization/CalendarData.Windows.cs b/src/mscorlib/corefx/System/Globalization/CalendarData.Windows.cs
new file mode 100644
index 0000000000..bdf3ff1881
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/CalendarData.Windows.cs
@@ -0,0 +1,469 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+using System.Runtime.CompilerServices;
+using System.Diagnostics.Contracts;
+using System.Collections.Generic;
+
+namespace System.Globalization
+{
+ internal partial class CalendarData
+ {
+ private bool LoadCalendarDataFromSystem(String localeName, CalendarId calendarId)
+ {
+ bool ret = true;
+
+ uint useOverrides = this.bUseUserOverrides ? 0 : CAL_NOUSEROVERRIDE;
+
+ //
+ // Windows doesn't support some calendars right now, so remap those.
+ //
+ switch (calendarId)
+ {
+ case CalendarId.JAPANESELUNISOLAR: // Data looks like Japanese
+ calendarId = CalendarId.JAPAN;
+ break;
+ case CalendarId.JULIAN: // Data looks like gregorian US
+ case CalendarId.CHINESELUNISOLAR: // Algorithmic, so actual data is irrelevent
+ case CalendarId.SAKA: // reserved to match Office but not implemented in our code, so data is irrelevent
+ case CalendarId.LUNAR_ETO_CHN: // reserved to match Office but not implemented in our code, so data is irrelevent
+ case CalendarId.LUNAR_ETO_KOR: // reserved to match Office but not implemented in our code, so data is irrelevent
+ case CalendarId.LUNAR_ETO_ROKUYOU: // reserved to match Office but not implemented in our code, so data is irrelevent
+ case CalendarId.KOREANLUNISOLAR: // Algorithmic, so actual data is irrelevent
+ case CalendarId.TAIWANLUNISOLAR: // Algorithmic, so actual data is irrelevent
+ calendarId = CalendarId.GREGORIAN_US;
+ break;
+ }
+
+ //
+ // Special handling for some special calendar due to OS limitation.
+ // This includes calendar like Taiwan calendar, UmAlQura calendar, etc.
+ //
+ CheckSpecialCalendar(ref calendarId, ref localeName);
+
+ // Numbers
+ ret &= CallGetCalendarInfoEx(localeName, calendarId, CAL_ITWODIGITYEARMAX | useOverrides, out this.iTwoDigitYearMax);
+
+ // Strings
+ ret &= CallGetCalendarInfoEx(localeName, calendarId, CAL_SCALNAME, out this.sNativeName);
+ ret &= CallGetCalendarInfoEx(localeName, calendarId, CAL_SMONTHDAY | useOverrides, out this.sMonthDay);
+
+ // String Arrays
+ // Formats
+ ret &= CallEnumCalendarInfo(localeName, calendarId, CAL_SSHORTDATE, LOCALE_SSHORTDATE | useOverrides, out this.saShortDates);
+ ret &= CallEnumCalendarInfo(localeName, calendarId, CAL_SLONGDATE, LOCALE_SLONGDATE | useOverrides, out this.saLongDates);
+
+ // Get the YearMonth pattern.
+ ret &= CallEnumCalendarInfo(localeName, calendarId, CAL_SYEARMONTH, LOCALE_SYEARMONTH, out this.saYearMonths);
+
+ // Day & Month Names
+ // These are all single calType entries, 1 per day, so we have to make 7 or 13 calls to collect all the names
+
+ // Day
+ // Note that we're off-by-one since managed starts on sunday and windows starts on monday
+ ret &= GetCalendarDayInfo(localeName, calendarId, CAL_SDAYNAME7, out this.saDayNames);
+ ret &= GetCalendarDayInfo(localeName, calendarId, CAL_SABBREVDAYNAME7, out this.saAbbrevDayNames);
+
+ // Month names
+ ret &= GetCalendarMonthInfo(localeName, calendarId, CAL_SMONTHNAME1, out this.saMonthNames);
+ ret &= GetCalendarMonthInfo(localeName, calendarId, CAL_SABBREVMONTHNAME1, out this.saAbbrevMonthNames);
+
+ //
+ // The following LCTYPE are not supported in some platforms. If the call fails,
+ // don't return a failure.
+ //
+ GetCalendarDayInfo(localeName, calendarId, CAL_SSHORTESTDAYNAME7, out this.saSuperShortDayNames);
+
+ // Gregorian may have genitive month names
+ if (calendarId == CalendarId.GREGORIAN)
+ {
+ GetCalendarMonthInfo(localeName, calendarId, CAL_SMONTHNAME1 | CAL_RETURN_GENITIVE_NAMES, out this.saMonthGenitiveNames);
+ GetCalendarMonthInfo(localeName, calendarId, CAL_SABBREVMONTHNAME1 | CAL_RETURN_GENITIVE_NAMES, out this.saAbbrevMonthGenitiveNames);
+ }
+
+ // Calendar Parts Names
+ // This doesn't get always get localized names for gregorian (not available in windows < 7)
+ // so: eg: coreclr on win < 7 won't get these
+ CallEnumCalendarInfo(localeName, calendarId, CAL_SERASTRING, 0, out this.saEraNames);
+ CallEnumCalendarInfo(localeName, calendarId, CAL_SABBREVERASTRING, 0, out this.saAbbrevEraNames);
+
+ //
+ // Calendar Era Info
+ // Note that calendar era data (offsets, etc) is hard coded for each calendar since this
+ // data is implementation specific and not dynamic (except perhaps Japanese)
+ //
+
+ // Clean up the escaping of the formats
+ this.saShortDates = CultureData.ReescapeWin32Strings(this.saShortDates);
+ this.saLongDates = CultureData.ReescapeWin32Strings(this.saLongDates);
+ this.saYearMonths = CultureData.ReescapeWin32Strings(this.saYearMonths);
+ this.sMonthDay = CultureData.ReescapeWin32String(this.sMonthDay);
+
+ return ret;
+ }
+
+ // Get native two digit year max
+ internal static int GetTwoDigitYearMax(CalendarId calendarId)
+ {
+ int twoDigitYearMax = -1;
+
+ if (!CallGetCalendarInfoEx(null, calendarId, (uint)CAL_ITWODIGITYEARMAX, out twoDigitYearMax))
+ {
+ twoDigitYearMax = -1;
+ }
+
+ return twoDigitYearMax;
+ }
+
+ // Call native side to figure out which calendars are allowed
+ internal static int GetCalendars(String localeName, bool useUserOverride, CalendarId[] calendars)
+ {
+ EnumCalendarsData data = new EnumCalendarsData();
+ data.userOverride = 0;
+ data.calendars = new LowLevelList<int>();
+
+ // First call GetLocaleInfo if necessary
+ if (useUserOverride)
+ {
+ // They want user overrides, see if the user calendar matches the input calendar
+ int userCalendar = Interop.mincore.GetLocaleInfoExInt(localeName, LOCALE_ICALENDARTYPE);
+
+ // If we got a default, then use it as the first calendar
+ if (userCalendar != 0)
+ {
+ data.userOverride = userCalendar;
+ data.calendars.Add(userCalendar);
+ }
+ }
+
+ GCHandle contextHandle = GCHandle.Alloc(data);
+ try
+ {
+ // Now call the enumeration API. Work is done by our callback function
+ IntPtr callback = AddrofIntrinsics.AddrOf<Func<IntPtr, uint, IntPtr, IntPtr, Interop.BOOL>>(EnumCalendarsCallback);
+ Interop.mincore.EnumCalendarInfoExEx(callback, localeName, ENUM_ALL_CALENDARS, null, CAL_ICALINTVALUE, (IntPtr)contextHandle);
+ }
+ finally
+ {
+ contextHandle.Free();
+ }
+
+ // Copy to the output array
+ for (int i = 0; i < Math.Min(calendars.Length, data.calendars.Count); i++)
+ calendars[i] = (CalendarId)data.calendars[i];
+
+ // Now we have a list of data, return the count
+ return data.calendars.Count;
+ }
+
+ private static bool SystemSupportsTaiwaneseCalendar()
+ {
+ string data;
+ // Taiwanese calendar get listed as one of the optional zh-TW calendars only when having zh-TW UI
+ return CallGetCalendarInfoEx("zh-TW", CalendarId.TAIWAN, CAL_SCALNAME, out data);
+ }
+
+ // PAL Layer ends here
+
+ private const uint CAL_RETURN_NUMBER = 0x20000000;
+ private const uint CAL_RETURN_GENITIVE_NAMES = 0x10000000;
+ private const uint CAL_NOUSEROVERRIDE = 0x80000000;
+ private const uint CAL_SCALNAME = 0x00000002;
+ private const uint CAL_SMONTHDAY = 0x00000038;
+ private const uint CAL_SSHORTDATE = 0x00000005;
+ private const uint CAL_SLONGDATE = 0x00000006;
+ private const uint CAL_SYEARMONTH = 0x0000002f;
+ private const uint CAL_SDAYNAME7 = 0x0000000d;
+ private const uint CAL_SABBREVDAYNAME7 = 0x00000014;
+ private const uint CAL_SMONTHNAME1 = 0x00000015;
+ private const uint CAL_SABBREVMONTHNAME1 = 0x00000022;
+ private const uint CAL_SSHORTESTDAYNAME7 = 0x00000037;
+ private const uint CAL_SERASTRING = 0x00000004;
+ private const uint CAL_SABBREVERASTRING = 0x00000039;
+ private const uint CAL_ICALINTVALUE = 0x00000001;
+ private const uint CAL_ITWODIGITYEARMAX = 0x00000030;
+
+ private const uint ENUM_ALL_CALENDARS = 0xffffffff;
+
+ private const uint LOCALE_SSHORTDATE = 0x0000001F;
+ private const uint LOCALE_SLONGDATE = 0x00000020;
+ private const uint LOCALE_SYEARMONTH = 0x00001006;
+ private const uint LOCALE_ICALENDARTYPE = 0x00001009;
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // For calendars like Gregorain US/Taiwan/UmAlQura, they are not available
+ // in all OS or all localized versions of OS.
+ // If OS does not support these calendars, we will fallback by using the
+ // appropriate fallback calendar and locale combination to retrieve data from OS.
+ //
+ // Parameters:
+ // __deref_inout pCalendarInt:
+ // Pointer to the calendar ID. This will be updated to new fallback calendar ID if needed.
+ // __in_out pLocaleNameStackBuffer
+ // Pointer to the StackSString object which holds the locale name to be checked.
+ // This will be updated to new fallback locale name if needed.
+ //
+ ////////////////////////////////////////////////////////////////////////
+ private static void CheckSpecialCalendar(ref CalendarId calendar, ref string localeName)
+ {
+ string data;
+
+ // Gregorian-US isn't always available in the OS, however it is the same for all locales
+ switch (calendar)
+ {
+ case CalendarId.GREGORIAN_US:
+ // See if this works
+ if (!CallGetCalendarInfoEx(localeName, calendar, CAL_SCALNAME, out data))
+ {
+ // Failed, set it to a locale (fa-IR) that's alway has Gregorian US available in the OS
+ localeName = "fa-IR";
+ }
+ // See if that works
+ if (!CallGetCalendarInfoEx(localeName, calendar, CAL_SCALNAME, out data))
+ {
+ // Failed again, just use en-US with the gregorian calendar
+ localeName = "en-US";
+ calendar = CalendarId.GREGORIAN;
+ }
+ break;
+ case CalendarId.TAIWAN:
+ // Taiwan calendar data is not always in all language version of OS due to Geopolical reasons.
+ // It is only available in zh-TW localized versions of Windows.
+ // Let's check if OS supports it. If not, fallback to Greogrian localized for Taiwan calendar.
+ if (!SystemSupportsTaiwaneseCalendar())
+ {
+ calendar = CalendarId.GREGORIAN;
+ }
+ break;
+ }
+ }
+
+ private static bool CallGetCalendarInfoEx(string localeName, CalendarId calendar, uint calType, out int data)
+ {
+ return (Interop.mincore.GetCalendarInfoEx(localeName, (uint)calendar, IntPtr.Zero, calType | CAL_RETURN_NUMBER, IntPtr.Zero, 0, out data) != 0);
+ }
+
+ private static unsafe bool CallGetCalendarInfoEx(string localeName, CalendarId calendar, uint calType, out string data)
+ {
+ const int BUFFER_LENGTH = 80;
+
+ // The maximum size for values returned from GetCalendarInfoEx is 80 characters.
+ char* buffer = stackalloc char[BUFFER_LENGTH];
+
+ int ret = Interop.mincore.GetCalendarInfoEx(localeName, (uint)calendar, IntPtr.Zero, calType, (IntPtr)buffer, BUFFER_LENGTH, IntPtr.Zero);
+ if (ret > 0)
+ {
+ if (buffer[ret - 1] == '\0')
+ {
+ ret--; // don't include the null termination in the string
+ }
+ data = new string(buffer, 0, ret);
+ return true;
+ }
+ data = "";
+ return false;
+ }
+
+ // Context for EnumCalendarInfoExEx callback.
+ private class EnumData
+ {
+ public string userOverride;
+ public LowLevelList<string> strings;
+ }
+
+ // EnumCalendarInfoExEx callback itself.
+ [NativeCallable(CallingConvention = CallingConvention.StdCall)]
+ private static unsafe Interop.BOOL EnumCalendarInfoCallback(IntPtr lpCalendarInfoString, uint calendar, IntPtr pReserved, IntPtr lParam)
+ {
+ EnumData context = (EnumData)((GCHandle)lParam).Target;
+ try
+ {
+ string calendarInfo = new string((char*)lpCalendarInfoString);
+
+ // If we had a user override, check to make sure this differs
+ if (context.userOverride != calendarInfo)
+ context.strings.Add(calendarInfo);
+
+ return Interop.BOOL.TRUE;
+ }
+ catch (Exception)
+ {
+ return Interop.BOOL.FALSE;
+ }
+ }
+
+ private static unsafe bool CallEnumCalendarInfo(string localeName, CalendarId calendar, uint calType, uint lcType, out string[] data)
+ {
+ EnumData context = new EnumData();
+ context.userOverride = null;
+ context.strings = new LowLevelList<string>();
+
+ // First call GetLocaleInfo if necessary
+ if (((lcType != 0) && ((lcType & CAL_NOUSEROVERRIDE) == 0)) &&
+ // Get user locale, see if it matches localeName.
+ // Note that they should match exactly, including letter case
+ GetUserDefaultLocaleName() == localeName)
+ {
+ // They want user overrides, see if the user calendar matches the input calendar
+ CalendarId userCalendar = (CalendarId)Interop.mincore.GetLocaleInfoExInt(localeName, LOCALE_ICALENDARTYPE);
+
+ // If the calendars were the same, see if the locales were the same
+ if (userCalendar == calendar)
+ {
+ // They matched, get the user override since locale & calendar match
+ string res = Interop.mincore.GetLocaleInfoEx(localeName, lcType);
+
+ // if it succeeded remember the override for the later callers
+ if (res != "")
+ {
+ // Remember this was the override (so we can look for duplicates later in the enum function)
+ context.userOverride = res;
+
+ // Add to the result strings.
+ context.strings.Add(res);
+ }
+ }
+ }
+
+ GCHandle contextHandle = GCHandle.Alloc(context);
+ try
+ {
+ // Now call the enumeration API. Work is done by our callback function
+ IntPtr callback = AddrofIntrinsics.AddrOf<Func<IntPtr, uint, IntPtr, IntPtr, Interop.BOOL>>(EnumCalendarInfoCallback);
+ Interop.mincore.EnumCalendarInfoExEx(callback, localeName, (uint)calendar, null, calType, (IntPtr)contextHandle);
+ }
+ finally
+ {
+ contextHandle.Free();
+ }
+
+ // Now we have a list of data, fail if we didn't find anything.
+ if (context.strings.Count == 0)
+ {
+ data = null;
+ return false;
+ }
+
+ string[] output = context.strings.ToArray();
+
+ if (calType == CAL_SABBREVERASTRING || calType == CAL_SERASTRING)
+ {
+ // Eras are enumerated backwards. (oldest era name first, but
+ // Japanese calendar has newest era first in array, and is only
+ // calendar with multiple eras)
+ Array.Reverse(output, 0, output.Length);
+ }
+
+ data = output;
+
+ return true;
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Get the native day names
+ //
+ // NOTE: There's a disparity between .Net & windows day orders, the input day should
+ // start with Sunday
+ //
+ // Parameters:
+ // OUT pOutputStrings The output string[] value.
+ //
+ ////////////////////////////////////////////////////////////////////////
+ private static bool GetCalendarDayInfo(string localeName, CalendarId calendar, uint calType, out string[] outputStrings)
+ {
+ bool result = true;
+
+ //
+ // We'll need a new array of 7 items
+ //
+ string[] results = new string[7];
+
+ // Get each one of them
+ for (int i = 0; i < 7; i++, calType++)
+ {
+ result &= CallGetCalendarInfoEx(localeName, calendar, calType, out results[i]);
+
+ // On the first iteration we need to go from CAL_SDAYNAME7 to CAL_SDAYNAME1, so subtract 7 before the ++ happens
+ // This is because the framework starts on sunday and windows starts on monday when counting days
+ if (i == 0)
+ calType -= 7;
+ }
+
+ outputStrings = results;
+
+ return result;
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Get the native month names
+ //
+ // Parameters:
+ // OUT pOutputStrings The output string[] value.
+ //
+ ////////////////////////////////////////////////////////////////////////
+ private static bool GetCalendarMonthInfo(string localeName, CalendarId calendar, uint calType, out string[] outputStrings)
+ {
+ //
+ // We'll need a new array of 13 items
+ //
+ string[] results = new string[13];
+
+ // Get each one of them
+ for (int i = 0; i < 13; i++, calType++)
+ {
+ if (!CallGetCalendarInfoEx(localeName, calendar, calType, out results[i]))
+ results[i] = "";
+ }
+
+ outputStrings = results;
+
+ return true;
+ }
+
+ //
+ // struct to help our calendar data enumaration callback
+ //
+ private class EnumCalendarsData
+ {
+ public int userOverride; // user override value (if found)
+ public LowLevelList<int> calendars; // list of calendars found so far
+ }
+
+ [NativeCallable(CallingConvention = CallingConvention.StdCall)]
+ private static Interop.BOOL EnumCalendarsCallback(IntPtr lpCalendarInfoString, uint calendar, IntPtr reserved, IntPtr lParam)
+ {
+ EnumCalendarsData context = (EnumCalendarsData)((GCHandle)lParam).Target;
+ try
+ {
+ // If we had a user override, check to make sure this differs
+ if (context.userOverride != calendar)
+ context.calendars.Add((int)calendar);
+
+ return Interop.BOOL.TRUE;
+ }
+ catch (Exception)
+ {
+ return Interop.BOOL.FALSE;
+ }
+ }
+
+ private static unsafe String GetUserDefaultLocaleName()
+ {
+ const int LOCALE_NAME_MAX_LENGTH = 85;
+ const uint LOCALE_SNAME = 0x0000005c;
+ const string LOCALE_NAME_USER_DEFAULT = null;
+
+ int result;
+ char* localeName = stackalloc char[LOCALE_NAME_MAX_LENGTH];
+ result = Interop.mincore.GetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT, LOCALE_SNAME, localeName, LOCALE_NAME_MAX_LENGTH);
+
+ return result <= 0 ? "" : new String(localeName, 0, result - 1); // exclude the null termination
+ }
+ }
+}
diff --git a/src/mscorlib/corefx/System/Globalization/CalendarData.cs b/src/mscorlib/corefx/System/Globalization/CalendarData.cs
new file mode 100644
index 0000000000..2dbd1b8069
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/CalendarData.cs
@@ -0,0 +1,381 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+using System.Runtime.CompilerServices;
+using System.Diagnostics.Contracts;
+using System.Collections.Generic;
+
+namespace System.Globalization
+{
+ // List of calendar data
+ // Note the we cache overrides.
+ // Note that localized names (resource names) aren't available from here.
+ //
+ // NOTE: Calendars depend on the locale name that creates it. Only a few
+ // properties are available without locales using CalendarData.GetCalendar(CalendarData)
+
+ internal partial class CalendarData
+ {
+ // Max calendars
+ internal const int MAX_CALENDARS = 23;
+
+ // Identity
+ internal String sNativeName; // Calendar Name for the locale
+
+ // Formats
+ internal String[] saShortDates; // Short Data format, default first
+ internal String[] saYearMonths; // Year/Month Data format, default first
+ internal String[] saLongDates; // Long Data format, default first
+ internal String sMonthDay; // Month/Day format
+
+ // Calendar Parts Names
+ internal String[] saEraNames; // Names of Eras
+ internal String[] saAbbrevEraNames; // Abbreviated Era Names
+ internal String[] saAbbrevEnglishEraNames; // Abbreviated Era Names in English
+ internal String[] saDayNames; // Day Names, null to use locale data, starts on Sunday
+ internal String[] saAbbrevDayNames; // Abbrev Day Names, null to use locale data, starts on Sunday
+ internal String[] saSuperShortDayNames; // Super short Day of week names
+ internal String[] saMonthNames; // Month Names (13)
+ internal String[] saAbbrevMonthNames; // Abbrev Month Names (13)
+ internal String[] saMonthGenitiveNames; // Genitive Month Names (13)
+ internal String[] saAbbrevMonthGenitiveNames; // Genitive Abbrev Month Names (13)
+ internal String[] saLeapYearMonthNames; // Multiple strings for the month names in a leap year.
+
+ // Integers at end to make marshaller happier
+ internal int iTwoDigitYearMax = 2029; // Max 2 digit year (for Y2K bug data entry)
+ internal int iCurrentEra = 0; // current era # (usually 1)
+
+ // Use overrides?
+ internal bool bUseUserOverrides; // True if we want user overrides.
+
+ // Static invariant for the invariant locale
+ internal static CalendarData Invariant;
+
+ // Private constructor
+ private CalendarData() { }
+
+ // Invariant constructor
+ static CalendarData()
+ {
+ // Set our default/gregorian US calendar data
+ // Calendar IDs are 1-based, arrays are 0 based.
+ CalendarData invariant = new CalendarData();
+
+ // Set default data for calendar
+ // Note that we don't load resources since this IS NOT supposed to change (by definition)
+ invariant.sNativeName = "Gregorian Calendar"; // Calendar Name
+
+ // Year
+ invariant.iTwoDigitYearMax = 2029; // Max 2 digit year (for Y2K bug data entry)
+ invariant.iCurrentEra = 1; // Current era #
+
+ // Formats
+ invariant.saShortDates = new String[] { "MM/dd/yyyy", "yyyy-MM-dd" }; // short date format
+ invariant.saLongDates = new String[] { "dddd, dd MMMM yyyy" }; // long date format
+ invariant.saYearMonths = new String[] { "yyyy MMMM" }; // year month format
+ invariant.sMonthDay = "MMMM dd"; // Month day pattern
+
+ // Calendar Parts Names
+ invariant.saEraNames = new String[] { "A.D." }; // Era names
+ invariant.saAbbrevEraNames = new String[] { "AD" }; // Abbreviated Era names
+ invariant.saAbbrevEnglishEraNames = new String[] { "AD" }; // Abbreviated era names in English
+ invariant.saDayNames = new String[] { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };// day names
+ invariant.saAbbrevDayNames = new String[] { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; // abbreviated day names
+ invariant.saSuperShortDayNames = new String[] { "Su", "Mo", "Tu", "We", "Th", "Fr", "Sa" }; // The super short day names
+ invariant.saMonthNames = new String[] { "January", "February", "March", "April", "May", "June",
+ "July", "August", "September", "October", "November", "December", String.Empty}; // month names
+ invariant.saAbbrevMonthNames = new String[] { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", String.Empty}; // abbreviated month names
+ invariant.saMonthGenitiveNames = invariant.saMonthNames; // Genitive month names (same as month names for invariant)
+ invariant.saAbbrevMonthGenitiveNames = invariant.saAbbrevMonthNames; // Abbreviated genitive month names (same as abbrev month names for invariant)
+ invariant.saLeapYearMonthNames = invariant.saMonthNames; // leap year month names are unused in Gregorian English (invariant)
+
+ invariant.bUseUserOverrides = false;
+
+ // Calendar was built, go ahead and assign it...
+ Invariant = invariant;
+ }
+
+ //
+ // Get a bunch of data for a calendar
+ //
+ internal CalendarData(String localeName, CalendarId calendarId, bool bUseUserOverrides)
+ {
+ this.bUseUserOverrides = bUseUserOverrides;
+
+ if (!LoadCalendarDataFromSystem(localeName, calendarId))
+ {
+ Contract.Assert(false, "[CalendarData] LoadCalendarDataFromSystem call isn't expected to fail for calendar " + calendarId + " locale " + localeName);
+
+ // Something failed, try invariant for missing parts
+ // This is really not good, but we don't want the callers to crash.
+ if (this.sNativeName == null) this.sNativeName = String.Empty; // Calendar Name for the locale.
+
+ // Formats
+ if (this.saShortDates == null) this.saShortDates = Invariant.saShortDates; // Short Data format, default first
+ if (this.saYearMonths == null) this.saYearMonths = Invariant.saYearMonths; // Year/Month Data format, default first
+ if (this.saLongDates == null) this.saLongDates = Invariant.saLongDates; // Long Data format, default first
+ if (this.sMonthDay == null) this.sMonthDay = Invariant.sMonthDay; // Month/Day format
+
+ // Calendar Parts Names
+ if (this.saEraNames == null) this.saEraNames = Invariant.saEraNames; // Names of Eras
+ if (this.saAbbrevEraNames == null) this.saAbbrevEraNames = Invariant.saAbbrevEraNames; // Abbreviated Era Names
+ if (this.saAbbrevEnglishEraNames == null) this.saAbbrevEnglishEraNames = Invariant.saAbbrevEnglishEraNames; // Abbreviated Era Names in English
+ if (this.saDayNames == null) this.saDayNames = Invariant.saDayNames; // Day Names, null to use locale data, starts on Sunday
+ if (this.saAbbrevDayNames == null) this.saAbbrevDayNames = Invariant.saAbbrevDayNames; // Abbrev Day Names, null to use locale data, starts on Sunday
+ if (this.saSuperShortDayNames == null) this.saSuperShortDayNames = Invariant.saSuperShortDayNames; // Super short Day of week names
+ if (this.saMonthNames == null) this.saMonthNames = Invariant.saMonthNames; // Month Names (13)
+ if (this.saAbbrevMonthNames == null) this.saAbbrevMonthNames = Invariant.saAbbrevMonthNames; // Abbrev Month Names (13)
+ // Genitive and Leap names can follow the fallback below
+ }
+
+ if (calendarId == CalendarId.TAIWAN)
+ {
+ if (SystemSupportsTaiwaneseCalendar())
+ {
+ // We got the month/day names from the OS (same as gregorian), but the native name is wrong
+ this.sNativeName = "\x4e2d\x83ef\x6c11\x570b\x66c6";
+ }
+ else
+ {
+ this.sNativeName = String.Empty;
+ }
+ }
+
+ // Check for null genitive names (in case unmanaged side skips it for non-gregorian calendars, etc)
+ if (this.saMonthGenitiveNames == null || this.saMonthGenitiveNames.Length == 0 || String.IsNullOrEmpty(this.saMonthGenitiveNames[0]))
+ this.saMonthGenitiveNames = this.saMonthNames; // Genitive month names (same as month names for invariant)
+ if (this.saAbbrevMonthGenitiveNames == null || this.saAbbrevMonthGenitiveNames.Length == 0 || String.IsNullOrEmpty(this.saAbbrevMonthGenitiveNames[0]))
+ this.saAbbrevMonthGenitiveNames = this.saAbbrevMonthNames; // Abbreviated genitive month names (same as abbrev month names for invariant)
+ if (this.saLeapYearMonthNames == null || this.saLeapYearMonthNames.Length == 0 || String.IsNullOrEmpty(this.saLeapYearMonthNames[0]))
+ this.saLeapYearMonthNames = this.saMonthNames;
+
+ InitializeEraNames(localeName, calendarId);
+
+ InitializeAbbreviatedEraNames(localeName, calendarId);
+
+ // Abbreviated English Era Names are only used for the Japanese calendar.
+ if (calendarId == CalendarId.JAPAN)
+ {
+ this.saAbbrevEnglishEraNames = JapaneseCalendar.EnglishEraNames();
+ }
+ else
+ {
+ // For all others just use the an empty string (doesn't matter we'll never ask for it for other calendars)
+ this.saAbbrevEnglishEraNames = new String[] { "" };
+ }
+
+ // Japanese is the only thing with > 1 era. Its current era # is how many ever
+ // eras are in the array. (And the others all have 1 string in the array)
+ this.iCurrentEra = this.saEraNames.Length;
+ }
+
+ private void InitializeEraNames(string localeName, CalendarId calendarId)
+ {
+ // Note that the saEraNames only include "A.D." We don't have localized names for other calendars available from windows
+ switch (calendarId)
+ {
+ // For Localized Gregorian we really expect the data from the OS.
+ case CalendarId.GREGORIAN:
+ // Fallback for CoreCLR < Win7 or culture.dll missing
+ if (this.saEraNames == null || this.saEraNames.Length == 0 || String.IsNullOrEmpty(this.saEraNames[0]))
+ {
+ this.saEraNames = new String[] { "A.D." };
+ }
+ break;
+
+ // The rest of the calendars have constant data, so we'll just use that
+ case CalendarId.GREGORIAN_US:
+ case CalendarId.JULIAN:
+ this.saEraNames = new String[] { "A.D." };
+ break;
+ case CalendarId.HEBREW:
+ this.saEraNames = new String[] { "C.E." };
+ break;
+ case CalendarId.HIJRI:
+ case CalendarId.UMALQURA:
+ if (localeName == "dv-MV")
+ {
+ // Special case for Divehi
+ this.saEraNames = new String[] { "\x0780\x07a8\x0796\x07b0\x0783\x07a9" };
+ }
+ else
+ {
+ this.saEraNames = new String[] { "\x0628\x0639\x062F \x0627\x0644\x0647\x062C\x0631\x0629" };
+ }
+ break;
+ case CalendarId.GREGORIAN_ARABIC:
+ case CalendarId.GREGORIAN_XLIT_ENGLISH:
+ case CalendarId.GREGORIAN_XLIT_FRENCH:
+ // These are all the same:
+ this.saEraNames = new String[] { "\x0645" };
+ break;
+
+ case CalendarId.GREGORIAN_ME_FRENCH:
+ this.saEraNames = new String[] { "ap. J.-C." };
+ break;
+
+ case CalendarId.TAIWAN:
+ if (SystemSupportsTaiwaneseCalendar())
+ {
+ this.saEraNames = new String[] { "\x4e2d\x83ef\x6c11\x570b" };
+ }
+ else
+ {
+ this.saEraNames = new String[] { String.Empty };
+ }
+ break;
+
+ case CalendarId.KOREA:
+ this.saEraNames = new String[] { "\xb2e8\xae30" };
+ break;
+
+ case CalendarId.THAI:
+ this.saEraNames = new String[] { "\x0e1e\x002e\x0e28\x002e" };
+ break;
+
+ case CalendarId.JAPAN:
+ case CalendarId.JAPANESELUNISOLAR:
+ this.saEraNames = JapaneseCalendar.EraNames();
+ break;
+
+ case CalendarId.PERSIAN:
+ if (this.saEraNames == null || this.saEraNames.Length == 0 || String.IsNullOrEmpty(this.saEraNames[0]))
+ {
+ this.saEraNames = new String[] { "\x0647\x002e\x0634" };
+ }
+ break;
+
+ default:
+ // Most calendars are just "A.D."
+ this.saEraNames = Invariant.saEraNames;
+ break;
+ }
+ }
+
+ private void InitializeAbbreviatedEraNames(string localeName, CalendarId calendarId)
+ {
+ // Note that the saAbbrevEraNames only include "AD" We don't have localized names for other calendars available from windows
+ switch (calendarId)
+ {
+ // For Localized Gregorian we really expect the data from the OS.
+ case CalendarId.GREGORIAN:
+ // Fallback for CoreCLR < Win7 or culture.dll missing
+ if (this.saAbbrevEraNames == null || this.saAbbrevEraNames.Length == 0 || String.IsNullOrEmpty(this.saAbbrevEraNames[0]))
+ {
+ this.saAbbrevEraNames = new String[] { "AD" };
+ }
+ break;
+
+ // The rest of the calendars have constant data, so we'll just use that
+ case CalendarId.GREGORIAN_US:
+ case CalendarId.JULIAN:
+ this.saAbbrevEraNames = new String[] { "AD" };
+ break;
+ case CalendarId.JAPAN:
+ case CalendarId.JAPANESELUNISOLAR:
+ this.saAbbrevEraNames = JapaneseCalendar.AbbrevEraNames();
+ break;
+ case CalendarId.HIJRI:
+ case CalendarId.UMALQURA:
+ if (localeName == "dv-MV")
+ {
+ // Special case for Divehi
+ this.saAbbrevEraNames = new String[] { "\x0780\x002e" };
+ }
+ else
+ {
+ this.saAbbrevEraNames = new String[] { "\x0647\x0640" };
+ }
+ break;
+ case CalendarId.TAIWAN:
+ // Get era name and abbreviate it
+ this.saAbbrevEraNames = new String[1];
+ if (this.saEraNames[0].Length == 4)
+ {
+ this.saAbbrevEraNames[0] = this.saEraNames[0].Substring(2, 2);
+ }
+ else
+ {
+ this.saAbbrevEraNames[0] = this.saEraNames[0];
+ }
+ break;
+
+ case CalendarId.PERSIAN:
+ if (this.saAbbrevEraNames == null || this.saAbbrevEraNames.Length == 0 || String.IsNullOrEmpty(this.saAbbrevEraNames[0]))
+ {
+ this.saAbbrevEraNames = this.saEraNames;
+ }
+ break;
+
+ default:
+ // Most calendars just use the full name
+ this.saAbbrevEraNames = this.saEraNames;
+ break;
+ }
+ }
+
+ internal static CalendarData GetCalendarData(CalendarId calendarId)
+ {
+ //
+ // Get a calendar.
+ // Unfortunately we depend on the locale in the OS, so we need a locale
+ // no matter what. So just get the appropriate calendar from the
+ // appropriate locale here
+ //
+
+ // Get a culture name
+ // TODO: Note that this doesn't handle the new calendars (lunisolar, etc)
+ String culture = CalendarIdToCultureName(calendarId);
+
+ // Return our calendar
+ return CultureInfo.GetCultureInfo(culture).m_cultureData.GetCalendar(calendarId);
+ }
+
+ private static String CalendarIdToCultureName(CalendarId calendarId)
+ {
+ switch (calendarId)
+ {
+ case CalendarId.GREGORIAN_US:
+ return "fa-IR"; // "fa-IR" Iran
+
+ case CalendarId.JAPAN:
+ return "ja-JP"; // "ja-JP" Japan
+
+ case CalendarId.TAIWAN:
+ return "zh-TW"; // zh-TW Taiwan
+
+ case CalendarId.KOREA:
+ return "ko-KR"; // "ko-KR" Korea
+
+ case CalendarId.HIJRI:
+ case CalendarId.GREGORIAN_ARABIC:
+ case CalendarId.UMALQURA:
+ return "ar-SA"; // "ar-SA" Saudi Arabia
+
+ case CalendarId.THAI:
+ return "th-TH"; // "th-TH" Thailand
+
+ case CalendarId.HEBREW:
+ return "he-IL"; // "he-IL" Israel
+
+ case CalendarId.GREGORIAN_ME_FRENCH:
+ return "ar-DZ"; // "ar-DZ" Algeria
+
+ case CalendarId.GREGORIAN_XLIT_ENGLISH:
+ case CalendarId.GREGORIAN_XLIT_FRENCH:
+ return "ar-IQ"; // "ar-IQ"; Iraq
+
+ default:
+ // Default to gregorian en-US
+ break;
+ }
+
+ return "en-US";
+ }
+ }
+}
+
diff --git a/src/mscorlib/corefx/System/Globalization/CalendarWeekRule.cs b/src/mscorlib/corefx/System/Globalization/CalendarWeekRule.cs
new file mode 100644
index 0000000000..490951e1f0
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/CalendarWeekRule.cs
@@ -0,0 +1,19 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.Globalization
+{
+ [Serializable]
+ [System.Runtime.InteropServices.ComVisible(true)]
+ public enum CalendarWeekRule
+ {
+ FirstDay = 0, // Week 1 begins on the first day of the year
+
+ FirstFullWeek = 1, // Week 1 begins on first FirstDayOfWeek not before the first day of the year
+
+ FirstFourDayWeek = 2 // Week 1 begins on first FirstDayOfWeek such that FirstDayOfWeek+3 is not before the first day of the year
+ };
+}
diff --git a/src/mscorlib/corefx/System/Globalization/CalendricalCalculationsHelper.cs b/src/mscorlib/corefx/System/Globalization/CalendricalCalculationsHelper.cs
new file mode 100644
index 0000000000..ba7601b420
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/CalendricalCalculationsHelper.cs
@@ -0,0 +1,413 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Diagnostics.Contracts;
+
+namespace System.Globalization
+{
+ internal class CalendricalCalculationsHelper
+ {
+ private const double FullCircleOfArc = 360.0; // 360.0;
+ private const int HalfCircleOfArc = 180;
+ private const double TwelveHours = 0.5; // half a day
+ private const double Noon2000Jan01 = 730120.5;
+ internal const double MeanTropicalYearInDays = 365.242189;
+ private const double MeanSpeedOfSun = MeanTropicalYearInDays / FullCircleOfArc;
+ private const double LongitudeSpring = 0.0;
+ private const double TwoDegreesAfterSpring = 2.0;
+ private const int SecondsPerDay = 24 * 60 * 60; // 24 hours * 60 minutes * 60 seconds
+
+ private const int DaysInUniformLengthCentury = 36525;
+ private const int SecondsPerMinute = 60;
+ private const int MinutesPerDegree = 60;
+
+ private static readonly long StartOf1810 = GetNumberOfDays(new DateTime(1810, 1, 1));
+ private static readonly long StartOf1900Century = GetNumberOfDays(new DateTime(1900, 1, 1));
+
+ private static readonly double[] s_coefficients1900to1987 = new double[] { -0.00002, 0.000297, 0.025184, -0.181133, 0.553040, -0.861938, 0.677066, -0.212591 };
+ private static readonly double[] s_coefficients1800to1899 = new double[] { -0.000009, 0.003844, 0.083563, 0.865736, 4.867575, 15.845535, 31.332267, 38.291999, 28.316289, 11.636204, 2.043794 };
+ private static readonly double[] s_coefficients1700to1799 = new double[] { 8.118780842, -0.005092142, 0.003336121, -0.0000266484 };
+ private static readonly double[] s_coefficients1620to1699 = new double[] { 196.58333, -4.0675, 0.0219167 };
+ private static readonly double[] s_lambdaCoefficients = new double[] { 280.46645, 36000.76983, 0.0003032 };
+ private static readonly double[] s_anomalyCoefficients = new double[] { 357.52910, 35999.05030, -0.0001559, -0.00000048 };
+ private static readonly double[] s_eccentricityCoefficients = new double[] { 0.016708617, -0.000042037, -0.0000001236 };
+ private static readonly double[] s_coefficients = new double[] { Angle(23, 26, 21.448), Angle(0, 0, -46.8150), Angle(0, 0, -0.00059), Angle(0, 0, 0.001813) };
+ private static readonly double[] s_coefficientsA = new double[] { 124.90, -1934.134, 0.002063 };
+ private static readonly double[] s_coefficientsB = new double[] { 201.11, 72001.5377, 0.00057 };
+
+ private static double RadiansFromDegrees(double degree)
+ {
+ return degree * Math.PI / 180;
+ }
+
+ private static double SinOfDegree(double degree)
+ {
+ return Math.Sin(RadiansFromDegrees(degree));
+ }
+
+ private static double CosOfDegree(double degree)
+ {
+ return Math.Cos(RadiansFromDegrees(degree));
+ }
+ private static double TanOfDegree(double degree)
+ {
+ return Math.Tan(RadiansFromDegrees(degree));
+ }
+
+ public static double Angle(int degrees, int minutes, double seconds)
+ {
+ return ((seconds / SecondsPerMinute + minutes) / MinutesPerDegree) + degrees;
+ }
+
+ private static double Obliquity(double julianCenturies)
+ {
+ return PolynomialSum(s_coefficients, julianCenturies);
+ }
+
+ internal static long GetNumberOfDays(DateTime date)
+ {
+ return date.Ticks / GregorianCalendar.TicksPerDay;
+ }
+
+ private static int GetGregorianYear(double numberOfDays)
+ {
+ return new DateTime(Math.Min((long)(Math.Floor(numberOfDays) * GregorianCalendar.TicksPerDay), DateTime.MaxValue.Ticks)).Year;
+ }
+
+ private enum CorrectionAlgorithm
+ {
+ Default,
+ Year1988to2019,
+ Year1900to1987,
+ Year1800to1899,
+ Year1700to1799,
+ Year1620to1699
+ }
+
+ private struct EphemerisCorrectionAlgorithmMap
+ {
+ public EphemerisCorrectionAlgorithmMap(int year, CorrectionAlgorithm algorithm)
+ {
+ _lowestYear = year;
+ _algorithm = algorithm;
+ }
+
+ internal int _lowestYear;
+ internal CorrectionAlgorithm _algorithm;
+ };
+
+ private static readonly EphemerisCorrectionAlgorithmMap[] s_ephemerisCorrectionTable = new EphemerisCorrectionAlgorithmMap[]
+ {
+ // lowest year that starts algorithm, algorithm to use
+ new EphemerisCorrectionAlgorithmMap(2020, CorrectionAlgorithm.Default),
+ new EphemerisCorrectionAlgorithmMap(1988, CorrectionAlgorithm.Year1988to2019),
+ new EphemerisCorrectionAlgorithmMap(1900, CorrectionAlgorithm.Year1900to1987),
+ new EphemerisCorrectionAlgorithmMap(1800, CorrectionAlgorithm.Year1800to1899),
+ new EphemerisCorrectionAlgorithmMap(1700, CorrectionAlgorithm.Year1700to1799),
+ new EphemerisCorrectionAlgorithmMap(1620, CorrectionAlgorithm.Year1620to1699),
+ new EphemerisCorrectionAlgorithmMap(int.MinValue, CorrectionAlgorithm.Default) // default must be last
+ };
+
+ private static double Reminder(double divisor, double dividend)
+ {
+ double whole = Math.Floor(divisor / dividend);
+ return divisor - (dividend * whole);
+ }
+
+ private static double NormalizeLongitude(double longitude)
+ {
+ longitude = Reminder(longitude, FullCircleOfArc);
+ if (longitude < 0)
+ {
+ longitude += FullCircleOfArc;
+ }
+ return longitude;
+ }
+
+ static public double AsDayFraction(double longitude)
+ {
+ return longitude / FullCircleOfArc;
+ }
+
+ private static double PolynomialSum(double[] coefficients, double indeterminate)
+ {
+ double sum = coefficients[0];
+ double indeterminateRaised = 1;
+ for (int i = 1; i < coefficients.Length; i++)
+ {
+ indeterminateRaised *= indeterminate;
+ sum += (coefficients[i] * indeterminateRaised);
+ }
+
+ return sum;
+ }
+
+ private static double CenturiesFrom1900(int gregorianYear)
+ {
+ long july1stOfYear = GetNumberOfDays(new DateTime(gregorianYear, 7, 1));
+ return (double)(july1stOfYear - StartOf1900Century) / DaysInUniformLengthCentury;
+ }
+
+ // the following formulas defines a polynomial function which gives us the amount that the earth is slowing down for specific year ranges
+ private static double DefaultEphemerisCorrection(int gregorianYear)
+ {
+ Contract.Assert(gregorianYear < 1620 || 2020 <= gregorianYear);
+ long january1stOfYear = GetNumberOfDays(new DateTime(gregorianYear, 1, 1));
+ double daysSinceStartOf1810 = january1stOfYear - StartOf1810;
+ double x = TwelveHours + daysSinceStartOf1810;
+ return ((Math.Pow(x, 2) / 41048480) - 15) / SecondsPerDay;
+ }
+
+ private static double EphemerisCorrection1988to2019(int gregorianYear)
+ {
+ Contract.Assert(1988 <= gregorianYear && gregorianYear <= 2019);
+ return (double)(gregorianYear - 1933) / SecondsPerDay;
+ }
+
+ private static double EphemerisCorrection1900to1987(int gregorianYear)
+ {
+ Contract.Assert(1900 <= gregorianYear && gregorianYear <= 1987);
+ double centuriesFrom1900 = CenturiesFrom1900(gregorianYear);
+ return PolynomialSum(s_coefficients1900to1987, centuriesFrom1900);
+ }
+
+ private static double EphemerisCorrection1800to1899(int gregorianYear)
+ {
+ Contract.Assert(1800 <= gregorianYear && gregorianYear <= 1899);
+ double centuriesFrom1900 = CenturiesFrom1900(gregorianYear);
+ return PolynomialSum(s_coefficients1800to1899, centuriesFrom1900);
+ }
+
+ private static double EphemerisCorrection1700to1799(int gregorianYear)
+ {
+ Contract.Assert(1700 <= gregorianYear && gregorianYear <= 1799);
+ double yearsSince1700 = gregorianYear - 1700;
+ return PolynomialSum(s_coefficients1700to1799, yearsSince1700) / SecondsPerDay;
+ }
+
+ private static double EphemerisCorrection1620to1699(int gregorianYear)
+ {
+ Contract.Assert(1620 <= gregorianYear && gregorianYear <= 1699);
+ double yearsSince1600 = gregorianYear - 1600;
+ return PolynomialSum(s_coefficients1620to1699, yearsSince1600) / SecondsPerDay;
+ }
+
+ // ephemeris-correction: correction to account for the slowing down of the rotation of the earth
+ private static double EphemerisCorrection(double time)
+ {
+ int year = GetGregorianYear(time);
+ foreach (EphemerisCorrectionAlgorithmMap map in s_ephemerisCorrectionTable)
+ {
+ if (map._lowestYear <= year)
+ {
+ switch (map._algorithm)
+ {
+ case CorrectionAlgorithm.Default: return DefaultEphemerisCorrection(year);
+ case CorrectionAlgorithm.Year1988to2019: return EphemerisCorrection1988to2019(year);
+ case CorrectionAlgorithm.Year1900to1987: return EphemerisCorrection1900to1987(year);
+ case CorrectionAlgorithm.Year1800to1899: return EphemerisCorrection1800to1899(year);
+ case CorrectionAlgorithm.Year1700to1799: return EphemerisCorrection1700to1799(year);
+ case CorrectionAlgorithm.Year1620to1699: return EphemerisCorrection1620to1699(year);
+ }
+
+ break; // break the loop and assert eventually
+ }
+ }
+
+ Contract.Assert(false, "Not expected to come here");
+ return DefaultEphemerisCorrection(year);
+ }
+
+ static public double JulianCenturies(double moment)
+ {
+ double dynamicalMoment = moment + EphemerisCorrection(moment);
+ return (dynamicalMoment - Noon2000Jan01) / DaysInUniformLengthCentury;
+ }
+
+ private static bool IsNegative(double value)
+ {
+ return Math.Sign(value) == -1;
+ }
+
+ private static double CopySign(double value, double sign)
+ {
+ return (IsNegative(value) == IsNegative(sign)) ? value : -value;
+ }
+
+ // equation-of-time; approximate the difference between apparent solar time and mean solar time
+ // formal definition is EOT = GHA - GMHA
+ // GHA is the Greenwich Hour Angle of the apparent (actual) Sun
+ // GMHA is the Greenwich Mean Hour Angle of the mean (fictitious) Sun
+ // http://www.esrl.noaa.gov/gmd/grad/solcalc/
+ // http://en.wikipedia.org/wiki/Equation_of_time
+ private static double EquationOfTime(double time)
+ {
+ double julianCenturies = JulianCenturies(time);
+ double lambda = PolynomialSum(s_lambdaCoefficients, julianCenturies);
+ double anomaly = PolynomialSum(s_anomalyCoefficients, julianCenturies);
+ double eccentricity = PolynomialSum(s_eccentricityCoefficients, julianCenturies);
+
+ double epsilon = Obliquity(julianCenturies);
+ double tanHalfEpsilon = TanOfDegree(epsilon / 2);
+ double y = tanHalfEpsilon * tanHalfEpsilon;
+
+ double dividend = ((y * SinOfDegree(2 * lambda))
+ - (2 * eccentricity * SinOfDegree(anomaly))
+ + (4 * eccentricity * y * SinOfDegree(anomaly) * CosOfDegree(2 * lambda))
+ - (0.5 * Math.Pow(y, 2) * SinOfDegree(4 * lambda))
+ - (1.25 * Math.Pow(eccentricity, 2) * SinOfDegree(2 * anomaly)));
+ double divisor = 2 * Math.PI;
+ double equation = dividend / divisor;
+
+ // approximation of equation of time is not valid for dates that are many millennia in the past or future
+ // thus limited to a half day
+ return CopySign(Math.Min(Math.Abs(equation), TwelveHours), equation);
+ }
+
+ private static double AsLocalTime(double apparentMidday, double longitude)
+ {
+ // slightly inaccurate since equation of time takes mean time not apparent time as its argument, but the difference is negligible
+ double universalTime = apparentMidday - AsDayFraction(longitude);
+ return apparentMidday - EquationOfTime(universalTime);
+ }
+
+ // midday
+ static public double Midday(double date, double longitude)
+ {
+ return AsLocalTime(date + TwelveHours, longitude) - AsDayFraction(longitude);
+ }
+
+ private static double InitLongitude(double longitude)
+ {
+ return NormalizeLongitude(longitude + HalfCircleOfArc) - HalfCircleOfArc;
+ }
+
+ // midday-in-tehran
+ static public double MiddayAtPersianObservationSite(double date)
+ {
+ return Midday(date, InitLongitude(52.5)); // 52.5 degrees east - longitude of UTC+3:30 which defines Iranian Standard Time
+ }
+
+ private static double PeriodicTerm(double julianCenturies, int x, double y, double z)
+ {
+ return x * SinOfDegree(y + z * julianCenturies);
+ }
+
+ private static double SumLongSequenceOfPeriodicTerms(double julianCenturies)
+ {
+ double sum = 0.0;
+ sum += PeriodicTerm(julianCenturies, 403406, 270.54861, 0.9287892);
+ sum += PeriodicTerm(julianCenturies, 195207, 340.19128, 35999.1376958);
+ sum += PeriodicTerm(julianCenturies, 119433, 63.91854, 35999.4089666);
+ sum += PeriodicTerm(julianCenturies, 112392, 331.2622, 35998.7287385);
+ sum += PeriodicTerm(julianCenturies, 3891, 317.843, 71998.20261);
+ sum += PeriodicTerm(julianCenturies, 2819, 86.631, 71998.4403);
+ sum += PeriodicTerm(julianCenturies, 1721, 240.052, 36000.35726);
+ sum += PeriodicTerm(julianCenturies, 660, 310.26, 71997.4812);
+ sum += PeriodicTerm(julianCenturies, 350, 247.23, 32964.4678);
+ sum += PeriodicTerm(julianCenturies, 334, 260.87, -19.441);
+ sum += PeriodicTerm(julianCenturies, 314, 297.82, 445267.1117);
+ sum += PeriodicTerm(julianCenturies, 268, 343.14, 45036.884);
+ sum += PeriodicTerm(julianCenturies, 242, 166.79, 3.1008);
+ sum += PeriodicTerm(julianCenturies, 234, 81.53, 22518.4434);
+ sum += PeriodicTerm(julianCenturies, 158, 3.5, -19.9739);
+ sum += PeriodicTerm(julianCenturies, 132, 132.75, 65928.9345);
+ sum += PeriodicTerm(julianCenturies, 129, 182.95, 9038.0293);
+ sum += PeriodicTerm(julianCenturies, 114, 162.03, 3034.7684);
+ sum += PeriodicTerm(julianCenturies, 99, 29.8, 33718.148);
+ sum += PeriodicTerm(julianCenturies, 93, 266.4, 3034.448);
+ sum += PeriodicTerm(julianCenturies, 86, 249.2, -2280.773);
+ sum += PeriodicTerm(julianCenturies, 78, 157.6, 29929.992);
+ sum += PeriodicTerm(julianCenturies, 72, 257.8, 31556.493);
+ sum += PeriodicTerm(julianCenturies, 68, 185.1, 149.588);
+ sum += PeriodicTerm(julianCenturies, 64, 69.9, 9037.75);
+ sum += PeriodicTerm(julianCenturies, 46, 8.0, 107997.405);
+ sum += PeriodicTerm(julianCenturies, 38, 197.1, -4444.176);
+ sum += PeriodicTerm(julianCenturies, 37, 250.4, 151.771);
+ sum += PeriodicTerm(julianCenturies, 32, 65.3, 67555.316);
+ sum += PeriodicTerm(julianCenturies, 29, 162.7, 31556.08);
+ sum += PeriodicTerm(julianCenturies, 28, 341.5, -4561.54);
+ sum += PeriodicTerm(julianCenturies, 27, 291.6, 107996.706);
+ sum += PeriodicTerm(julianCenturies, 27, 98.5, 1221.655);
+ sum += PeriodicTerm(julianCenturies, 25, 146.7, 62894.167);
+ sum += PeriodicTerm(julianCenturies, 24, 110.0, 31437.369);
+ sum += PeriodicTerm(julianCenturies, 21, 5.2, 14578.298);
+ sum += PeriodicTerm(julianCenturies, 21, 342.6, -31931.757);
+ sum += PeriodicTerm(julianCenturies, 20, 230.9, 34777.243);
+ sum += PeriodicTerm(julianCenturies, 18, 256.1, 1221.999);
+ sum += PeriodicTerm(julianCenturies, 17, 45.3, 62894.511);
+ sum += PeriodicTerm(julianCenturies, 14, 242.9, -4442.039);
+ sum += PeriodicTerm(julianCenturies, 13, 115.2, 107997.909);
+ sum += PeriodicTerm(julianCenturies, 13, 151.8, 119.066);
+ sum += PeriodicTerm(julianCenturies, 13, 285.3, 16859.071);
+ sum += PeriodicTerm(julianCenturies, 12, 53.3, -4.578);
+ sum += PeriodicTerm(julianCenturies, 10, 126.6, 26895.292);
+ sum += PeriodicTerm(julianCenturies, 10, 205.7, -39.127);
+ sum += PeriodicTerm(julianCenturies, 10, 85.9, 12297.536);
+ sum += PeriodicTerm(julianCenturies, 10, 146.1, 90073.778);
+ return sum;
+ }
+
+ private static double Aberration(double julianCenturies)
+ {
+ return (0.0000974 * CosOfDegree(177.63 + (35999.01848 * julianCenturies))) - 0.005575;
+ }
+
+ private static double Nutation(double julianCenturies)
+ {
+ double a = PolynomialSum(s_coefficientsA, julianCenturies);
+ double b = PolynomialSum(s_coefficientsB, julianCenturies);
+ return (-0.004778 * SinOfDegree(a)) - (0.0003667 * SinOfDegree(b));
+ }
+
+ static public double Compute(double time)
+ {
+ double julianCenturies = JulianCenturies(time);
+ double lambda = 282.7771834
+ + (36000.76953744 * julianCenturies)
+ + (0.000005729577951308232 * SumLongSequenceOfPeriodicTerms(julianCenturies));
+
+ double longitude = lambda + Aberration(julianCenturies) + Nutation(julianCenturies);
+ return InitLongitude(longitude);
+ }
+
+ static public double AsSeason(double longitude)
+ {
+ return (longitude < 0) ? (longitude + FullCircleOfArc) : longitude;
+ }
+
+ private static double EstimatePrior(double longitude, double time)
+ {
+ double timeSunLastAtLongitude = time - (MeanSpeedOfSun * AsSeason(InitLongitude(Compute(time) - longitude)));
+ double longitudeErrorDelta = InitLongitude(Compute(timeSunLastAtLongitude) - longitude);
+ return Math.Min(time, timeSunLastAtLongitude - (MeanSpeedOfSun * longitudeErrorDelta));
+ }
+
+ // persian-new-year-on-or-before
+ // number of days is the absolute date. The absolute date is the number of days from January 1st, 1 A.D.
+ // 1/1/0001 is absolute date 1.
+ internal static long PersianNewYearOnOrBefore(long numberOfDays)
+ {
+ double date = (double)numberOfDays;
+
+ double approx = EstimatePrior(LongitudeSpring, MiddayAtPersianObservationSite(date));
+ long lowerBoundNewYearDay = (long)Math.Floor(approx) - 1;
+ long upperBoundNewYearDay = lowerBoundNewYearDay + 3; // estimate is generally within a day of the actual occurrance (at the limits, the error expands, since the calculations rely on the mean tropical year which changes...)
+ long day = lowerBoundNewYearDay;
+ for (; day != upperBoundNewYearDay; ++day)
+ {
+ double midday = MiddayAtPersianObservationSite((double)day);
+ double l = Compute(midday);
+ if ((LongitudeSpring <= l) && (l <= TwoDegreesAfterSpring))
+ {
+ break;
+ }
+ }
+ Contract.Assert(day != upperBoundNewYearDay);
+
+ return day - 1;
+ }
+ }
+}
diff --git a/src/mscorlib/corefx/System/Globalization/CharUnicodeInfo.cs b/src/mscorlib/corefx/System/Globalization/CharUnicodeInfo.cs
new file mode 100644
index 0000000000..4cb95fb8f1
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/CharUnicodeInfo.cs
@@ -0,0 +1,339 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+////////////////////////////////////////////////////////////////////////////
+//
+//
+// Purpose: This class implements a set of methods for retrieving
+// character type information. Character type information is
+// independent of culture and region.
+//
+//
+////////////////////////////////////////////////////////////////////////////
+
+using System;
+using System.Threading;
+using System.Runtime.InteropServices;
+using System.Runtime.CompilerServices;
+using System.Reflection;
+using System.Security;
+using System.Diagnostics.Contracts;
+
+namespace System.Globalization
+{
+ public static partial class CharUnicodeInfo
+ {
+ //--------------------------------------------------------------------//
+ // Internal Information //
+ //--------------------------------------------------------------------//
+
+ //
+ // Native methods to access the Unicode category data tables in charinfo.nlp.
+ //
+ internal const char HIGH_SURROGATE_START = '\ud800';
+ internal const char HIGH_SURROGATE_END = '\udbff';
+ internal const char LOW_SURROGATE_START = '\udc00';
+ internal const char LOW_SURROGATE_END = '\udfff';
+
+ internal const int UNICODE_CATEGORY_OFFSET = 0;
+ internal const int BIDI_CATEGORY_OFFSET = 1;
+
+
+
+ // The starting codepoint for Unicode plane 1. Plane 1 contains 0x010000 ~ 0x01ffff.
+ internal const int UNICODE_PLANE01_START = 0x10000;
+
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Actions:
+ // Convert the BMP character or surrogate pointed by index to a UTF32 value.
+ // This is similar to Char.ConvertToUTF32, but the difference is that
+ // it does not throw exceptions when invalid surrogate characters are passed in.
+ //
+ // WARNING: since it doesn't throw an exception it CAN return a value
+ // in the surrogate range D800-DFFF, which are not legal unicode values.
+ //
+ ////////////////////////////////////////////////////////////////////////
+
+ internal static int InternalConvertToUtf32(String s, int index)
+ {
+ Contract.Assert(s != null, "s != null");
+ Contract.Assert(index >= 0 && index < s.Length, "index < s.Length");
+ if (index < s.Length - 1)
+ {
+ int temp1 = (int)s[index] - HIGH_SURROGATE_START;
+ if (temp1 >= 0 && temp1 <= 0x3ff)
+ {
+ int temp2 = (int)s[index + 1] - LOW_SURROGATE_START;
+ if (temp2 >= 0 && temp2 <= 0x3ff)
+ {
+ // Convert the surrogate to UTF32 and get the result.
+ return ((temp1 * 0x400) + temp2 + UNICODE_PLANE01_START);
+ }
+ }
+ }
+ return ((int)s[index]);
+ }
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Convert a character or a surrogate pair starting at index of string s
+ // to UTF32 value.
+ //
+ // Parameters:
+ // s The string
+ // index The starting index. It can point to a BMP character or
+ // a surrogate pair.
+ // len The length of the string.
+ // charLength [out] If the index points to a BMP char, charLength
+ // will be 1. If the index points to a surrogate pair,
+ // charLength will be 2.
+ //
+ // WARNING: since it doesn't throw an exception it CAN return a value
+ // in the surrogate range D800-DFFF, which are not legal unicode values.
+ //
+ // Returns:
+ // The UTF32 value
+ //
+ ////////////////////////////////////////////////////////////////////////
+
+ internal static int InternalConvertToUtf32(String s, int index, out int charLength)
+ {
+ Contract.Assert(s != null, "s != null");
+ Contract.Assert(s.Length > 0, "s.Length > 0");
+ Contract.Assert(index >= 0 && index < s.Length, "index >= 0 && index < s.Length");
+ charLength = 1;
+ if (index < s.Length - 1)
+ {
+ int temp1 = (int)s[index] - HIGH_SURROGATE_START;
+ if (temp1 >= 0 && temp1 <= 0x3ff)
+ {
+ int temp2 = (int)s[index + 1] - LOW_SURROGATE_START;
+ if (temp2 >= 0 && temp2 <= 0x3ff)
+ {
+ // Convert the surrogate to UTF32 and get the result.
+ charLength++;
+ return ((temp1 * 0x400) + temp2 + UNICODE_PLANE01_START);
+ }
+ }
+ }
+ return ((int)s[index]);
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // IsWhiteSpace
+ //
+ // Determines if the given character is a white space character.
+ //
+ ////////////////////////////////////////////////////////////////////////
+
+ internal static bool IsWhiteSpace(String s, int index)
+ {
+ Contract.Assert(s != null, "s!=null");
+ Contract.Assert(index >= 0 && index < s.Length, "index >= 0 && index < s.Length");
+
+ UnicodeCategory uc = GetUnicodeCategory(s, index);
+ // In Unicode 3.0, U+2028 is the only character which is under the category "LineSeparator".
+ // And U+2029 is th eonly character which is under the category "ParagraphSeparator".
+ switch (uc)
+ {
+ case (UnicodeCategory.SpaceSeparator):
+ case (UnicodeCategory.LineSeparator):
+ case (UnicodeCategory.ParagraphSeparator):
+ return (true);
+ }
+ return (false);
+ }
+
+
+ internal static bool IsWhiteSpace(char c)
+ {
+ UnicodeCategory uc = GetUnicodeCategory(c);
+ // In Unicode 3.0, U+2028 is the only character which is under the category "LineSeparator".
+ // And U+2029 is th eonly character which is under the category "ParagraphSeparator".
+ switch (uc)
+ {
+ case (UnicodeCategory.SpaceSeparator):
+ case (UnicodeCategory.LineSeparator):
+ case (UnicodeCategory.ParagraphSeparator):
+ return (true);
+ }
+
+ return (false);
+ }
+
+
+ //
+ // This is called by the public char and string, index versions
+ //
+ // Note that for ch in the range D800-DFFF we just treat it as any other non-numeric character
+ //
+ internal unsafe static double InternalGetNumericValue(int ch)
+ {
+ Contract.Assert(ch >= 0 && ch <= 0x10ffff, "ch is not in valid Unicode range.");
+ // Get the level 2 item from the highest 12 bit (8 - 19) of ch.
+ ushort index = s_pNumericLevel1Index[ch >> 8];
+ // Get the level 2 WORD offset from the 4 - 7 bit of ch. This provides the base offset of the level 3 table.
+ // The offset is referred to an float item in m_pNumericFloatData.
+ // Note that & has the lower precedence than addition, so don't forget the parathesis.
+ index = s_pNumericLevel1Index[index + ((ch >> 4) & 0x000f)];
+
+ fixed (ushort* pUshortPtr = &(s_pNumericLevel1Index[index]))
+ {
+ byte* pBytePtr = (byte*)pUshortPtr;
+ fixed (byte* pByteNum = s_pNumericValues)
+ {
+ double* pDouble = (double*)pByteNum;
+ return pDouble[pBytePtr[(ch & 0x000f)]];
+ }
+ }
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //Returns the numeric value associated with the character c. If the character is a fraction,
+ // the return value will not be an integer. If the character does not have a numeric value, the return value is -1.
+ //
+ //Returns:
+ // the numeric value for the specified Unicode character. If the character does not have a numeric value, the return value is -1.
+ //Arguments:
+ // ch a Unicode character
+ //Exceptions:
+ // ArgumentNullException
+ // ArgumentOutOfRangeException
+ //
+ ////////////////////////////////////////////////////////////////////////
+
+
+ public static double GetNumericValue(char ch)
+ {
+ return (InternalGetNumericValue(ch));
+ }
+
+
+ public static double GetNumericValue(String s, int index)
+ {
+ if (s == null)
+ {
+ throw new ArgumentNullException("s");
+ }
+ if (index < 0 || index >= s.Length)
+ {
+ throw new ArgumentOutOfRangeException("index", SR.ArgumentOutOfRange_Index);
+ }
+ Contract.EndContractBlock();
+ return (InternalGetNumericValue(InternalConvertToUtf32(s, index)));
+ }
+
+ public static UnicodeCategory GetUnicodeCategory(char ch)
+ {
+ return (InternalGetUnicodeCategory(ch));
+ }
+
+ public static UnicodeCategory GetUnicodeCategory(String s, int index)
+ {
+ if (s == null)
+ throw new ArgumentNullException("s");
+ if (((uint)index) >= ((uint)s.Length))
+ {
+ throw new ArgumentOutOfRangeException("index");
+ }
+ Contract.EndContractBlock();
+ return InternalGetUnicodeCategory(s, index);
+ }
+
+ internal unsafe static UnicodeCategory InternalGetUnicodeCategory(int ch)
+ {
+ return ((UnicodeCategory)InternalGetCategoryValue(ch, UNICODE_CATEGORY_OFFSET));
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //Action: Returns the Unicode Category property for the character c.
+ //Returns:
+ // an value in UnicodeCategory enum
+ //Arguments:
+ // ch a Unicode character
+ //Exceptions:
+ // None
+ //
+ //Note that this API will return values for D800-DF00 surrogate halves.
+ //
+ ////////////////////////////////////////////////////////////////////////
+
+ internal unsafe static byte InternalGetCategoryValue(int ch, int offset)
+ {
+ Contract.Assert(ch >= 0 && ch <= 0x10ffff, "ch is not in valid Unicode range.");
+ // Get the level 2 item from the highest 12 bit (8 - 19) of ch.
+ ushort index = s_pCategoryLevel1Index[ch >> 8];
+ // Get the level 2 WORD offset from the 4 - 7 bit of ch. This provides the base offset of the level 3 table.
+ // Note that & has the lower precedence than addition, so don't forget the parathesis.
+ index = s_pCategoryLevel1Index[index + ((ch >> 4) & 0x000f)];
+
+ fixed (ushort* pUshortPtr = &(s_pCategoryLevel1Index[index]))
+ {
+ byte* pBytePtr = (byte*)pUshortPtr;
+ // Get the result from the 0 -3 bit of ch.
+ byte valueIndex = pBytePtr[(ch & 0x000f)];
+ byte uc = s_pCategoriesValue[valueIndex * 2 + offset];
+ //
+ // Make sure that OtherNotAssigned is the last category in UnicodeCategory.
+ // If that changes, change the following assertion as well.
+ //
+ //Contract.Assert(uc >= 0 && uc <= UnicodeCategory.OtherNotAssigned, "Table returns incorrect Unicode category");
+ return (uc);
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //Action: Returns the Unicode Category property for the character c.
+ //Returns:
+ // an value in UnicodeCategory enum
+ //Arguments:
+ // value a Unicode String
+ // index Index for the specified string.
+ //Exceptions:
+ // None
+ //
+ ////////////////////////////////////////////////////////////////////////
+
+ internal static UnicodeCategory InternalGetUnicodeCategory(String value, int index)
+ {
+ Contract.Assert(value != null, "value can not be null");
+ Contract.Assert(index < value.Length, "index < value.Length");
+
+ return (InternalGetUnicodeCategory(InternalConvertToUtf32(value, index)));
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Get the Unicode category of the character starting at index. If the character is in BMP, charLength will return 1.
+ // If the character is a valid surrogate pair, charLength will return 2.
+ //
+ ////////////////////////////////////////////////////////////////////////
+
+ internal static UnicodeCategory InternalGetUnicodeCategory(String str, int index, out int charLength)
+ {
+ Contract.Assert(str != null, "str can not be null");
+ Contract.Assert(str.Length > 0, "str.Length > 0"); ;
+ Contract.Assert(index >= 0 && index < str.Length, "index >= 0 && index < str.Length");
+
+ return (InternalGetUnicodeCategory(InternalConvertToUtf32(str, index, out charLength)));
+ }
+
+ internal static bool IsCombiningCategory(UnicodeCategory uc)
+ {
+ Contract.Assert(uc >= 0, "uc >= 0");
+ return (
+ uc == UnicodeCategory.NonSpacingMark ||
+ uc == UnicodeCategory.SpacingCombiningMark ||
+ uc == UnicodeCategory.EnclosingMark
+ );
+ }
+ }
+}
diff --git a/src/mscorlib/corefx/System/Globalization/CharUnicodeInfoData.cs b/src/mscorlib/corefx/System/Globalization/CharUnicodeInfoData.cs
new file mode 100644
index 0000000000..7284cfd3bc
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/CharUnicodeInfoData.cs
@@ -0,0 +1,1222 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.Globalization
+{
+ public static partial class CharUnicodeInfo
+ {
+ // THE FOLLOWING DATA IS AUTO GENERATED BY GenUnicodeProp.pl SCRIPT UNDER THE TOOLS FOLDER
+ // PLEASE DON'T MODIFY BY HAND
+
+
+ // 12:4:4 index table of the Unicode cateogry data.
+ private static ushort[] s_pCategoryLevel1Index = new ushort[]
+ {
+ 0x1100, 0x1110, 0x1120, 0x1130, 0x1140, 0x1150, 0x1160, 0x1170, 0x1180, 0x1190, 0x11a0, 0x11b0, 0x11c0, 0x11d0, 0x11e0, 0x11f0,
+ 0x1200, 0x1210, 0x1220, 0x1230, 0x1240, 0x1210, 0x1250, 0x1260, 0x1270, 0x1280, 0x1290, 0x12a0, 0x12b0, 0x12c0, 0x12d0, 0x12e0,
+ 0x12f0, 0x1300, 0x1310, 0x1320, 0x1330, 0x1340, 0x1350, 0x1360, 0x1370, 0x1380, 0x1390, 0x13a0, 0x13b0, 0x13c0, 0x13d0, 0x13e0,
+ 0x13f0, 0x1400, 0x1410, 0x1420, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210,
+ 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1430, 0x1210, 0x1210,
+ 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210,
+ 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210,
+ 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210,
+ 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210,
+ 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1440,
+ 0x1450, 0x1210, 0x1210, 0x1210, 0x1460, 0x1210, 0x1470, 0x1480, 0x1490, 0x14a0, 0x14b0, 0x14c0, 0x1210, 0x1210, 0x1210, 0x1210,
+ 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210,
+ 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210,
+ 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x14d0, 0x14e0, 0x14e0, 0x14e0, 0x14e0, 0x14e0, 0x14e0, 0x14e0, 0x14e0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x1210, 0x1500, 0x1510, 0x1520, 0x1530, 0x1540, 0x1550,
+ 0x1560, 0x1570, 0x1580, 0x1590, 0x15a0, 0x15b0, 0x1210, 0x15c0, 0x15d0, 0x15e0, 0x15f0, 0x1600, 0x1610, 0x1620, 0x1630, 0x1620,
+ 0x1640, 0x1650, 0x1660, 0x1670, 0x1680, 0x1690, 0x16a0, 0x16b0, 0x16c0, 0x1620, 0x16d0, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1210, 0x1210, 0x1210, 0x16e0, 0x16f0, 0x1700, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1210, 0x1210, 0x1210, 0x1210, 0x1710, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1210, 0x1210, 0x1720, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1210, 0x1210, 0x1730, 0x1740, 0x1620, 0x1620, 0x1620, 0x1750,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1760, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1770, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1780, 0x1790, 0x17a0, 0x17b0, 0x17c0, 0x17d0, 0x17e0, 0x17f0, 0x1370, 0x1370, 0x1800, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1810, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1820, 0x1620,
+ 0x1830, 0x1840, 0x1850, 0x1860, 0x1870, 0x1880, 0x1890, 0x18a0, 0x18b0, 0x18c0, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210,
+ 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210,
+ 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210,
+ 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210,
+ 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210,
+ 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210,
+ 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210,
+ 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210,
+ 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210,
+ 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210,
+ 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x18d0, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210,
+ 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x18e0, 0x18f0, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210,
+ 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1210, 0x1900, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1210, 0x1210, 0x1910, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1920, 0x1930, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620, 0x1620,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x1940,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0,
+ 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x14f0, 0x1940,
+ 0x1950, 0x1958, 0x1960, 0x1968, 0x1970, 0x1978, 0x1980, 0x1988, 0x1990, 0x1998, 0x19a0, 0x19a8, 0x19b0, 0x19b8, 0x19c0, 0x19c8,
+ 0x19d0, 0x19d0, 0x19d0, 0x19d8, 0x19e0, 0x19d0, 0x19d0, 0x19e8, 0x19f0, 0x19f8, 0x1a00, 0x1a08, 0x1a10, 0x1a18, 0x19d0, 0x1a20,
+ 0x19d0, 0x19d0, 0x19d0, 0x1a28, 0x1a30, 0x19c0, 0x19c0, 0x19c0, 0x19c0, 0x1a38, 0x19c0, 0x1a40, 0x1a48, 0x1a50, 0x1a58, 0x1a60,
+ 0x1a68, 0x1a68, 0x1a68, 0x1a68, 0x1a68, 0x1a68, 0x1a68, 0x1a70, 0x1a78, 0x1a80, 0x1a88, 0x19c0, 0x1a90, 0x1a98, 0x19d0, 0x1aa0,
+ 0x19b0, 0x19b0, 0x19b0, 0x19c0, 0x19c0, 0x19c0, 0x19d0, 0x19d0, 0x1aa8, 0x19d0, 0x19d0, 0x19d0, 0x1ab0, 0x19d0, 0x19d0, 0x19d0,
+ 0x19d0, 0x19d0, 0x19d0, 0x1ab8, 0x19b0, 0x1ac0, 0x1ac8, 0x19c0, 0x1ad0, 0x1ad8, 0x1a68, 0x1ae0, 0x1ae8, 0x1af0, 0x1af8, 0x1b00,
+ 0x1b08, 0x1b10, 0x1b18, 0x1b18, 0x1b20, 0x1a68, 0x1b28, 0x1b30, 0x1b18, 0x1b18, 0x1b18, 0x1b18, 0x1b18, 0x1b38, 0x1b40, 0x1b48,
+ 0x1b50, 0x1b58, 0x1b18, 0x1a68, 0x1b60, 0x1b18, 0x1b18, 0x1b18, 0x1b18, 0x1b18, 0x1b68, 0x1b70, 0x1b78, 0x1af0, 0x1b80, 0x1b88,
+ 0x1af0, 0x1b90, 0x1b98, 0x1ba0, 0x1af0, 0x1ba8, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1b18, 0x1bb8, 0x1bb0, 0x1bb0, 0x1bc0, 0x1a68,
+ 0x1bc8, 0x1bd0, 0x1bd0, 0x1bd8, 0x1be0, 0x1be8, 0x1bf0, 0x1bf8, 0x1c00, 0x1c08, 0x1c10, 0x1c18, 0x1c20, 0x1c28, 0x1c30, 0x1c38,
+ 0x1c40, 0x1c08, 0x1c10, 0x1c48, 0x1c50, 0x1c58, 0x1c60, 0x1c68, 0x1c70, 0x1c78, 0x1c10, 0x1c80, 0x1c88, 0x1c90, 0x1c30, 0x1c98,
+ 0x1ca0, 0x1c08, 0x1c10, 0x1ca8, 0x1cb0, 0x1cb8, 0x1c30, 0x1cc0, 0x1cc8, 0x1cd0, 0x1cd8, 0x1ce0, 0x1ce8, 0x1cf0, 0x1c60, 0x1cf8,
+ 0x1d00, 0x1d08, 0x1c10, 0x1d10, 0x1d18, 0x1d20, 0x1c30, 0x1d28, 0x1d30, 0x1d08, 0x1c10, 0x1d38, 0x1d40, 0x1d48, 0x1c30, 0x1d50,
+ 0x1d30, 0x1d08, 0x1bd0, 0x1d58, 0x1d60, 0x1d68, 0x1c30, 0x1d70, 0x1d78, 0x1d80, 0x1bd0, 0x1d88, 0x1d90, 0x1d98, 0x1c60, 0x1da0,
+ 0x1da8, 0x1bd0, 0x1bd0, 0x1db0, 0x1db8, 0x1dc0, 0x1bb0, 0x1bb0, 0x1dc8, 0x1dd0, 0x1dd8, 0x1de0, 0x1de8, 0x1df0, 0x1bb0, 0x1bb0,
+ 0x1df8, 0x1e00, 0x1e08, 0x1e10, 0x1e18, 0x1bd0, 0x1e20, 0x1e28, 0x1e30, 0x1e38, 0x1a68, 0x1e40, 0x1e48, 0x1e50, 0x1bb0, 0x1bb0,
+ 0x1bd0, 0x1bd0, 0x1e58, 0x1e60, 0x1e68, 0x1e70, 0x1e78, 0x1e80, 0x1e88, 0x1e90, 0x19b0, 0x19b0, 0x1e98, 0x1bd0, 0x1bd0, 0x1ea0,
+ 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0,
+ 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1ea8, 0x1eb0, 0x1bd0, 0x1bd0, 0x1ea8, 0x1bd0, 0x1bd0, 0x1eb8, 0x1ec0, 0x1ec8, 0x1bd0, 0x1bd0,
+ 0x1bd0, 0x1ec0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1ed0, 0x1ed8, 0x1ee0, 0x1bd0, 0x1ee8, 0x19b0, 0x19b0, 0x19b0, 0x19b0, 0x19b0, 0x1ef0,
+ 0x1ef8, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0,
+ 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1f00, 0x1bd0, 0x1f08, 0x1f10, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1f18, 0x1f20,
+ 0x1f28, 0x1f30, 0x1bd0, 0x1f38, 0x1bd0, 0x1f40, 0x1f28, 0x1f48, 0x1bd0, 0x1bd0, 0x1bd0, 0x1f50, 0x1f58, 0x1f60, 0x1f68, 0x1f70,
+ 0x1f78, 0x1f68, 0x1bd0, 0x1bd0, 0x1f80, 0x1bd0, 0x1bd0, 0x1f88, 0x1bd0, 0x1bd0, 0x1f90, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1f98,
+ 0x1bd0, 0x1fa0, 0x1fa8, 0x1fb0, 0x1fb8, 0x1bd0, 0x1fc0, 0x1fc8, 0x1bd0, 0x1bd0, 0x1fd0, 0x1bd0, 0x1fd8, 0x1fe0, 0x1fe8, 0x1fe8,
+ 0x1bd0, 0x1ff0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1ff8, 0x2000, 0x2008, 0x1f68, 0x1f68, 0x2010, 0x2018, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0,
+ 0x2020, 0x1bd0, 0x1bd0, 0x2028, 0x2030, 0x1e68, 0x2038, 0x2040, 0x2048, 0x1bd0, 0x2050, 0x2058, 0x1bd0, 0x1bd0, 0x2060, 0x2068,
+ 0x1bd0, 0x1bd0, 0x2070, 0x2078, 0x2080, 0x2058, 0x1bd0, 0x2088, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x2090, 0x2098, 0x20a0, 0x20a8,
+ 0x19c0, 0x19c0, 0x20b0, 0x20b8, 0x20b8, 0x20b8, 0x20c0, 0x20c8, 0x19c0, 0x20d0, 0x20b8, 0x20b8, 0x1a68, 0x1a68, 0x1a68, 0x20d8,
+ 0x19d0, 0x19d0, 0x19d0, 0x19d0, 0x19d0, 0x19d0, 0x19d0, 0x19d0, 0x19d0, 0x20e0, 0x19d0, 0x19d0, 0x19d0, 0x19d0, 0x19d0, 0x19d0,
+ 0x20e8, 0x20f0, 0x20e8, 0x20e8, 0x20f0, 0x20f8, 0x20e8, 0x2100, 0x2108, 0x2108, 0x2108, 0x2110, 0x2118, 0x2120, 0x2128, 0x2130,
+ 0x2138, 0x2140, 0x2148, 0x2150, 0x2158, 0x2160, 0x2168, 0x2170, 0x2178, 0x2180, 0x2188, 0x2190, 0x1bb0, 0x2198, 0x21a0, 0x21a8,
+ 0x21b0, 0x21b8, 0x21c0, 0x21c8, 0x21d0, 0x21d8, 0x21e0, 0x21e0, 0x21e8, 0x21f0, 0x21f8, 0x1fe8, 0x2200, 0x2208, 0x1fe8, 0x2210,
+ 0x2218, 0x2220, 0x2218, 0x2218, 0x2218, 0x2218, 0x2218, 0x2218, 0x2218, 0x2218, 0x2218, 0x2218, 0x2218, 0x2218, 0x2218, 0x2218,
+ 0x2228, 0x1fe8, 0x2230, 0x2238, 0x2240, 0x2240, 0x2240, 0x2248, 0x1fe8, 0x2250, 0x2218, 0x2258, 0x1fe8, 0x2260, 0x2268, 0x2270,
+ 0x1fe8, 0x1fe8, 0x2278, 0x1bb0, 0x2270, 0x1bb0, 0x21d8, 0x21d8, 0x2280, 0x2288, 0x2240, 0x2240, 0x2240, 0x2240, 0x2290, 0x21d8,
+ 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x2298, 0x22a0, 0x1fe8, 0x1fe8, 0x22a8,
+ 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x22b0, 0x1fe8, 0x1fe8, 0x1fe8, 0x22b8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8,
+ 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x22c0, 0x22c8, 0x21d8, 0x22d0, 0x1fe8, 0x1fe8, 0x22d8, 0x2218, 0x22e0, 0x2218,
+ 0x2240, 0x2240, 0x2240, 0x2240, 0x2240, 0x2240, 0x2240, 0x2240, 0x2240, 0x2240, 0x2240, 0x2240, 0x2240, 0x2240, 0x2240, 0x2240,
+ 0x2218, 0x2218, 0x2218, 0x2218, 0x2218, 0x2218, 0x2218, 0x2218, 0x22e8, 0x22f0, 0x2218, 0x2218, 0x2218, 0x22f8, 0x2218, 0x2300,
+ 0x2218, 0x2218, 0x2218, 0x2218, 0x2218, 0x2218, 0x2218, 0x2218, 0x2218, 0x2218, 0x2218, 0x2218, 0x2218, 0x2218, 0x2218, 0x2218,
+ 0x1fe8, 0x1fe8, 0x1fe8, 0x2218, 0x2308, 0x1fe8, 0x1fe8, 0x2310, 0x1fe8, 0x2318, 0x1fe8, 0x2320, 0x2328, 0x2330, 0x2338, 0x1bb0,
+ 0x19b0, 0x19b0, 0x2340, 0x19c0, 0x19c0, 0x2348, 0x2350, 0x2358, 0x19d0, 0x19d0, 0x19d0, 0x19d0, 0x19d0, 0x19d0, 0x2360, 0x2368,
+ 0x19c0, 0x19c0, 0x2370, 0x1bd0, 0x1bd0, 0x1bd0, 0x2378, 0x2380, 0x1bd0, 0x2388, 0x2390, 0x2390, 0x2390, 0x2390, 0x1a68, 0x1a68,
+ 0x2398, 0x23a0, 0x23a8, 0x23b0, 0x23b8, 0x1bb0, 0x1bb0, 0x1bb0, 0x1fe8, 0x23c0, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x23c8,
+ 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x23d0, 0x1bb0, 0x23d8,
+ 0x23e0, 0x23e8, 0x23f0, 0x23f8, 0x1da8, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x2400, 0x1ef8, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x2408,
+ 0x2410, 0x1bd0, 0x1fc0, 0x1da8, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1fa0, 0x2418, 0x1bd0, 0x2420, 0x1fe8, 0x1fe8, 0x23c8, 0x1bd0,
+ 0x2240, 0x2428, 0x2430, 0x2240, 0x2438, 0x2440, 0x2240, 0x2448, 0x2430, 0x2240, 0x2240, 0x2450, 0x2458, 0x2240, 0x2240, 0x2460,
+ 0x2240, 0x2240, 0x2240, 0x2240, 0x2240, 0x2240, 0x2240, 0x2468, 0x2240, 0x2240, 0x2240, 0x2240, 0x2240, 0x2470, 0x2240, 0x2478,
+ 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1f98, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8,
+ 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1f98, 0x1bb0, 0x1bb0,
+ 0x1bd0, 0x2480, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0,
+ 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1e20, 0x1fe8, 0x1fe8, 0x1fe8, 0x2278, 0x1bd0, 0x1bd0, 0x2088,
+ 0x2488, 0x1bd0, 0x2490, 0x1bb0, 0x19d0, 0x19d0, 0x2498, 0x24a0, 0x19d0, 0x24a8, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x24b0, 0x24b8,
+ 0x1a60, 0x24c0, 0x24c8, 0x24d0, 0x19d0, 0x19d0, 0x19d0, 0x24d8, 0x24e0, 0x24e8, 0x24f0, 0x24f8, 0x1bb0, 0x1bb0, 0x1bb0, 0x2500,
+ 0x2508, 0x1bd0, 0x2510, 0x2518, 0x1bd0, 0x1bd0, 0x1bd0, 0x2520, 0x2528, 0x1bd0, 0x1bd0, 0x2530, 0x2538, 0x1f68, 0x1a68, 0x2540,
+ 0x2058, 0x1bd0, 0x2548, 0x1bd0, 0x2550, 0x2558, 0x1bd0, 0x1e20, 0x1bc8, 0x1bd0, 0x1bd0, 0x2560, 0x2568, 0x2570, 0x2578, 0x2580,
+ 0x1bd0, 0x1bd0, 0x2588, 0x2590, 0x2598, 0x25a0, 0x1bd0, 0x25a8, 0x1bd0, 0x1bd0, 0x1bd0, 0x25b0, 0x25b8, 0x25c0, 0x25c8, 0x25d0,
+ 0x25d8, 0x25e0, 0x2390, 0x19c0, 0x19c0, 0x25e8, 0x25f0, 0x19c0, 0x19c0, 0x19c0, 0x19c0, 0x19c0, 0x1bd0, 0x1bd0, 0x25f8, 0x1f68,
+ 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x2600, 0x1bd0, 0x2608, 0x1bd0, 0x1bd0, 0x1fd0,
+ 0x2610, 0x2610, 0x2610, 0x2610, 0x2610, 0x2610, 0x2610, 0x2610, 0x2610, 0x2610, 0x2610, 0x2610, 0x2610, 0x2610, 0x2610, 0x2610,
+ 0x2618, 0x2618, 0x2618, 0x2618, 0x2618, 0x2618, 0x2618, 0x2618, 0x2618, 0x2618, 0x2618, 0x2618, 0x2618, 0x2618, 0x2618, 0x2618,
+ 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1fc0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1fd8, 0x1bb0, 0x1bb0,
+ 0x2620, 0x2628, 0x2630, 0x2638, 0x2640, 0x1b18, 0x1b18, 0x1b18, 0x1b18, 0x1b18, 0x1b18, 0x2648, 0x2650, 0x2658, 0x1b18, 0x1b18,
+ 0x1b18, 0x1b18, 0x1b18, 0x1b18, 0x1b18, 0x1b18, 0x1b18, 0x1b18, 0x1b18, 0x1b18, 0x1b18, 0x1b18, 0x1b18, 0x1b18, 0x1b18, 0x1b18,
+ 0x1b18, 0x1b18, 0x1b18, 0x2660, 0x1bb0, 0x1b18, 0x1b18, 0x1b18, 0x1b18, 0x2668, 0x1b18, 0x1b18, 0x2670, 0x1bb0, 0x1bb0, 0x2678,
+ 0x1a68, 0x2680, 0x1a68, 0x2688, 0x2690, 0x2698, 0x26a0, 0x26a8, 0x1b18, 0x1b18, 0x1b18, 0x1b18, 0x1b18, 0x1b18, 0x1b18, 0x26b0,
+ 0x26b8, 0x1968, 0x1970, 0x1978, 0x1980, 0x26c0, 0x26c8, 0x26d0, 0x1bd0, 0x26d8, 0x1bd0, 0x1fa0, 0x26e0, 0x26e8, 0x26f0, 0x26f8,
+ 0x2700, 0x1bd0, 0x1ec8, 0x2708, 0x1fc0, 0x1fc0, 0x1bb0, 0x1bb0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x2420,
+ 0x2710, 0x2718, 0x2718, 0x2720, 0x2728, 0x2728, 0x2728, 0x2730, 0x2738, 0x23d8, 0x2740, 0x1bb0, 0x1bb0, 0x2240, 0x2240, 0x2748,
+ 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bd0, 0x1e20, 0x1bd0, 0x1bd0, 0x1bd0, 0x1c90, 0x2750, 0x2758,
+ 0x1bd0, 0x1bd0, 0x2760, 0x1bd0, 0x2768, 0x1bd0, 0x1bd0, 0x2770, 0x1bd0, 0x2778, 0x1bd0, 0x1bd0, 0x2780, 0x2788, 0x1bb0, 0x1bb0,
+ 0x19b0, 0x19b0, 0x2790, 0x19c0, 0x19c0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1fc0, 0x1f68, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0,
+ 0x1bd0, 0x1bd0, 0x1f88, 0x1bd0, 0x1bd0, 0x1bd0, 0x2798, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0,
+ 0x1bd0, 0x1bd0, 0x1bd0, 0x2388, 0x1bd0, 0x1f98, 0x1f88, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0,
+ 0x27a0, 0x1af0, 0x1af0, 0x27a8, 0x1af0, 0x27b0, 0x1af0, 0x27b8, 0x1af0, 0x27c0, 0x27c8, 0x1bb0, 0x1bb0, 0x1bb0, 0x1af0, 0x27d0,
+ 0x1af0, 0x27d8, 0x1af0, 0x27e0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1af0, 0x1af0, 0x1af0, 0x27e8, 0x27f0, 0x27f8, 0x27f0, 0x27f0,
+ 0x2800, 0x2808, 0x1af0, 0x2810, 0x2818, 0x2820, 0x1af0, 0x2828, 0x1af0, 0x2830, 0x1bb0, 0x1bb0, 0x2838, 0x1af0, 0x2840, 0x2848,
+ 0x1af0, 0x1af0, 0x1af0, 0x2850, 0x1af0, 0x2858, 0x1af0, 0x2860, 0x1af0, 0x2868, 0x2870, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0,
+ 0x1af0, 0x1af0, 0x1af0, 0x1af0, 0x2878, 0x1bb0, 0x1bb0, 0x1bb0, 0x2880, 0x2880, 0x2880, 0x2888, 0x2890, 0x2890, 0x2890, 0x2898,
+ 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0,
+ 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x28a0, 0x28a8, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0,
+ 0x28b0, 0x1bd0, 0x1bd0, 0x28b8, 0x28c0, 0x28c8, 0x28d0, 0x28d8, 0x2048, 0x1bd0, 0x1bd0, 0x28e0, 0x28e8, 0x1bd0, 0x28f0, 0x1f68,
+ 0x28f8, 0x1bd0, 0x2900, 0x2908, 0x2910, 0x1bd0, 0x1bd0, 0x2918, 0x2048, 0x1bd0, 0x1bd0, 0x2920, 0x2928, 0x2930, 0x2938, 0x2940,
+ 0x1bd0, 0x1c78, 0x2948, 0x2950, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x2958, 0x2960, 0x2968, 0x1bd0, 0x1bd0, 0x2970, 0x2978, 0x1f68,
+ 0x2980, 0x1c08, 0x1c10, 0x1c80, 0x2988, 0x2990, 0x2998, 0x29a0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0,
+ 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bd0, 0x1bd0, 0x1bd0, 0x29a8, 0x29b0, 0x1f68, 0x1bb0, 0x1bb0,
+ 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bd0, 0x1bd0, 0x29b8, 0x29c0, 0x29c8, 0x29d0, 0x1bb0, 0x1bb0,
+ 0x1bd0, 0x1bd0, 0x1bd0, 0x29d8, 0x29e0, 0x1f68, 0x1bb0, 0x1bb0, 0x1bd0, 0x1bd0, 0x29e8, 0x29f0, 0x1f68, 0x1bb0, 0x1bb0, 0x1bb0,
+ 0x1bd0, 0x29f8, 0x2a00, 0x2a08, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0,
+ 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x19b0, 0x19b0, 0x19c0, 0x19c0, 0x1e08, 0x2a10,
+ 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bd0, 0x1bd0, 0x1bd0, 0x28f0,
+ 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1fd8, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0,
+ 0x21e0, 0x21e0, 0x21e0, 0x21e0, 0x21e0, 0x21e0, 0x2a18, 0x2a20, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0,
+ 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x2600, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0,
+ 0x1bd0, 0x1bd0, 0x1fa0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0,
+ 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x2388, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0,
+ 0x1bd0, 0x1bd0, 0x1bd0, 0x28f0, 0x1bd0, 0x1fa0, 0x2570, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bd0, 0x1fc0, 0x2a28,
+ 0x1bd0, 0x1bd0, 0x1bd0, 0x2a30, 0x2a38, 0x2a40, 0x2a48, 0x2a50, 0x1bd0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0,
+ 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1fc8, 0x2a58, 0x2a60, 0x2a68, 0x28d8, 0x2a70, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0,
+ 0x2a78, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0,
+ 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x2420, 0x1e20, 0x28f0, 0x2a80, 0x2a88, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0,
+ 0x2240, 0x2240, 0x2240, 0x2240, 0x2240, 0x2240, 0x2240, 0x2240, 0x2240, 0x2240, 0x2240, 0x2240, 0x2240, 0x2240, 0x2240, 0x2a90,
+ 0x2240, 0x2240, 0x2a98, 0x2240, 0x2240, 0x2240, 0x2aa0, 0x2aa8, 0x2ab0, 0x2240, 0x2ab8, 0x2240, 0x2240, 0x2240, 0x2ac0, 0x1bb0,
+ 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x2ac8, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0,
+ 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x2278, 0x2718, 0x2ad0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0,
+ 0x19b0, 0x2ad8, 0x19c0, 0x2ae0, 0x2ae8, 0x2af0, 0x20e8, 0x19b0, 0x2af8, 0x2b00, 0x2b08, 0x2b10, 0x2b18, 0x19b0, 0x2ad8, 0x19c0,
+ 0x2b20, 0x2b28, 0x19c0, 0x2b30, 0x2b38, 0x2b40, 0x2b48, 0x19b0, 0x2b50, 0x19c0, 0x19b0, 0x2ad8, 0x19c0, 0x2ae0, 0x2ae8, 0x19c0,
+ 0x20e8, 0x19b0, 0x2af8, 0x2b48, 0x19b0, 0x2b50, 0x19c0, 0x19b0, 0x2ad8, 0x19c0, 0x2b58, 0x19b0, 0x2b60, 0x2b68, 0x2b70, 0x2b78,
+ 0x19c0, 0x2b80, 0x19b0, 0x2b88, 0x2b90, 0x2b98, 0x2ba0, 0x19c0, 0x2ba8, 0x19b0, 0x2bb0, 0x19c0, 0x2bb8, 0x2bc0, 0x2bc0, 0x2bc0,
+ 0x1a68, 0x1a68, 0x1a68, 0x2bc8, 0x1a68, 0x1a68, 0x2bd0, 0x2bd8, 0x2be0, 0x2be8, 0x1ad8, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0,
+ 0x1af0, 0x1af0, 0x1af0, 0x1af0, 0x1af0, 0x1af0, 0x1af0, 0x1af0, 0x1af0, 0x1af0, 0x1af0, 0x1af0, 0x2bf0, 0x2bf8, 0x1bb0, 0x1bb0,
+ 0x2c00, 0x1b18, 0x2c08, 0x2c10, 0x2c18, 0x2c20, 0x2c28, 0x2c30, 0x2c38, 0x2c40, 0x2c48, 0x2c40, 0x1bb0, 0x1bb0, 0x1bb0, 0x2c50,
+ 0x1fe8, 0x1fe8, 0x23d8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x23c8, 0x2c58, 0x2c60, 0x2c60, 0x2c60, 0x1fe8, 0x23d0,
+ 0x2c68, 0x2240, 0x2460, 0x2240, 0x2240, 0x2240, 0x2c70, 0x2240, 0x2240, 0x2c78, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x2c80, 0x2240,
+ 0x2c88, 0x2240, 0x2240, 0x2c78, 0x2ac0, 0x2c90, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0,
+ 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x2c98,
+ 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8,
+ 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x23c0, 0x1fe8, 0x1fe8, 0x2ca0, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8,
+ 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x2740, 0x2ca8, 0x23c8,
+ 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x23c8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x1fe8, 0x2cb0, 0x1bb0, 0x1bb0,
+ 0x23d8, 0x1fe8, 0x1fe8, 0x1fe8, 0x2cb8, 0x1ee8, 0x1fe8, 0x1fe8, 0x2cb8, 0x1fe8, 0x2cc0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0,
+ 0x1bb0, 0x2cc8, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x2cb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x2740, 0x1bb0, 0x1bb0, 0x1bb0,
+ 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x2388, 0x1bb0, 0x1bb0,
+ 0x1bd0, 0x1bd0, 0x1bd0, 0x1fc8, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0,
+ 0x1bd0, 0x1fc0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0,
+ 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x1bd0, 0x2a78, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0,
+ 0x1bd0, 0x1fc0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0,
+ 0x2cd0, 0x1bb0, 0x2cd8, 0x2cd8, 0x2cd8, 0x2cd8, 0x2cd8, 0x2cd8, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0, 0x1bb0,
+ 0x1a68, 0x1a68, 0x1a68, 0x1a68, 0x1a68, 0x1a68, 0x1a68, 0x1a68, 0x1a68, 0x1a68, 0x1a68, 0x1a68, 0x1a68, 0x1a68, 0x1a68, 0x1bb0,
+ 0x2618, 0x2618, 0x2618, 0x2618, 0x2618, 0x2618, 0x2618, 0x2618, 0x2618, 0x2618, 0x2618, 0x2618, 0x2618, 0x2618, 0x2618, 0x2ce0,
+ 0x0101, 0x0101, 0x0101, 0x0101, 0x0201, 0x0203, 0x0304, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0303, 0x0203,
+ 0x0605, 0x0706, 0x0708, 0x0606, 0x0a09, 0x0b06, 0x0d0c, 0x0c0c, 0x0e0e, 0x0e0e, 0x0e0e, 0x0e0e, 0x0e0e, 0x060c, 0x0f0f, 0x060f,
+ 0x1006, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x0910, 0x0a06, 0x1211,
+ 0x1311, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x0913, 0x0a0f, 0x010f,
+ 0x0101, 0x0101, 0x0301, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101,
+ 0x0614, 0x0808, 0x0808, 0x0615, 0x1511, 0x1716, 0x180f, 0x1115, 0x1a19, 0x1b1b, 0x1311, 0x0606, 0x1b11, 0x1c16, 0x1d1d, 0x061d,
+ 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x0f10, 0x1010, 0x1010, 0x1010, 0x1310,
+ 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x0f13, 0x1313, 0x1313, 0x1313, 0x1313,
+ 0x1310, 0x1310, 0x1310, 0x1310, 0x1310, 0x1310, 0x1310, 0x1310, 0x1310, 0x1310, 0x1310, 0x1310, 0x1013, 0x1013, 0x1013, 0x1013,
+ 0x1013, 0x1013, 0x1013, 0x1013, 0x1313, 0x1310, 0x1310, 0x1310, 0x1310, 0x1310, 0x1310, 0x1310, 0x1010, 0x1013, 0x1013, 0x1313,
+ 0x1013, 0x1310, 0x1310, 0x1010, 0x1013, 0x1010, 0x1313, 0x1010, 0x1010, 0x1013, 0x1310, 0x1010, 0x1310, 0x1313, 0x1010, 0x1013,
+ 0x1310, 0x1310, 0x1310, 0x1010, 0x1013, 0x1313, 0x1310, 0x1010, 0x1013, 0x1010, 0x1013, 0x1013, 0x1310, 0x1613, 0x1310, 0x1313,
+ 0x1616, 0x1616, 0x1e10, 0x1013, 0x131e, 0x1e10, 0x1013, 0x1013, 0x1013, 0x1013, 0x1013, 0x1013, 0x1013, 0x1013, 0x1313, 0x1310,
+ 0x1013, 0x131e, 0x1310, 0x1010, 0x1310, 0x1310, 0x1310, 0x1310, 0x1310, 0x1310, 0x1313, 0x1313, 0x1313, 0x1010, 0x1013, 0x1310,
+ 0x1013, 0x1013, 0x1010, 0x1310, 0x1310, 0x1310, 0x1310, 0x1310, 0x1313, 0x1313, 0x1316, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313,
+ 0x1f1f, 0x1f1f, 0x1f1f, 0x1f1f, 0x201f, 0x1f20, 0x1f1f, 0x1f1f, 0x1f1f, 0x1111, 0x1111, 0x2020, 0x2020, 0x2020, 0x2020, 0x2020,
+ 0x1f1f, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1f1f, 0x1f1f, 0x111f, 0x1111, 0x1111, 0x1111, 0x1120, 0x111f,
+ 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x1111, 0x2121, 0x2121, 0x2121, 0x2121, 0x2121, 0x2121, 0x2121, 0x2121,
+ 0x1310, 0x1310, 0x1120, 0x1310, 0x0000, 0x131f, 0x1313, 0x1006, 0x0000, 0x0000, 0x1111, 0x0610, 0x1010, 0x0010, 0x0010, 0x1010,
+ 0x1013, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1000, 0x1010, 0x1010, 0x1010, 0x1010, 0x1313, 0x1313,
+ 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1013, 0x1313, 0x1010, 0x1310, 0x1313, 0x1310, 0x1310, 0x1310, 0x1310,
+ 0x1313, 0x1313, 0x1310, 0x100f, 0x1013, 0x1310, 0x1013, 0x1010, 0x1310, 0x2122, 0x2121, 0x2121, 0x2323, 0x1310, 0x1310, 0x1310,
+ 0x1010, 0x1013, 0x1013, 0x1013, 0x1013, 0x1013, 0x1013, 0x1313, 0x1000, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010,
+ 0x1010, 0x1010, 0x1010, 0x0010, 0x1f00, 0x2424, 0x2424, 0x2424, 0x1300, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313,
+ 0x1313, 0x1313, 0x1313, 0x1313, 0x2400, 0x0025, 0x1500, 0x0815, 0x2100, 0x2121, 0x2121, 0x2121, 0x2121, 0x2121, 0x2121, 0x2121,
+ 0x2121, 0x2121, 0x2121, 0x2121, 0x2121, 0x2121, 0x2121, 0x2126, 0x2127, 0x2721, 0x2121, 0x2127, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x0028, 0x0000, 0x0000,
+ 0x2828, 0x2728, 0x0027, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2929, 0x2929, 0x2929, 0x0f0f, 0x072a, 0x2b07, 0x2c0c, 0x1515,
+ 0x2121, 0x2121, 0x2121, 0x2121, 0x2121, 0x2c21, 0x002d, 0x2c2c, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e,
+ 0x2e2f, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x212e, 0x2121, 0x2121, 0x3030, 0x3030, 0x3030, 0x3030, 0x3030, 0x3107, 0x2c31, 0x2e2e,
+ 0x2e21, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2c, 0x2121, 0x2121, 0x2121, 0x2921, 0x2115,
+ 0x2121, 0x2121, 0x2f21, 0x212f, 0x1521, 0x2121, 0x2121, 0x2e2e, 0x0e0e, 0x0e0e, 0x0e0e, 0x0e0e, 0x0e0e, 0x2e2e, 0x322e, 0x2e32,
+ 0x2c2c, 0x2c2c, 0x2c2c, 0x2c2c, 0x2c2c, 0x2c2c, 0x2c2c, 0x2d00, 0x212e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e,
+ 0x2121, 0x2121, 0x2121, 0x2121, 0x2121, 0x0021, 0x2e00, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2121, 0x2121, 0x2121, 0x2121, 0x2121,
+ 0x2e21, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3333, 0x3333, 0x3333, 0x3333, 0x3333, 0x2828, 0x2828, 0x2828,
+ 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2128, 0x2121, 0x2121, 0x2121, 0x2121, 0x3434, 0x0615, 0x0606, 0x0034, 0x0000, 0x0000,
+ 0x2828, 0x2828, 0x2828, 0x2121, 0x2121, 0x2134, 0x2121, 0x2121, 0x2121, 0x2121, 0x2134, 0x2121, 0x2134, 0x2121, 0x2121, 0x0000,
+ 0x2727, 0x2727, 0x2727, 0x2727, 0x2727, 0x2727, 0x2727, 0x0027, 0x2828, 0x2828, 0x2828, 0x2828, 0x2128, 0x2121, 0x0000, 0x0027,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2e2e, 0x2e2e, 0x002e, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x2100, 0x2121, 0x2121, 0x2121, 0x2121, 0x2121, 0x2121, 0x2121, 0x3521, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616,
+ 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x3521, 0x1621, 0x3535,
+ 0x2135, 0x2121, 0x2121, 0x2121, 0x3521, 0x3535, 0x2135, 0x3535, 0x2116, 0x2121, 0x2121, 0x2121, 0x1616, 0x1616, 0x1616, 0x1616,
+ 0x1616, 0x2121, 0x2424, 0x3636, 0x3636, 0x3636, 0x3636, 0x3636, 0x1f24, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616,
+ 0x2116, 0x3535, 0x1600, 0x1616, 0x1616, 0x1616, 0x0016, 0x1600, 0x0016, 0x1600, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616,
+ 0x1616, 0x1616, 0x1616, 0x1616, 0x0016, 0x1616, 0x1616, 0x1616, 0x0016, 0x0016, 0x0000, 0x1616, 0x1616, 0x0000, 0x1621, 0x3535,
+ 0x2135, 0x2121, 0x0021, 0x3500, 0x0035, 0x3500, 0x2135, 0x0016, 0x0000, 0x0000, 0x0000, 0x3500, 0x0000, 0x0000, 0x1616, 0x1600,
+ 0x1616, 0x2121, 0x0000, 0x3636, 0x3636, 0x3636, 0x3636, 0x3636, 0x1616, 0x0808, 0x3737, 0x3737, 0x3737, 0x0822, 0x0000, 0x0000,
+ 0x2100, 0x3521, 0x1600, 0x1616, 0x1616, 0x0016, 0x0000, 0x1600, 0x0016, 0x1616, 0x1600, 0x0016, 0x1616, 0x0000, 0x0021, 0x3535,
+ 0x2135, 0x0021, 0x0000, 0x2100, 0x0021, 0x2100, 0x2121, 0x0000, 0x2100, 0x0000, 0x0000, 0x0000, 0x1600, 0x1616, 0x0016, 0x0016,
+ 0x0000, 0x0000, 0x0000, 0x3636, 0x3636, 0x3636, 0x3636, 0x3636, 0x2121, 0x1616, 0x2116, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x2100, 0x3521, 0x1600, 0x1616, 0x1616, 0x1616, 0x1616, 0x1600, 0x1616, 0x1600, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616,
+ 0x0016, 0x1616, 0x1600, 0x1616, 0x1616, 0x0000, 0x1621, 0x3535, 0x2135, 0x2121, 0x2121, 0x2100, 0x3521, 0x3500, 0x2135, 0x0000,
+ 0x0016, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0824, 0x0000, 0x0000, 0x0000, 0x1600, 0x0000, 0x0000, 0x0000,
+ 0x2100, 0x3535, 0x1600, 0x1616, 0x1616, 0x1616, 0x0016, 0x1600, 0x0016, 0x1616, 0x1600, 0x1616, 0x1616, 0x0000, 0x1621, 0x2135,
+ 0x2135, 0x2121, 0x0021, 0x3500, 0x0035, 0x3500, 0x2135, 0x0000, 0x0000, 0x0000, 0x0000, 0x3521, 0x0000, 0x0000, 0x1616, 0x1600,
+ 0x1622, 0x3737, 0x3737, 0x3737, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1621, 0x1600, 0x1616, 0x1616, 0x0016, 0x0000, 0x1616,
+ 0x0016, 0x1616, 0x1616, 0x0000, 0x1600, 0x0016, 0x0016, 0x1616, 0x0000, 0x1600, 0x0016, 0x0000, 0x1616, 0x0016, 0x0000, 0x1616,
+ 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x0000, 0x0000, 0x3535, 0x3521, 0x0035, 0x0000, 0x3535, 0x0035, 0x3535, 0x2135, 0x0000,
+ 0x0016, 0x0000, 0x0000, 0x3500, 0x0000, 0x0000, 0x0000, 0x0000, 0x3737, 0x1537, 0x1515, 0x1515, 0x0815, 0x0015, 0x0000, 0x0000,
+ 0x3521, 0x3535, 0x1600, 0x1616, 0x1616, 0x1616, 0x0016, 0x1616, 0x0016, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616,
+ 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x0000, 0x1600, 0x2121, 0x3521, 0x3535, 0x0035, 0x2121, 0x0021, 0x2121, 0x2121, 0x0000,
+ 0x0000, 0x0000, 0x2100, 0x0021, 0x1616, 0x0016, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1d1d, 0x1d1d, 0x1d1d, 0x221d,
+ 0x2100, 0x3535, 0x1600, 0x1616, 0x1616, 0x1616, 0x0016, 0x1616, 0x1616, 0x1616, 0x1600, 0x1616, 0x1616, 0x0000, 0x1621, 0x3835,
+ 0x3535, 0x3535, 0x0035, 0x3538, 0x0035, 0x3535, 0x2121, 0x0000, 0x0000, 0x0000, 0x3500, 0x0035, 0x0000, 0x0000, 0x0000, 0x0016,
+ 0x1600, 0x0016, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x0016, 0x1600, 0x3535,
+ 0x2135, 0x2121, 0x0021, 0x3535, 0x0035, 0x3535, 0x2135, 0x0016, 0x0000, 0x0000, 0x0000, 0x3500, 0x0000, 0x0000, 0x0000, 0x1600,
+ 0x3737, 0x3737, 0x3737, 0x0000, 0x2200, 0x1616, 0x1616, 0x1616, 0x0000, 0x3535, 0x1600, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616,
+ 0x1616, 0x1616, 0x1616, 0x0016, 0x0000, 0x1616, 0x1616, 0x1616, 0x1616, 0x1600, 0x1616, 0x1616, 0x1616, 0x1616, 0x1600, 0x0000,
+ 0x1616, 0x1616, 0x1616, 0x0016, 0x0000, 0x0021, 0x0000, 0x3500, 0x3535, 0x2121, 0x0021, 0x0021, 0x3535, 0x3535, 0x3535, 0x3535,
+ 0x0000, 0x3535, 0x0024, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1600, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616,
+ 0x2116, 0x1616, 0x2121, 0x2121, 0x2121, 0x0021, 0x0000, 0x0800, 0x1616, 0x1616, 0x1616, 0x211f, 0x2121, 0x2121, 0x2121, 0x2421,
+ 0x3636, 0x3636, 0x3636, 0x3636, 0x3636, 0x2424, 0x0000, 0x0000, 0x1600, 0x0016, 0x0016, 0x1600, 0x0016, 0x0016, 0x1600, 0x0000,
+ 0x0000, 0x0000, 0x1616, 0x1616, 0x1600, 0x1616, 0x1616, 0x1616, 0x1600, 0x1616, 0x1600, 0x1600, 0x0000, 0x1616, 0x1600, 0x1616,
+ 0x2116, 0x1616, 0x2121, 0x2121, 0x2121, 0x2100, 0x1621, 0x0000, 0x1616, 0x1616, 0x0016, 0x001f, 0x2121, 0x2121, 0x2121, 0x0000,
+ 0x3636, 0x3636, 0x3636, 0x3636, 0x3636, 0x0000, 0x1616, 0x1616, 0x2216, 0x2222, 0x2424, 0x2424, 0x2424, 0x2424, 0x2424, 0x2424,
+ 0x2424, 0x2224, 0x2224, 0x2222, 0x2121, 0x2222, 0x2222, 0x2222, 0x3636, 0x3636, 0x3636, 0x3636, 0x3636, 0x3737, 0x3737, 0x3737,
+ 0x3737, 0x3737, 0x2122, 0x2122, 0x2122, 0x0a09, 0x0a09, 0x3535, 0x1616, 0x1616, 0x1616, 0x1616, 0x1600, 0x1616, 0x1616, 0x1616,
+ 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x0016, 0x0000, 0x2100, 0x2121, 0x2121, 0x2121, 0x2121, 0x2121, 0x2121, 0x3521,
+ 0x2121, 0x2121, 0x2421, 0x2121, 0x1616, 0x1616, 0x2116, 0x2121, 0x2121, 0x2121, 0x2121, 0x2121, 0x2100, 0x2121, 0x2121, 0x2121,
+ 0x2121, 0x2121, 0x2121, 0x2121, 0x2121, 0x2121, 0x0021, 0x2222, 0x2222, 0x2222, 0x2222, 0x2221, 0x2222, 0x2222, 0x0022, 0x2222,
+ 0x2424, 0x2424, 0x2224, 0x2222, 0x2422, 0x0024, 0x0000, 0x0000, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x3516, 0x2135, 0x2121,
+ 0x3521, 0x2121, 0x2121, 0x2121, 0x2135, 0x3521, 0x2135, 0x1621, 0x3636, 0x3636, 0x3636, 0x3636, 0x3636, 0x2424, 0x2424, 0x2424,
+ 0x1616, 0x1616, 0x1616, 0x3535, 0x2121, 0x1616, 0x1616, 0x2121, 0x1621, 0x3535, 0x1635, 0x3516, 0x3535, 0x3535, 0x3535, 0x1616,
+ 0x2116, 0x2121, 0x1621, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x3521, 0x2135, 0x3521, 0x3535, 0x3535, 0x2135, 0x3516,
+ 0x3636, 0x3636, 0x3636, 0x3636, 0x3636, 0x3535, 0x2135, 0x2222, 0x1010, 0x1010, 0x1010, 0x1000, 0x0000, 0x0000, 0x1000, 0x0000,
+ 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x2416, 0x161f, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x0016, 0x1616, 0x1616, 0x0000,
+ 0x1616, 0x1616, 0x1616, 0x0016, 0x0016, 0x1616, 0x1616, 0x0000, 0x0016, 0x1616, 0x1616, 0x0000, 0x1616, 0x1616, 0x1616, 0x0016,
+ 0x0016, 0x1616, 0x1616, 0x0000, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x0016, 0x1616, 0x1616, 0x1616, 0x1616,
+ 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x0016, 0x2100, 0x2121, 0x2424, 0x2424, 0x2424, 0x2424, 0x3724, 0x3737, 0x3737, 0x3737,
+ 0x3737, 0x3737, 0x3737, 0x3737, 0x3737, 0x3737, 0x0037, 0x0000, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x0000, 0x0000, 0x0000,
+ 0x1010, 0x1010, 0x1010, 0x0000, 0x1313, 0x1313, 0x1313, 0x0000, 0x1625, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616,
+ 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x2416, 0x1624, 0x1605, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616,
+ 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x0916, 0x000a, 0x0000, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x2416, 0x2424, 0x3939,
+ 0x1639, 0x1616, 0x1616, 0x1616, 0x0016, 0x0000, 0x0000, 0x0000, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x0016, 0x1616,
+ 0x1616, 0x2121, 0x0021, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1616, 0x2121, 0x2421, 0x0024, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x1616, 0x2121, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0016, 0x2121, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x1616, 0x1616, 0x2121, 0x2135, 0x2121, 0x2121, 0x2121, 0x3535, 0x3535, 0x3535, 0x3535, 0x3521, 0x2135, 0x2121, 0x2121, 0x2121,
+ 0x2121, 0x2121, 0x2424, 0x1f24, 0x2424, 0x0824, 0x2116, 0x0000, 0x3636, 0x3636, 0x3636, 0x3636, 0x3636, 0x0000, 0x0000, 0x0000,
+ 0x1d1d, 0x1d1d, 0x1d1d, 0x1d1d, 0x1d1d, 0x0000, 0x0000, 0x0000, 0x0606, 0x0606, 0x0606, 0x0625, 0x0606, 0x2106, 0x2121, 0x0018,
+ 0x1616, 0x1f16, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x1616, 0x1616, 0x1616, 0x1616, 0x2116, 0x0016, 0x0000, 0x0000, 0x1616, 0x1616, 0x1616, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x0016, 0x2121, 0x3521, 0x3535, 0x2135, 0x3521, 0x3535, 0x0000, 0x0000,
+ 0x3535, 0x3521, 0x3535, 0x3535, 0x2135, 0x2121, 0x0000, 0x0000, 0x0015, 0x0000, 0x0606, 0x3636, 0x3636, 0x3636, 0x3636, 0x3636,
+ 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x0000, 0x1616, 0x1616, 0x0016, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x0000, 0x0000, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x0000, 0x0000, 0x0000,
+ 0x3636, 0x3636, 0x3636, 0x3636, 0x3636, 0x0037, 0x0000, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515,
+ 0x1616, 0x1616, 0x1616, 0x2116, 0x3521, 0x2135, 0x0000, 0x2424, 0x1616, 0x1616, 0x3516, 0x3521, 0x2121, 0x2121, 0x2121, 0x0021,
+ 0x3521, 0x3521, 0x2135, 0x2121, 0x2121, 0x2121, 0x3521, 0x3535, 0x3535, 0x2135, 0x2121, 0x2121, 0x2121, 0x2121, 0x0021, 0x2100,
+ 0x2424, 0x2424, 0x2424, 0x1f24, 0x2424, 0x2424, 0x2424, 0x0000, 0x2121, 0x2121, 0x2121, 0x2121, 0x2121, 0x2121, 0x2121, 0x0023,
+ 0x2121, 0x2121, 0x1635, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x3521, 0x2121, 0x2121, 0x3521, 0x3521, 0x3535,
+ 0x3535, 0x3521, 0x1635, 0x1616, 0x1616, 0x1616, 0x0000, 0x0000, 0x2224, 0x2222, 0x2222, 0x2222, 0x2222, 0x2122, 0x2121, 0x2121,
+ 0x2121, 0x2121, 0x2222, 0x2222, 0x2222, 0x2222, 0x0022, 0x0000, 0x2121, 0x1635, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616,
+ 0x3516, 0x2121, 0x2121, 0x3535, 0x2121, 0x2135, 0x2121, 0x1616, 0x3636, 0x3636, 0x3636, 0x3636, 0x3636, 0x1616, 0x1616, 0x1616,
+ 0x1616, 0x1616, 0x1616, 0x3521, 0x2121, 0x3535, 0x2135, 0x2135, 0x2121, 0x3535, 0x0000, 0x0000, 0x0000, 0x0000, 0x2424, 0x2424,
+ 0x1616, 0x1616, 0x3535, 0x3535, 0x3535, 0x3535, 0x2121, 0x2121, 0x2121, 0x2121, 0x3535, 0x2121, 0x0000, 0x2400, 0x2424, 0x2424,
+ 0x3636, 0x3636, 0x3636, 0x3636, 0x3636, 0x0000, 0x1600, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1f1f, 0x1f1f, 0x1f1f, 0x2424,
+ 0x2424, 0x2424, 0x2424, 0x2424, 0x0000, 0x0000, 0x0000, 0x0000, 0x2121, 0x2421, 0x2121, 0x2121, 0x2121, 0x2121, 0x2121, 0x2121,
+ 0x3521, 0x2121, 0x2121, 0x2121, 0x1621, 0x1616, 0x2116, 0x1616, 0x1616, 0x3535, 0x1621, 0x0016, 0x2121, 0x0000, 0x0000, 0x0000,
+ 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1f1f, 0x1f1f, 0x1f1f, 0x1f1f, 0x1f1f, 0x1f1f, 0x1f1f, 0x1f1f, 0x1f1f, 0x1f1f,
+ 0x1f1f, 0x1f1f, 0x1f1f, 0x1f1f, 0x1f1f, 0x131f, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x131f, 0x1313, 0x1313, 0x1313,
+ 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1f13, 0x1f1f, 0x1f1f, 0x2121, 0x2121, 0x2121, 0x0000, 0x0000, 0x0000, 0x2121, 0x2121,
+ 0x1310, 0x1310, 0x1310, 0x1313, 0x1313, 0x1313, 0x1313, 0x1310, 0x1313, 0x1313, 0x1313, 0x1313, 0x1010, 0x1010, 0x1010, 0x1010,
+ 0x1313, 0x1313, 0x1313, 0x0000, 0x1010, 0x1010, 0x1010, 0x0000, 0x1313, 0x1313, 0x1313, 0x1313, 0x1000, 0x1000, 0x1000, 0x1000,
+ 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x0000, 0x1313, 0x1313, 0x1313, 0x1313, 0x1e1e, 0x1e1e, 0x1e1e, 0x1e1e,
+ 0x1313, 0x1313, 0x0013, 0x1313, 0x1010, 0x1010, 0x111e, 0x1113, 0x1111, 0x1313, 0x0013, 0x1313, 0x1010, 0x1010, 0x111e, 0x1111,
+ 0x1313, 0x1313, 0x0000, 0x1313, 0x1010, 0x1010, 0x1100, 0x1111, 0x1313, 0x1313, 0x1313, 0x1313, 0x1010, 0x1010, 0x1110, 0x1111,
+ 0x0000, 0x1313, 0x0013, 0x1313, 0x1010, 0x1010, 0x111e, 0x0011, 0x0505, 0x0505, 0x0505, 0x0505, 0x0505, 0x1805, 0x1818, 0x3b3a,
+ 0x2525, 0x2525, 0x2525, 0x0606, 0x1c17, 0x1709, 0x1c17, 0x1709, 0x0606, 0x0606, 0x0606, 0x0606, 0x3d3c, 0x3f3e, 0x4140, 0x1442,
+ 0x0707, 0x0707, 0x0607, 0x0606, 0x1706, 0x061c, 0x0606, 0x1206, 0x0612, 0x0606, 0x0943, 0x060a, 0x0606, 0x0606, 0x0606, 0x0606,
+ 0x0606, 0x060f, 0x0612, 0x0606, 0x0606, 0x0606, 0x0606, 0x0506, 0x1818, 0x1818, 0x0018, 0x4544, 0x4746, 0x1818, 0x1818, 0x1818,
+ 0x1f1b, 0x0000, 0x1b1b, 0x1b1b, 0x1b1b, 0x0b0b, 0x090f, 0x1f0a, 0x1b1b, 0x1b1b, 0x1b1b, 0x1b1b, 0x1b1b, 0x0b0b, 0x090f, 0x000a,
+ 0x1f1f, 0x1f1f, 0x1f1f, 0x1f1f, 0x1f1f, 0x1f1f, 0x001f, 0x0000, 0x0808, 0x0808, 0x0808, 0x0808, 0x0808, 0x0808, 0x0808, 0x0808,
+ 0x0808, 0x0808, 0x0808, 0x0808, 0x0808, 0x0808, 0x0808, 0x0008, 0x2121, 0x2121, 0x2121, 0x2121, 0x2121, 0x2121, 0x2321, 0x2323,
+ 0x2123, 0x2323, 0x2123, 0x2121, 0x2121, 0x2121, 0x2121, 0x2121, 0x0021, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x1515, 0x1510, 0x1515, 0x1015, 0x1515, 0x1013, 0x1010, 0x1313, 0x1010, 0x1310, 0x1015, 0x1515, 0x100f, 0x1010, 0x1010, 0x1515,
+ 0x1515, 0x1515, 0x1510, 0x1510, 0x1510, 0x1010, 0x1010, 0x1319, 0x1010, 0x1010, 0x1613, 0x1616, 0x1316, 0x1515, 0x1313, 0x1010,
+ 0x0f0f, 0x0f0f, 0x100f, 0x1313, 0x1313, 0x0f15, 0x1515, 0x2213, 0x1d1d, 0x1d1d, 0x1d1d, 0x1d1d, 0x1d1d, 0x1d1d, 0x1d1d, 0x1d1d,
+ 0x3939, 0x3939, 0x3939, 0x3939, 0x3939, 0x3939, 0x3939, 0x3939, 0x3939, 0x1039, 0x3913, 0x3939, 0x1d39, 0x1515, 0x0000, 0x0000,
+ 0x0f0f, 0x0f0f, 0x150f, 0x1515, 0x1515, 0x0f0f, 0x1515, 0x1515, 0x150f, 0x0f15, 0x1515, 0x150f, 0x1515, 0x1515, 0x1515, 0x150f,
+ 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x0f0f, 0x1515, 0x150f, 0x150f, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515,
+ 0x1515, 0x1515, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f,
+ 0x0f0f, 0x1a0b, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x1515, 0x1515, 0x1515, 0x1515, 0x0a09, 0x0a09, 0x1515, 0x1515,
+ 0x0f0f, 0x1515, 0x1515, 0x1515, 0x0915, 0x150a, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222,
+ 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x1522, 0x150f, 0x1515,
+ 0x1515, 0x1515, 0x2215, 0x1515, 0x1515, 0x0f15, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515,
+ 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x0f0f, 0x0f0f, 0x0f0f, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515,
+ 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x0015, 0x0000, 0x0000, 0x1515, 0x1515, 0x1515, 0x0015, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x1d1d, 0x1d1d, 0x1d1d, 0x1d1d, 0x1b1b, 0x1b1b, 0x1b1b, 0x1b1b, 0x1b1b, 0x1b1b, 0x1b1b, 0x1b1b, 0x1b1b, 0x1b1b, 0x2222, 0x2222,
+ 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x1d1d, 0x1d1d, 0x1d1d, 0x1515, 0x1515, 0x1515, 0x0f15, 0x1515, 0x1515, 0x1515, 0x1515,
+ 0x0f15, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f,
+ 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x0f15, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1522, 0x1515,
+ 0x1515, 0x1515, 0x1515, 0x1515, 0x0a09, 0x0a09, 0x0a09, 0x0a09, 0x0a09, 0x0a09, 0x0a09, 0x1d1d, 0x1d1d, 0x1d1d, 0x1d1d, 0x1d1d,
+ 0x1d1d, 0x1d1d, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x0f0f, 0x0f0f, 0x090f, 0x0f0a, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f,
+ 0x0f0f, 0x0f0f, 0x0f0f, 0x0a09, 0x0a09, 0x0a09, 0x0a09, 0x0a09, 0x0f0f, 0x090f, 0x090a, 0x090a, 0x090a, 0x090a, 0x090a, 0x090a,
+ 0x090a, 0x090a, 0x090a, 0x090a, 0x0f0a, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x0a09, 0x0a09, 0x0f0f, 0x0f0f,
+ 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x0f0f, 0x0a09, 0x0f0f, 0x0f0f, 0x0f0f, 0x150f, 0x0f15, 0x0f0f, 0x0f0f, 0x150f, 0x1515,
+ 0x1515, 0x1515, 0x0000, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x0000, 0x1515, 0x1515, 0x1515, 0x1515,
+ 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x0000, 0x1500, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x0015, 0x1515, 0x1515, 0x1515,
+ 0x1515, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1515, 0x1515,
+ 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x0010, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x0013,
+ 0x1310, 0x1010, 0x1310, 0x1013, 0x1013, 0x1013, 0x1013, 0x1010, 0x1310, 0x1310, 0x1013, 0x1313, 0x1313, 0x1313, 0x1f1f, 0x1010,
+ 0x1310, 0x1310, 0x1513, 0x1515, 0x1515, 0x1015, 0x1013, 0x2113, 0x2121, 0x1310, 0x0000, 0x0000, 0x0600, 0x0606, 0x1d06, 0x0606,
+ 0x1313, 0x1313, 0x1313, 0x1300, 0x0000, 0x0000, 0x1300, 0x0000, 0x1616, 0x1616, 0x1616, 0x1616, 0x0000, 0x0000, 0x0000, 0x1f00,
+ 0x0024, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2100, 0x1616, 0x1616, 0x1616, 0x0016, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x1616, 0x1616, 0x1616, 0x0016, 0x1616, 0x1616, 0x1616, 0x0016, 0x0606, 0x1c17, 0x1c17, 0x0606, 0x1706, 0x061c, 0x1c17, 0x0606,
+ 0x0606, 0x0606, 0x0606, 0x2506, 0x0606, 0x0625, 0x1c17, 0x0606, 0x1c17, 0x0a09, 0x0a09, 0x0a09, 0x0a09, 0x0606, 0x0606, 0x2006,
+ 0x0606, 0x0606, 0x0606, 0x0606, 0x0606, 0x2525, 0x0606, 0x0606, 0x0625, 0x0009, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1500, 0x1515, 0x1515, 0x1515, 0x1515, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x1515, 0x1515, 0x1515, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x0000, 0x0000,
+ 0x0605, 0x0606, 0x1f15, 0x3916, 0x0a09, 0x0a09, 0x0a09, 0x0a09, 0x0a09, 0x1515, 0x0a09, 0x0a09, 0x0a09, 0x0a09, 0x0925, 0x0a0a,
+ 0x3915, 0x3939, 0x3939, 0x3939, 0x3939, 0x2121, 0x2121, 0x3535, 0x1f25, 0x1f1f, 0x1f1f, 0x1515, 0x3939, 0x1f39, 0x0616, 0x1515,
+ 0x1616, 0x1616, 0x1616, 0x0016, 0x2100, 0x1121, 0x1f11, 0x161f, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x0616, 0x1f1f, 0x161f,
+ 0x0000, 0x0000, 0x1600, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x2222, 0x3737, 0x3737, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222,
+ 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x0016, 0x0000, 0x0000, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x1522, 0x0015,
+ 0x3737, 0x3737, 0x3737, 0x3737, 0x3737, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x3737, 0x3737, 0x3737, 0x3737,
+ 0x1d15, 0x1d1d, 0x1d1d, 0x1d1d, 0x1d1d, 0x1d1d, 0x1d1d, 0x1d1d, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x1515, 0x2215,
+ 0x1d22, 0x1d1d, 0x1d1d, 0x1d1d, 0x1d1d, 0x1d1d, 0x1d1d, 0x1d1d, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x1515, 0x1515,
+ 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x0022, 0x2222, 0x2222, 0x2222, 0x1522, 0x1515, 0x2215, 0x2222, 0x2222,
+ 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x1515, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x1522,
+ 0x1616, 0x1616, 0x1f16, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x061f, 0x0606,
+ 0x3636, 0x3636, 0x3636, 0x3636, 0x3636, 0x1616, 0x0000, 0x0000, 0x1310, 0x1310, 0x1310, 0x1310, 0x1310, 0x1310, 0x1310, 0x2116,
+ 0x2323, 0x0623, 0x2121, 0x2121, 0x2121, 0x2121, 0x2121, 0x2006, 0x1310, 0x1310, 0x1310, 0x1310, 0x1310, 0x1310, 0x1f1f, 0x2121,
+ 0x1616, 0x1616, 0x1616, 0x3939, 0x3939, 0x3939, 0x3939, 0x3939, 0x2121, 0x2424, 0x2424, 0x2424, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x1111, 0x1111, 0x1111, 0x2011, 0x2020, 0x2020, 0x2020, 0x2020, 0x1111, 0x1310, 0x1310, 0x1310, 0x1310, 0x1310, 0x1310, 0x1310,
+ 0x1313, 0x1310, 0x1310, 0x1310, 0x1310, 0x1310, 0x1310, 0x1310, 0x131f, 0x1313, 0x1313, 0x1313, 0x1013, 0x1013, 0x1013, 0x1310,
+ 0x1310, 0x1310, 0x1310, 0x1310, 0x4820, 0x1048, 0x1013, 0x1613, 0x1310, 0x1310, 0x1313, 0x1310, 0x1310, 0x1310, 0x1310, 0x1310,
+ 0x1310, 0x1310, 0x1310, 0x1310, 0x1310, 0x1010, 0x1010, 0x0000, 0x1010, 0x1010, 0x1310, 0x1310, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x1600, 0x1f1f, 0x1613, 0x1616, 0x1616, 0x1616, 0x1621, 0x1616, 0x1621, 0x1616, 0x2116, 0x1616, 0x1616,
+ 0x1616, 0x3516, 0x2135, 0x3521, 0x1515, 0x1515, 0x0000, 0x0000, 0x3737, 0x3737, 0x3737, 0x2222, 0x1908, 0x0000, 0x0000, 0x0000,
+ 0x1616, 0x1616, 0x0606, 0x0606, 0x0000, 0x0000, 0x0000, 0x0000, 0x3535, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616,
+ 0x1616, 0x1616, 0x3535, 0x3535, 0x3535, 0x3535, 0x3535, 0x3535, 0x3535, 0x3535, 0x0021, 0x0000, 0x0000, 0x0000, 0x0000, 0x2424,
+ 0x2121, 0x1616, 0x1616, 0x1616, 0x2424, 0x1624, 0x1624, 0x0000, 0x1616, 0x1616, 0x1616, 0x2121, 0x2121, 0x2121, 0x2121, 0x2424,
+ 0x1616, 0x1616, 0x1616, 0x2116, 0x2121, 0x2121, 0x2121, 0x2121, 0x2121, 0x3535, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2400,
+ 0x1616, 0x2116, 0x3535, 0x2121, 0x2121, 0x3535, 0x3521, 0x3535, 0x2435, 0x2424, 0x2424, 0x2424, 0x2424, 0x2424, 0x2424, 0x1f00,
+ 0x3636, 0x3636, 0x3636, 0x3636, 0x3636, 0x0000, 0x0000, 0x2424, 0x1616, 0x1616, 0x2116, 0x161f, 0x1616, 0x1616, 0x1616, 0x1616,
+ 0x3636, 0x3636, 0x3636, 0x3636, 0x3636, 0x1616, 0x1616, 0x0016, 0x1616, 0x1616, 0x1616, 0x1616, 0x2116, 0x2121, 0x2121, 0x3521,
+ 0x2135, 0x3521, 0x2135, 0x0021, 0x0000, 0x0000, 0x0000, 0x0000, 0x1616, 0x2116, 0x1616, 0x1616, 0x1616, 0x1616, 0x3521, 0x0000,
+ 0x3636, 0x3636, 0x3636, 0x3636, 0x3636, 0x0000, 0x2424, 0x2424, 0x161f, 0x1616, 0x1616, 0x2216, 0x2222, 0x3516, 0x3521, 0x1616,
+ 0x1621, 0x2121, 0x1621, 0x2116, 0x1621, 0x1616, 0x1616, 0x2121, 0x2116, 0x0016, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1600, 0x1f16, 0x2424, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x3516, 0x2121, 0x3535,
+ 0x2424, 0x1f16, 0x351f, 0x0021, 0x0000, 0x0000, 0x0000, 0x0000, 0x1600, 0x1616, 0x1616, 0x0016, 0x1600, 0x1616, 0x1616, 0x0016,
+ 0x1600, 0x1616, 0x1616, 0x0016, 0x0000, 0x0000, 0x0000, 0x0000, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x4813, 0x1f1f, 0x1f1f,
+ 0x1313, 0x1313, 0x1313, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1616, 0x3516, 0x2135, 0x3535, 0x3521, 0x2435, 0x2135, 0x0000,
+ 0x1616, 0x1616, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1616, 0x1616, 0x1616, 0x0016, 0x0000, 0x1600, 0x1616, 0x1616,
+ 0x4949, 0x4949, 0x4949, 0x4949, 0x4949, 0x4949, 0x4949, 0x4949, 0x4a4a, 0x4a4a, 0x4a4a, 0x4a4a, 0x4a4a, 0x4a4a, 0x4a4a, 0x4a4a,
+ 0x1313, 0x1313, 0x1313, 0x0013, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1300, 0x1313, 0x1313, 0x0000, 0x0000, 0x2800, 0x2821,
+ 0x2828, 0x2828, 0x2828, 0x2828, 0x0b28, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x0028, 0x2828, 0x2828, 0x0028, 0x0028,
+ 0x2828, 0x2800, 0x0028, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2e2e, 0x4b4b, 0x4b4b, 0x4b4b, 0x4b4b, 0x4b4b, 0x4b4b, 0x4b4b,
+ 0x4b4b, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2e00, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e,
+ 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x090a, 0x0000, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e,
+ 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x0000, 0x0000, 0x0000, 0x0000, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x152b, 0x0000,
+ 0x0606, 0x0606, 0x0606, 0x0906, 0x060a, 0x0000, 0x0000, 0x0000, 0x2506, 0x1225, 0x0912, 0x090a, 0x090a, 0x090a, 0x090a, 0x090a,
+ 0x090a, 0x090a, 0x060a, 0x0906, 0x060a, 0x0606, 0x1206, 0x1212, 0x060c, 0x000c, 0x0c06, 0x0606, 0x0925, 0x090a, 0x090a, 0x070a,
+ 0x0606, 0x0d0b, 0x0f0f, 0x000f, 0x0806, 0x0607, 0x0000, 0x0000, 0x2e2e, 0x2e2e, 0x002e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e,
+ 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x002e, 0x1800, 0x0600, 0x0706, 0x0708, 0x0606, 0x0a09, 0x0b06, 0x0d0c, 0x0c0c,
+ 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x0913, 0x0a0f, 0x090f, 0x060a, 0x0a09, 0x0606, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616,
+ 0x161f, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1f1f,
+ 0x0000, 0x1616, 0x1616, 0x1616, 0x0000, 0x1616, 0x1616, 0x1616, 0x0000, 0x1616, 0x1616, 0x1616, 0x0000, 0x1616, 0x0016, 0x0000,
+ 0x0808, 0x110f, 0x0815, 0x0008, 0x0f15, 0x0f0f, 0x150f, 0x0015, 0x0000, 0x0000, 0x0000, 0x0000, 0x4c00, 0x4c4c, 0x1515, 0x0000,
+ 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1600, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x0016, 0x1616, 0x1600,
+ 0x0624, 0x0024, 0x0000, 0x3700, 0x3737, 0x3737, 0x3737, 0x3737, 0x3737, 0x3737, 0x3737, 0x3737, 0x3737, 0x3737, 0x3737, 0x3737,
+ 0x3737, 0x3737, 0x0000, 0x2200, 0x2222, 0x2222, 0x2222, 0x2222, 0x4d4d, 0x4d4d, 0x4d4d, 0x4d4d, 0x4d4d, 0x4d4d, 0x4d4d, 0x4d4d,
+ 0x4d4d, 0x4d4d, 0x1d4d, 0x1d1d, 0x151d, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1d1d, 0x0015, 0x0000,
+ 0x0015, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x2122, 0x0000,
+ 0x1b21, 0x1b1b, 0x1b1b, 0x1b1b, 0x1b1b, 0x1b1b, 0x1b1b, 0x1b1b, 0x1b1b, 0x1b1b, 0x1b1b, 0x1b1b, 0x1b1b, 0x1b1b, 0x0000, 0x0000,
+ 0x3737, 0x3737, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3916, 0x1616, 0x1616, 0x1616, 0x1616, 0x0039, 0x0000, 0x0000,
+ 0x1616, 0x1616, 0x1616, 0x2121, 0x2121, 0x0021, 0x0000, 0x0000, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x2400,
+ 0x1616, 0x1616, 0x0000, 0x0000, 0x1616, 0x1616, 0x1616, 0x1616, 0x3924, 0x3939, 0x3939, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x1010, 0x1010, 0x1010, 0x1010, 0x1313, 0x1313, 0x1313, 0x1313, 0x1616, 0x1616, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2400,
+ 0x2828, 0x2828, 0x2828, 0x0000, 0x0028, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2800, 0x0028, 0x0000, 0x0028, 0x2800,
+ 0x2828, 0x2828, 0x2828, 0x2700, 0x4e4e, 0x4e4e, 0x4e4e, 0x4e4e, 0x2828, 0x2828, 0x2828, 0x4f28, 0x4e4f, 0x4e4e, 0x4e4e, 0x4e4e,
+ 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x0028, 0x0000, 0x0000, 0x0000, 0x4e00, 0x4e4e, 0x4e4e, 0x4e4e, 0x4e4e,
+ 0x2828, 0x0028, 0x2828, 0x0000, 0x0000, 0x4e00, 0x4e4e, 0x4e4e, 0x2828, 0x2828, 0x2828, 0x4e4e, 0x4e4e, 0x4e4e, 0x0000, 0x0600,
+ 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x0000, 0x0000, 0x2700, 0x2828, 0x2828, 0x2828, 0x2828, 0x0000, 0x0000, 0x4e4e, 0x2828,
+ 0x4e4e, 0x4e4e, 0x4e4e, 0x4e4e, 0x4e4e, 0x4e4e, 0x4e4e, 0x4e4e, 0x0000, 0x4e4e, 0x4e4e, 0x4e4e, 0x4e4e, 0x4e4e, 0x4e4e, 0x4e4e,
+ 0x2128, 0x2121, 0x2100, 0x0021, 0x0000, 0x0000, 0x2121, 0x2121, 0x2828, 0x2828, 0x2800, 0x2828, 0x2800, 0x2828, 0x2828, 0x2828,
+ 0x2828, 0x2828, 0x0000, 0x0000, 0x2121, 0x0021, 0x0000, 0x2100, 0x4e4e, 0x4e4e, 0x4e4e, 0x4e4e, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x2727, 0x2727, 0x2727, 0x2727, 0x0027, 0x0000, 0x0000, 0x0000, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x4e28, 0x274e,
+ 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x4e28, 0x4e4e, 0x2828, 0x2828, 0x2828, 0x2828, 0x284f, 0x2828, 0x2828, 0x2828,
+ 0x2828, 0x2828, 0x2128, 0x0021, 0x0000, 0x4e00, 0x4e4e, 0x4e4e, 0x2727, 0x2727, 0x2727, 0x0027, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x2828, 0x2828, 0x2828, 0x0000, 0x0600, 0x0606, 0x0606, 0x0606, 0x2828, 0x2828, 0x2828, 0x0000, 0x4e4e, 0x4e4e, 0x4e4e, 0x4e4e,
+ 0x2828, 0x0028, 0x0000, 0x0000, 0x4e4e, 0x4e4e, 0x4e4e, 0x4e4e, 0x2828, 0x0000, 0x0000, 0x0000, 0x2700, 0x2727, 0x0027, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x4e00, 0x4e4e, 0x4e4e, 0x4e4e, 0x2828, 0x2828, 0x2828, 0x2828, 0x0028, 0x0000, 0x0000, 0x0000,
+ 0x5050, 0x5050, 0x5050, 0x5050, 0x5050, 0x5050, 0x5050, 0x5050, 0x5050, 0x0050, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x5151, 0x5151, 0x5151, 0x5151, 0x5151, 0x5151, 0x5151, 0x5151, 0x5151, 0x0051, 0x0000, 0x0000, 0x0000, 0x4e4e, 0x4e4e, 0x4e4e,
+ 0x5252, 0x5252, 0x5252, 0x5252, 0x5252, 0x5252, 0x5252, 0x5252, 0x5252, 0x5252, 0x5252, 0x5252, 0x5252, 0x5252, 0x5252, 0x0052,
+ 0x2135, 0x1635, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x2121, 0x2121, 0x2121, 0x2121,
+ 0x2121, 0x2121, 0x2121, 0x2421, 0x2424, 0x2424, 0x2424, 0x0000, 0x0000, 0x1d1d, 0x1d1d, 0x1d1d, 0x1d1d, 0x1d1d, 0x1d1d, 0x1d1d,
+ 0x1d1d, 0x1d1d, 0x1d1d, 0x3636, 0x3636, 0x3636, 0x3636, 0x3636, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2100,
+ 0x3535, 0x2135, 0x2121, 0x3521, 0x2135, 0x2421, 0x3a24, 0x2424, 0x2424, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x1616, 0x1616, 0x1616, 0x1616, 0x0016, 0x0000, 0x0000, 0x0000, 0x2121, 0x1621, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616,
+ 0x1616, 0x1616, 0x1616, 0x2116, 0x2121, 0x2121, 0x2135, 0x2121, 0x2121, 0x2121, 0x0021, 0x3636, 0x3636, 0x3636, 0x3636, 0x3636,
+ 0x2424, 0x2424, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1616, 0x2116, 0x2424, 0x0016, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x1616, 0x3516, 0x3535, 0x2121, 0x2121, 0x2121, 0x2121, 0x3521, 0x1635, 0x1616, 0x2416, 0x2424, 0x2424, 0x2121, 0x2421, 0x0000,
+ 0x3636, 0x3636, 0x3636, 0x3636, 0x3636, 0x2416, 0x2416, 0x2424, 0x3700, 0x3737, 0x3737, 0x3737, 0x3737, 0x3737, 0x3737, 0x3737,
+ 0x3737, 0x3737, 0x0037, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x3535, 0x2135,
+ 0x2121, 0x3535, 0x3521, 0x2121, 0x2424, 0x2424, 0x2424, 0x0000, 0x1616, 0x1616, 0x1616, 0x0016, 0x0016, 0x1616, 0x1616, 0x1600,
+ 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1600, 0x1616, 0x1616, 0x1616, 0x1616, 0x2416, 0x0000, 0x0000, 0x0000,
+ 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x2116, 0x3535, 0x2135, 0x2121, 0x2121, 0x2121, 0x0021, 0x0000, 0x0000,
+ 0x2121, 0x3535, 0x1600, 0x1616, 0x1616, 0x1616, 0x0016, 0x1600, 0x3521, 0x3535, 0x0035, 0x3500, 0x0035, 0x3500, 0x3535, 0x0000,
+ 0x0016, 0x0000, 0x0000, 0x3500, 0x0000, 0x0000, 0x1600, 0x1616, 0x1616, 0x3535, 0x0000, 0x2121, 0x2121, 0x2121, 0x0021, 0x0000,
+ 0x2121, 0x2121, 0x0021, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3535, 0x2135, 0x2121, 0x2121, 0x3521, 0x3521, 0x3535, 0x2135,
+ 0x3521, 0x2121, 0x1616, 0x1624, 0x0000, 0x0000, 0x0000, 0x0000, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x3516,
+ 0x3535, 0x2121, 0x2121, 0x0000, 0x3535, 0x3535, 0x2121, 0x2135, 0x2421, 0x2424, 0x2424, 0x2424, 0x2424, 0x2424, 0x2424, 0x2424,
+ 0x2424, 0x2424, 0x2424, 0x2424, 0x1616, 0x1616, 0x2121, 0x0000, 0x3535, 0x2135, 0x2121, 0x2121, 0x2121, 0x3521, 0x2135, 0x2135,
+ 0x2421, 0x2424, 0x0016, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x2116, 0x2135, 0x3535,
+ 0x2121, 0x2121, 0x2121, 0x2135, 0x0000, 0x0000, 0x0000, 0x0000, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x0000, 0x2100, 0x2121,
+ 0x3535, 0x2121, 0x2121, 0x2135, 0x2121, 0x2121, 0x0000, 0x0000, 0x3636, 0x3636, 0x3636, 0x3636, 0x3636, 0x3737, 0x2424, 0x2224,
+ 0x3737, 0x0037, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1600, 0x3939, 0x3939, 0x3939, 0x3939, 0x3939, 0x3939, 0x3939, 0x0039,
+ 0x2424, 0x2424, 0x0024, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2121, 0x2121, 0x2421, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x2121, 0x2121, 0x2121, 0x2421, 0x2424, 0x2424, 0x2222, 0x2222, 0x1f1f, 0x1f1f, 0x2224, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x3636, 0x3636, 0x3636, 0x3636, 0x3636, 0x3700, 0x3737, 0x3737, 0x3737, 0x1600, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x1616,
+ 0x1616, 0x1616, 0x1616, 0x1616, 0x0000, 0x0000, 0x1600, 0x1616, 0x3516, 0x3535, 0x3535, 0x3535, 0x3535, 0x3535, 0x3535, 0x3535,
+ 0x3535, 0x3535, 0x3535, 0x3535, 0x3535, 0x3535, 0x3535, 0x3535, 0x3535, 0x3535, 0x3535, 0x3535, 0x3535, 0x3535, 0x3535, 0x0035,
+ 0x2121, 0x1f21, 0x1f1f, 0x1f1f, 0x1f1f, 0x1f1f, 0x1f1f, 0x1f1f, 0x1616, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x1616, 0x1616, 0x1616, 0x1616, 0x1616, 0x0000, 0x2122, 0x2421, 0x1818, 0x1818, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x2222, 0x2222, 0x2222, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2222, 0x2222, 0x2222, 0x0022, 0x2200, 0x2222, 0x2222, 0x2222,
+ 0x2222, 0x2222, 0x3522, 0x2135, 0x2121, 0x2222, 0x3522, 0x3535, 0x3535, 0x1835, 0x1818, 0x1818, 0x1818, 0x2118, 0x2121, 0x2121,
+ 0x2121, 0x2221, 0x2122, 0x2121, 0x2121, 0x2121, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x2121, 0x2121, 0x2222,
+ 0x2222, 0x2222, 0x2222, 0x2222, 0x0022, 0x0000, 0x0000, 0x0000, 0x1515, 0x2121, 0x1521, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x3737, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1313, 0x1313, 0x1313,
+ 0x1313, 0x1313, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1313,
+ 0x1313, 0x1313, 0x0013, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1010, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313,
+ 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x0010, 0x1010, 0x0000, 0x0010, 0x1000, 0x0010, 0x1000, 0x1010, 0x0010, 0x1010,
+ 0x1010, 0x1010, 0x1010, 0x1313, 0x1313, 0x1300, 0x1300, 0x1313, 0x1313, 0x1313, 0x1300, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313,
+ 0x1313, 0x1313, 0x1010, 0x1000, 0x1010, 0x0010, 0x1000, 0x1010, 0x1010, 0x1010, 0x0010, 0x1010, 0x1010, 0x1010, 0x0010, 0x1313,
+ 0x1313, 0x1313, 0x1313, 0x1313, 0x1010, 0x1000, 0x1010, 0x0010, 0x1010, 0x1010, 0x0010, 0x0010, 0x0000, 0x1010, 0x1010, 0x1010,
+ 0x0010, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1010, 0x1010,
+ 0x1010, 0x1010, 0x1010, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x0000, 0x1010, 0x1010, 0x1010, 0x1010,
+ 0x5310, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x0f13, 0x1313, 0x1313,
+ 0x1313, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x5310, 0x1313, 0x1313,
+ 0x1313, 0x1313, 0x0f13, 0x1313, 0x1313, 0x1313, 0x1010, 0x1010, 0x1010, 0x1010, 0x5310, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313,
+ 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x1313, 0x0f13, 0x1313, 0x1313, 0x1313, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010,
+ 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x1010, 0x5310, 0x1313, 0x1313, 0x1313, 0x1313, 0x0f13, 0x1313, 0x1313, 0x1313,
+ 0x1010, 0x1010, 0x1010, 0x1010, 0x5310, 0x1313, 0x1313, 0x1313, 0x1313, 0x0f13, 0x1313, 0x1313, 0x1313, 0x1310, 0x0000, 0x0e0e,
+ 0x0e0e, 0x0e0e, 0x0e0e, 0x0e0e, 0x0e0e, 0x0e0e, 0x0e0e, 0x0e0e, 0x2121, 0x2121, 0x2121, 0x2221, 0x2222, 0x2122, 0x2121, 0x2121,
+ 0x2121, 0x2121, 0x2121, 0x2121, 0x2121, 0x2121, 0x2221, 0x2222, 0x2222, 0x2222, 0x2122, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222,
+ 0x2222, 0x2222, 0x2221, 0x2422, 0x2424, 0x2424, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2100, 0x2121, 0x2121,
+ 0x2828, 0x2828, 0x0028, 0x4e00, 0x4e4e, 0x4e4e, 0x4e4e, 0x4e4e, 0x2121, 0x2121, 0x2121, 0x0021, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x2e2e, 0x2e2e, 0x2e00, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e00, 0x002e, 0x002e, 0x2e00, 0x2e00, 0x2e2e, 0x2e2e, 0x2e2e,
+ 0x2e2e, 0x002e, 0x2e2e, 0x2e2e, 0x2e00, 0x2e00, 0x0000, 0x0000, 0x0000, 0x002e, 0x0000, 0x2e00, 0x2e00, 0x2e00, 0x2e00, 0x2e2e,
+ 0x2e00, 0x002e, 0x002e, 0x2e00, 0x2e00, 0x2e00, 0x2e00, 0x2e00, 0x2e00, 0x002e, 0x002e, 0x2e00, 0x2e2e, 0x002e, 0x2e2e, 0x2e2e,
+ 0x2e2e, 0x002e, 0x2e2e, 0x2e2e, 0x2e00, 0x2e2e, 0x002e, 0x002e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e00, 0x2e2e, 0x2e2e,
+ 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x2e2e, 0x0000, 0x0000, 0x2e00, 0x2e2e, 0x2e00, 0x2e2e, 0x2e2e, 0x2e00, 0x2e2e, 0x2e2e,
+ 0x0f0f, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x0015,
+ 0x1500, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1b1b, 0x1b1b, 0x1b1b, 0x1b1b, 0x1b1b, 0x1d1b, 0x001d, 0x0000,
+ 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x1515, 0x0000, 0x0000, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x0022, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x2222, 0x0022, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x2222, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1115, 0x1111, 0x1111,
+ 0x1515, 0x1515, 0x1500, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x0015, 0x0000,
+ 0x1515, 0x1515, 0x0015, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1515, 0x1515, 0x1515, 0x1515, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x1515, 0x0000, 0x1515, 0x1515, 0x1515, 0x1515, 0x0015, 0x0000, 0x0000, 0x0000,
+ 0x1800, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1818, 0x1818, 0x1818, 0x1818, 0x1818, 0x1818, 0x1818, 0x1818,
+ 0x4a4a, 0x4a4a, 0x4a4a, 0x4a4a, 0x4a4a, 0x4a4a, 0x4a4a, 0x0000, 0xeeee, 0xeeee
+ };
+
+ private static byte[] s_pCategoriesValue = new byte[]
+ {
+ 0x1d, 0x00, 0x0e, 0x0e, 0x0e, 0x10, 0x0e, 0x0f, 0x0e, 0x11, 0x0b, 0x11, 0x18, 0x12, 0x18, 0x0a,
+ 0x1a, 0x0a, 0x14, 0x12, 0x15, 0x12, 0x19, 0x09, 0x18, 0x0c, 0x13, 0x09, 0x08, 0x08, 0x19, 0x12,
+ 0x00, 0x00, 0x1b, 0x12, 0x12, 0x12, 0x01, 0x00, 0x0b, 0x0c, 0x1c, 0x12, 0x04, 0x00, 0x16, 0x12,
+ 0x0f, 0x0e, 0x1c, 0x0a, 0x19, 0x0a, 0x0a, 0x08, 0x17, 0x12, 0x0a, 0x12, 0x02, 0x00, 0x03, 0x00,
+ 0x03, 0x12, 0x05, 0x0d, 0x1c, 0x00, 0x07, 0x0d, 0x18, 0x00, 0x13, 0x12, 0x13, 0x03, 0x18, 0x03,
+ 0x04, 0x03, 0x0f, 0x0b, 0x19, 0x04, 0x1a, 0x04, 0x18, 0x04, 0x0f, 0x04, 0x04, 0x04, 0x03, 0x04,
+ 0x08, 0x0b, 0x18, 0x0b, 0x1c, 0x04, 0x08, 0x03, 0x03, 0x03, 0x06, 0x00, 0x08, 0x00, 0x0a, 0x00,
+ 0x05, 0x00, 0x09, 0x00, 0x0f, 0x00, 0x0f, 0x03, 0x0c, 0x11, 0x0d, 0x0f, 0x0f, 0x01, 0x0f, 0x05,
+ 0x0f, 0x07, 0x0f, 0x02, 0x0f, 0x06, 0x19, 0x0c, 0x0f, 0x13, 0x0f, 0x14, 0x0f, 0x15, 0x0f, 0x16,
+ 0x1b, 0x00, 0x10, 0x00, 0x11, 0x00, 0x1b, 0x04, 0x0f, 0x12, 0x09, 0x12, 0x0a, 0x03, 0x1c, 0x03,
+ 0x00, 0x03, 0x01, 0x03, 0x0a, 0x0b, 0x19, 0x00
+ };
+ // 12:4:4 index table of the Unicode numeric data.
+ private static ushort[] s_pNumericLevel1Index = new ushort[]
+ {
+ 0x1100, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1120, 0x1130, 0x1110, 0x1140, 0x1150, 0x1160, 0x1170, 0x1180, 0x1190, 0x11a0,
+ 0x11b0, 0x1110, 0x1110, 0x11c0, 0x1110, 0x1110, 0x11d0, 0x11e0, 0x11f0, 0x1200, 0x1210, 0x1220, 0x1230, 0x1110, 0x1110, 0x1110,
+ 0x1240, 0x1250, 0x1110, 0x1110, 0x1260, 0x1110, 0x1110, 0x1270, 0x1110, 0x1110, 0x1110, 0x1110, 0x1280, 0x1110, 0x1110, 0x1110,
+ 0x1290, 0x12a0, 0x12b0, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x12c0, 0x1110, 0x12d0, 0x12e0, 0x12f0, 0x1300, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1310, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x11f0,
+ 0x1110, 0x1320, 0x1330, 0x1340, 0x1350, 0x1110, 0x1110, 0x1110, 0x1360, 0x1370, 0x1380, 0x1390, 0x13a0, 0x1110, 0x13b0, 0x1110,
+ 0x13c0, 0x13d0, 0x1300, 0x1110, 0x13e0, 0x1110, 0x13f0, 0x1400, 0x1410, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1420, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1430, 0x1440, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1450, 0x1110, 0x1110, 0x1110, 0x1460, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1470, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1480, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1490, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110, 0x1110,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a8, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14b0, 0x14a0, 0x14a0, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a8, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a8,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a8, 0x14a0, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14b8, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14b8, 0x14c0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14b8, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14b8, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14b8, 0x14c8, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14b8, 0x14d0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14b8, 0x14d8, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14b8, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14b8, 0x14e0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14b8, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a8, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a8, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14e8, 0x14f0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a8, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a8, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14f8, 0x1500, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x1508, 0x1510,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a8, 0x1518,
+ 0x14a0, 0x14a8, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14b8, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x1520, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a8, 0x14a8, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a8, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a8, 0x14a0, 0x14a0, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a8, 0x14a8, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x1528, 0x1530, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x1538, 0x1540, 0x1540, 0x1548, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x1550, 0x1558, 0x1560, 0x1568, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x1570, 0x1578,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x1580, 0x1588, 0x1590, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x1598,
+ 0x15a0, 0x14a0, 0x15a8, 0x15b0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x15b8, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x15c0, 0x14a0, 0x15c8, 0x15d0, 0x14a0, 0x14a0, 0x15c0, 0x14a0, 0x14a0, 0x15d8, 0x14a0, 0x14a0, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a8, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x15e0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x15e8, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a8, 0x14a0, 0x14a0,
+ 0x14a8, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a8, 0x14a0, 0x14a8,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a8, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a8,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x15f0, 0x15f8, 0x14a0, 0x14a0, 0x14a0, 0x1600, 0x14a0, 0x1608, 0x14a0, 0x1610,
+ 0x1618, 0x1620, 0x1628, 0x1630, 0x1638, 0x1640, 0x1648, 0x1650, 0x1658, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x1660, 0x1668,
+ 0x14a0, 0x14a0, 0x1670, 0x14a0, 0x1678, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x1680, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a8, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x1688, 0x14a0, 0x1690, 0x14a0, 0x14a0, 0x1698, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x16a0,
+ 0x14a0, 0x16a8, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x16b0, 0x16b8, 0x16c0, 0x16c8, 0x16d0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x16d8, 0x14a0, 0x14a0, 0x16e0, 0x14a0, 0x16e8, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x16a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x16f0, 0x14a0, 0x16f0, 0x14a0, 0x14a0, 0x16f8, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x1700,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x1708, 0x1710, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x1718, 0x1720, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a8,
+ 0x14a0, 0x14a0, 0x14a0, 0x14b8, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a8, 0x1660, 0x1728,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a8, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a8, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a8, 0x14a0, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x1730, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x1738, 0x1740,
+ 0x1748, 0x1750, 0x1758, 0x1760, 0x1768, 0x1770, 0x1778, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a8, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x1780, 0x1788, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x16b8, 0x1790, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x1798, 0x17a0, 0x17a8, 0x17b0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x1618, 0x14a0, 0x14a0, 0x14a0,
+ 0x17b8, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0,
+ 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x17c0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0, 0x14a0,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0201, 0x0403, 0x0605, 0x0807, 0x0a09, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0c0b, 0x0000, 0x0000, 0x0d00, 0x0000, 0x0f0e, 0x0010, 0x0000, 0x0000, 0x0000, 0x0201, 0x0403, 0x0605, 0x0807, 0x0a09,
+ 0x0000, 0x0000, 0x1211, 0x0e13, 0x1410, 0x0000, 0x0000, 0x0000, 0x0000, 0x0f0e, 0x1110, 0x1312, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x1615, 0x0017, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1918, 0x1b1a, 0x1a19, 0x001b,
+ 0x1615, 0x0e17, 0x100f, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0201, 0x0403, 0x0605, 0x0807, 0x0a09, 0x1c0f, 0x1e1d, 0x201f,
+ 0x2221, 0x2423, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0d00, 0x0c0b, 0x2625, 0x2827,
+ 0x2a29, 0x2b15, 0x2d2c, 0x2f2e, 0x3130, 0x1632, 0x0033, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3534,
+ 0x0036, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1918, 0x1b1a, 0x3837, 0x3a39, 0x3c3b, 0x0000, 0x0000, 0x0000,
+ 0x0201, 0x0403, 0x0605, 0x0807, 0x0a09, 0x000d, 0x0000, 0x0000, 0x003d, 0x0000, 0x2625, 0x2827, 0x2a29, 0x0000, 0x0000, 0x0000,
+ 0x0d3d, 0x0c0b, 0x2625, 0x2827, 0x2a29, 0x0000, 0x0000, 0x0000, 0x3f3e, 0x4140, 0x4342, 0x4544, 0x4746, 0x1248, 0x4a49, 0x194b,
+ 0x1a19, 0x371b, 0x3938, 0x3b3a, 0x153c, 0x4d4c, 0x162e, 0x174e, 0x4f17, 0x0033, 0x3900, 0x502e, 0x1851, 0x0000, 0x0000, 0x0000,
+ 0x0b0d, 0x250c, 0x2726, 0x2928, 0x152a, 0x4d4c, 0x5352, 0x1454, 0x3534, 0x2b36, 0x0b0d, 0x250c, 0x2726, 0x2928, 0x152a, 0x4d4c,
+ 0x5352, 0x1454, 0x3534, 0x2b36, 0x0b0d, 0x250c, 0x2726, 0x2928, 0x152a, 0x4d4c, 0x5352, 0x1454, 0x3534, 0x2b36, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x4c3d, 0x524d, 0x5453, 0x3414, 0x3635, 0x0d2b, 0x0c0b, 0x2625, 0x2827, 0x2a29, 0x3d15,
+ 0x0000, 0x0000, 0x0000, 0x0b0d, 0x250c, 0x2726, 0x2928, 0x152a, 0x0b0d, 0x250c, 0x2726, 0x2928, 0x152a, 0x0b0d, 0x250c, 0x2726,
+ 0x2928, 0x152a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0f00, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x1800, 0x0000, 0x0000, 0x0000, 0x0000, 0x1900, 0x1b1a, 0x3837, 0x3a39, 0x3c3b, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x2b15, 0x002c, 0x0000, 0x0000, 0x0000, 0x1a19, 0x371b, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x1a19, 0x371b, 0x3938, 0x3b3a, 0x153c, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2b15, 0x2d2c, 0x2f2e, 0x3130,
+ 0x5500, 0x5756, 0x5958, 0x5b5a, 0x5d5c, 0x5e2c, 0x605f, 0x6261, 0x6300, 0x6564, 0x2d66, 0x6867, 0x6a69, 0x6c6b, 0x6e6d, 0x2e6f,
+ 0x0000, 0x0000, 0x0000, 0x1a19, 0x371b, 0x3938, 0x3b3a, 0x183c, 0x0f0e, 0x1110, 0x1312, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1b00, 0x0000, 0x0000, 0x0000, 0x1500, 0x0000, 0x0000, 0x001a, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0018, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3900, 0x3900, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1500, 0x0000, 0x0000, 0x0000, 0x0000, 0x1900, 0x1b1a, 0x3837, 0x3a39, 0x3c3b,
+ 0x2b15, 0x2d2c, 0x2f2e, 0x3130, 0x1632, 0x7170, 0x4e72, 0x7473, 0x7675, 0x7717, 0x7978, 0x7a4f, 0x7c7b, 0x337d, 0x7f7e, 0x5080,
+ 0x8281, 0x8483, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0f0e, 0x3819, 0x4e2e, 0x504f, 0x1538, 0x162e, 0x174e, 0x384f,
+ 0x2e15, 0x4e16, 0x3317, 0x1550, 0x1919, 0x1a19, 0x1a1a, 0x381a, 0x1515, 0x1515, 0x2c15, 0x2e2e, 0x2e2e, 0x7116, 0x4e4e, 0x4e4e,
+ 0x174e, 0x384f, 0x0f2e, 0x420f, 0x0010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0e18, 0x0000, 0x0000,
+ 0x1900, 0x1b1a, 0x3837, 0x3a39, 0x3c3b, 0x2b15, 0x2d2c, 0x2f2e, 0x3130, 0x1632, 0x7170, 0x4e72, 0x7473, 0x7675, 0x0000, 0x0000,
+ 0x3819, 0x2e15, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3200, 0x0000, 0x0000, 0x0000, 0x0000, 0x0076, 0x0000, 0x0000,
+ 0x1900, 0x151a, 0x162b, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1a19, 0x151b, 0x162b, 0x3317,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x1900, 0x1b1a, 0x3837, 0x2b15, 0x0000, 0x0000, 0x0000, 0x1900, 0x1b1a, 0x3737, 0x1538, 0x162b,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1900, 0x1538, 0x162b, 0x0000, 0x0000, 0x0000, 0x1519, 0x162b, 0x1b1a, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0f85, 0x0000, 0x1a19, 0x371b, 0x3938, 0x3b3a, 0x153c, 0x2c2b, 0x2e2d, 0x302f,
+ 0x0000, 0x7016, 0x7271, 0x734e, 0x7574, 0x1776, 0x7877, 0x4f79, 0x7b7a, 0x7d7c, 0x7e33, 0x807f, 0x8150, 0x8382, 0x5184, 0x8786,
+ 0x8988, 0x8b8a, 0x8d8c, 0x8f8e, 0x9190, 0x9392, 0x9594, 0x9796, 0x0b0d, 0x250c, 0x2b15, 0x1716, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1900, 0x002e, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1900, 0x2b15,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x1a19, 0x371b, 0x2b15, 0x1716, 0x0000, 0x0000, 0x0000, 0x0000, 0x1900, 0x1b1a, 0x1537, 0x162b,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3819, 0x2e15, 0x1716, 0x0b0d, 0x250c, 0x2726, 0x2928, 0x152a, 0x2c2b, 0x2e2d, 0x302f,
+ 0x3231, 0x7016, 0x7271, 0x734e, 0x7574, 0x0f76, 0x410e, 0x0042, 0x0000, 0x0b0d, 0x250c, 0x2726, 0x2928, 0x152a, 0x2c2b, 0x2e2d,
+ 0x302f, 0x3231, 0x1716, 0x0201, 0x0403, 0x0605, 0x0807, 0x0a09, 0x3130, 0x1632, 0x0017, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0201, 0x0403, 0x0605, 0x0807, 0x0a09, 0x2b15, 0x0000, 0x0000, 0x0201, 0x0403, 0x0605, 0x0807, 0x0a09, 0x2b15, 0x2d2c, 0x2f2e,
+ 0x3130, 0x0032, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1b1a, 0x3837, 0x3a39, 0x3c3b, 0x371b, 0x3938, 0x3b3a, 0x373c,
+ 0x3938, 0x3b3a, 0x193c, 0x1b1a, 0x3837, 0x3a39, 0x3c3b, 0x1a19, 0x371b, 0x1a38, 0x1b1b, 0x3837, 0x3a39, 0x3c3b, 0x1a19, 0x1b1b,
+ 0x3837, 0x9998, 0x1a19, 0x1b1b, 0x3837, 0x1b1b, 0x3737, 0x3737, 0x3a39, 0x3a3a, 0x3b3b, 0x3c3c, 0x3c3c, 0x1b1a, 0x3837, 0x1939,
+ 0x1b1a, 0x3737, 0x3838, 0x1b1a, 0x1a19, 0x4241, 0x4148, 0x1242, 0x470e, 0x0e0e, 0x410f, 0x2d42, 0x372e, 0x3938, 0x3b3a, 0x003c,
+ 0x0201, 0x0403, 0x0605, 0x0807, 0x0a09, 0x1500, 0x3316, 0x9b9a, 0x9d9c, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x3231, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0201,
+ 0x0403, 0x0605, 0x0807, 0x0a09, 0x0201, 0x0403, 0x0605, 0x0807, 0x0a09, 0x0201, 0x0403, 0x0605, 0x0807, 0x0a09, 0x0201, 0x0403,
+ 0x0605, 0x0807, 0x0a09, 0x0201, 0x0403, 0x0605, 0x0807, 0x0a09, 0x3d3d, 0x0b0d, 0x250c, 0x2726, 0x2928, 0x182a, 0x0018, 0x0000,
+ 0x003c, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xeeee, 0xeeee, 0xeeee, 0xeeee
+ };
+ // Every item contains the value for numeric value.
+ private static byte[] s_pNumericValues = new byte[]
+ {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x3f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x3f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x3f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x8f, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x51, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x56, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0xc3, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x92, 0x24, 0x49, 0x92, 0x24, 0x49, 0xc2, 0x3f, 0x1c, 0xc7, 0x71, 0x1c, 0xc7, 0x71, 0xbc, 0x3f,
+ 0x9a, 0x99, 0x99, 0x99, 0x99, 0x99, 0xb9, 0x3f, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5, 0x3f,
+ 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xe5, 0x3f, 0x9a, 0x99, 0x99, 0x99, 0x99, 0x99, 0xc9, 0x3f,
+ 0x9a, 0x99, 0x99, 0x99, 0x99, 0x99, 0xd9, 0x3f, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0xe3, 0x3f,
+ 0x9a, 0x99, 0x99, 0x99, 0x99, 0x99, 0xe9, 0x3f, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xc5, 0x3f,
+ 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x3f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xec, 0x3f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x7f, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0xb3, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x6a, 0xe8, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6a, 0xf8, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x35, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x41, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x42, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x43, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x44, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x45, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x46, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x47, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x48, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x69, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x72, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x82, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x85, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x8c, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x9f, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xa7, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xaf, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xb7, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0xbb, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xbf, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x94, 0xc1, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0xd3, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, 0xdd, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0xe3, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, 0xed, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0xf1, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0xf3, 0x40,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xf9, 0xf5, 0x40, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xed, 0x3f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x6a, 0x08, 0x41, 0x00, 0x00, 0x00, 0x00, 0x80, 0x4f, 0x12, 0x41,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x6a, 0x18, 0x41, 0x00, 0x00, 0x00, 0x00, 0x80, 0x84, 0x1e, 0x41,
+ 0x00, 0x00, 0x00, 0x00, 0x80, 0x4f, 0x22, 0x41, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x5c, 0x25, 0x41,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x6a, 0x28, 0x41, 0x00, 0x00, 0x00, 0x00, 0x40, 0x77, 0x2b, 0x41,
+ 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xb5, 0x3f, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xc5, 0x3f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x3f, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5, 0x3f,
+ 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xda, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x3f,
+ 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xe2, 0x3f, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xe5, 0x3f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0x3f, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea, 0x3f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x0a, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x1a, 0x41,
+ 0x00, 0x00, 0x00, 0x00, 0x80, 0x84, 0x2e, 0x41, 0x00, 0x00, 0x00, 0x00, 0x84, 0xd7, 0x97, 0x41,
+ 0x00, 0x00, 0x00, 0x20, 0x5f, 0xa0, 0x02, 0x42, 0x00, 0x00, 0x00, 0xa2, 0x94, 0x1a, 0x6d, 0x42
+ };
+ }
+}
diff --git a/src/mscorlib/corefx/System/Globalization/ChineseLunisolarCalendar.cs b/src/mscorlib/corefx/System/Globalization/ChineseLunisolarCalendar.cs
new file mode 100644
index 0000000000..48f62019d7
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/ChineseLunisolarCalendar.cs
@@ -0,0 +1,399 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Diagnostics.Contracts;
+
+namespace System.Globalization
+{
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Notes about ChineseLunisolarCalendar
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ /*
+ ** Calendar support range:
+ ** Calendar Minimum Maximum
+ ** ========== ========== ==========
+ ** Gregorian 1901/02/19 2101/01/28
+ ** ChineseLunisolar 1901/01/01 2100/12/29
+ */
+ [Serializable]
+ public class ChineseLunisolarCalendar : EastAsianLunisolarCalendar
+ {
+ //
+ // The era value for the current era.
+ //
+
+ public const int ChineseEra = 1;
+
+ internal const int MIN_LUNISOLAR_YEAR = 1901;
+ internal const int MAX_LUNISOLAR_YEAR = 2100;
+
+ internal const int MIN_GREGORIAN_YEAR = 1901;
+ internal const int MIN_GREGORIAN_MONTH = 2;
+ internal const int MIN_GREGORIAN_DAY = 19;
+
+ internal const int MAX_GREGORIAN_YEAR = 2101;
+ internal const int MAX_GREGORIAN_MONTH = 1;
+ internal const int MAX_GREGORIAN_DAY = 28;
+
+ internal static DateTime minDate = new DateTime(MIN_GREGORIAN_YEAR, MIN_GREGORIAN_MONTH, MIN_GREGORIAN_DAY);
+ internal static DateTime maxDate = new DateTime((new DateTime(MAX_GREGORIAN_YEAR, MAX_GREGORIAN_MONTH, MAX_GREGORIAN_DAY, 23, 59, 59, 999)).Ticks + 9999);
+
+ [System.Runtime.InteropServices.ComVisible(false)]
+ public override DateTime MinSupportedDateTime
+ {
+ get
+ {
+ return (minDate);
+ }
+ }
+
+
+ [System.Runtime.InteropServices.ComVisible(false)]
+ public override DateTime MaxSupportedDateTime
+ {
+ get
+ {
+ return (maxDate);
+ }
+ }
+
+ protected override int DaysInYearBeforeMinSupportedYear
+ {
+ get
+ {
+ // 1900: 1-29 2-30 3-29 4-29 5-30 6-29 7-30 8-30 Leap8-29 9-30 10-30 11-29 12-30 from Calendrical Tabulations
+ return 384;
+ }
+ }
+
+
+ private static readonly int[,] s_yinfo =
+ {
+ /*Y LM Lmon Lday DaysPerMonth D1 D2 D3 D4 D5 D6 D7 D8 D9 D10 D11 D12 D13 #Days
+ 1901 */
+ { 0 , 2 , 19 , 19168 },/* 29 30 29 29 30 29 30 29 30 30 30 29 0 354
+1902 */{ 0 , 2 , 8 , 42352 },/* 30 29 30 29 29 30 29 30 29 30 30 30 0 355
+1903 */{ 5 , 1 , 29 , 21096 },/* 29 30 29 30 29 29 30 29 29 30 30 29 30 383
+1904 */{ 0 , 2 , 16 , 53856 },/* 30 30 29 30 29 29 30 29 29 30 30 29 0 354
+1905 */{ 0 , 2 , 4 , 55632 },/* 30 30 29 30 30 29 29 30 29 30 29 30 0 355
+1906 */{ 4 , 1 , 25 , 27304 },/* 29 30 30 29 30 29 30 29 30 29 30 29 30 384
+1907 */{ 0 , 2 , 13 , 22176 },/* 29 30 29 30 29 30 30 29 30 29 30 29 0 354
+1908 */{ 0 , 2 , 2 , 39632 },/* 30 29 29 30 30 29 30 29 30 30 29 30 0 355
+1909 */{ 2 , 1 , 22 , 19176 },/* 29 30 29 29 30 29 30 29 30 30 30 29 30 384
+1910 */{ 0 , 2 , 10 , 19168 },/* 29 30 29 29 30 29 30 29 30 30 30 29 0 354
+1911 */{ 6 , 1 , 30 , 42200 },/* 30 29 30 29 29 30 29 29 30 30 29 30 30 384
+1912 */{ 0 , 2 , 18 , 42192 },/* 30 29 30 29 29 30 29 29 30 30 29 30 0 354
+1913 */{ 0 , 2 , 6 , 53840 },/* 30 30 29 30 29 29 30 29 29 30 29 30 0 354
+1914 */{ 5 , 1 , 26 , 54568 },/* 30 30 29 30 29 30 29 30 29 29 30 29 30 384
+1915 */{ 0 , 2 , 14 , 46400 },/* 30 29 30 30 29 30 29 30 29 30 29 29 0 354
+1916 */{ 0 , 2 , 3 , 54944 },/* 30 30 29 30 29 30 30 29 30 29 30 29 0 355
+1917 */{ 2 , 1 , 23 , 38608 },/* 30 29 29 30 29 30 30 29 30 30 29 30 29 384
+1918 */{ 0 , 2 , 11 , 38320 },/* 30 29 29 30 29 30 29 30 30 29 30 30 0 355
+1919 */{ 7 , 2 , 1 , 18872 },/* 29 30 29 29 30 29 29 30 30 29 30 30 30 384
+1920 */{ 0 , 2 , 20 , 18800 },/* 29 30 29 29 30 29 29 30 29 30 30 30 0 354
+1921 */{ 0 , 2 , 8 , 42160 },/* 30 29 30 29 29 30 29 29 30 29 30 30 0 354
+1922 */{ 5 , 1 , 28 , 45656 },/* 30 29 30 30 29 29 30 29 29 30 29 30 30 384
+1923 */{ 0 , 2 , 16 , 27216 },/* 29 30 30 29 30 29 30 29 29 30 29 30 0 354
+1924 */{ 0 , 2 , 5 , 27968 },/* 29 30 30 29 30 30 29 30 29 30 29 29 0 354
+1925 */{ 4 , 1 , 24 , 44456 },/* 30 29 30 29 30 30 29 30 30 29 30 29 30 385
+1926 */{ 0 , 2 , 13 , 11104 },/* 29 29 30 29 30 29 30 30 29 30 30 29 0 354
+1927 */{ 0 , 2 , 2 , 38256 },/* 30 29 29 30 29 30 29 30 29 30 30 30 0 355
+1928 */{ 2 , 1 , 23 , 18808 },/* 29 30 29 29 30 29 29 30 29 30 30 30 30 384
+1929 */{ 0 , 2 , 10 , 18800 },/* 29 30 29 29 30 29 29 30 29 30 30 30 0 354
+1930 */{ 6 , 1 , 30 , 25776 },/* 29 30 30 29 29 30 29 29 30 29 30 30 29 383
+1931 */{ 0 , 2 , 17 , 54432 },/* 30 30 29 30 29 30 29 29 30 29 30 29 0 354
+1932 */{ 0 , 2 , 6 , 59984 },/* 30 30 30 29 30 29 30 29 29 30 29 30 0 355
+1933 */{ 5 , 1 , 26 , 27976 },/* 29 30 30 29 30 30 29 30 29 30 29 29 30 384
+1934 */{ 0 , 2 , 14 , 23248 },/* 29 30 29 30 30 29 30 29 30 30 29 30 0 355
+1935 */{ 0 , 2 , 4 , 11104 },/* 29 29 30 29 30 29 30 30 29 30 30 29 0 354
+1936 */{ 3 , 1 , 24 , 37744 },/* 30 29 29 30 29 29 30 30 29 30 30 30 29 384
+1937 */{ 0 , 2 , 11 , 37600 },/* 30 29 29 30 29 29 30 29 30 30 30 29 0 354
+1938 */{ 7 , 1 , 31 , 51560 },/* 30 30 29 29 30 29 29 30 29 30 30 29 30 384
+1939 */{ 0 , 2 , 19 , 51536 },/* 30 30 29 29 30 29 29 30 29 30 29 30 0 354
+1940 */{ 0 , 2 , 8 , 54432 },/* 30 30 29 30 29 30 29 29 30 29 30 29 0 354
+1941 */{ 6 , 1 , 27 , 55888 },/* 30 30 29 30 30 29 30 29 29 30 29 30 29 384
+1942 */{ 0 , 2 , 15 , 46416 },/* 30 29 30 30 29 30 29 30 29 30 29 30 0 355
+1943 */{ 0 , 2 , 5 , 22176 },/* 29 30 29 30 29 30 30 29 30 29 30 29 0 354
+1944 */{ 4 , 1 , 25 , 43736 },/* 30 29 30 29 30 29 30 29 30 30 29 30 30 385
+1945 */{ 0 , 2 , 13 , 9680 },/* 29 29 30 29 29 30 29 30 30 30 29 30 0 354
+1946 */{ 0 , 2 , 2 , 37584 },/* 30 29 29 30 29 29 30 29 30 30 29 30 0 354
+1947 */{ 2 , 1 , 22 , 51544 },/* 30 30 29 29 30 29 29 30 29 30 29 30 30 384
+1948 */{ 0 , 2 , 10 , 43344 },/* 30 29 30 29 30 29 29 30 29 30 29 30 0 354
+1949 */{ 7 , 1 , 29 , 46248 },/* 30 29 30 30 29 30 29 29 30 29 30 29 30 384
+1950 */{ 0 , 2 , 17 , 27808 },/* 29 30 30 29 30 30 29 29 30 29 30 29 0 354
+1951 */{ 0 , 2 , 6 , 46416 },/* 30 29 30 30 29 30 29 30 29 30 29 30 0 355
+1952 */{ 5 , 1 , 27 , 21928 },/* 29 30 29 30 29 30 29 30 30 29 30 29 30 384
+1953 */{ 0 , 2 , 14 , 19872 },/* 29 30 29 29 30 30 29 30 30 29 30 29 0 354
+1954 */{ 0 , 2 , 3 , 42416 },/* 30 29 30 29 29 30 29 30 30 29 30 30 0 355
+1955 */{ 3 , 1 , 24 , 21176 },/* 29 30 29 30 29 29 30 29 30 29 30 30 30 384
+1956 */{ 0 , 2 , 12 , 21168 },/* 29 30 29 30 29 29 30 29 30 29 30 30 0 354
+1957 */{ 8 , 1 , 31 , 43344 },/* 30 29 30 29 30 29 29 30 29 30 29 30 29 383
+1958 */{ 0 , 2 , 18 , 59728 },/* 30 30 30 29 30 29 29 30 29 30 29 30 0 355
+1959 */{ 0 , 2 , 8 , 27296 },/* 29 30 30 29 30 29 30 29 30 29 30 29 0 354
+1960 */{ 6 , 1 , 28 , 44368 },/* 30 29 30 29 30 30 29 30 29 30 29 30 29 384
+1961 */{ 0 , 2 , 15 , 43856 },/* 30 29 30 29 30 29 30 30 29 30 29 30 0 355
+1962 */{ 0 , 2 , 5 , 19296 },/* 29 30 29 29 30 29 30 30 29 30 30 29 0 354
+1963 */{ 4 , 1 , 25 , 42352 },/* 30 29 30 29 29 30 29 30 29 30 30 30 29 384
+1964 */{ 0 , 2 , 13 , 42352 },/* 30 29 30 29 29 30 29 30 29 30 30 30 0 355
+1965 */{ 0 , 2 , 2 , 21088 },/* 29 30 29 30 29 29 30 29 29 30 30 29 0 353
+1966 */{ 3 , 1 , 21 , 59696 },/* 30 30 30 29 30 29 29 30 29 29 30 30 29 384
+1967 */{ 0 , 2 , 9 , 55632 },/* 30 30 29 30 30 29 29 30 29 30 29 30 0 355
+1968 */{ 7 , 1 , 30 , 23208 },/* 29 30 29 30 30 29 30 29 30 29 30 29 30 384
+1969 */{ 0 , 2 , 17 , 22176 },/* 29 30 29 30 29 30 30 29 30 29 30 29 0 354
+1970 */{ 0 , 2 , 6 , 38608 },/* 30 29 29 30 29 30 30 29 30 30 29 30 0 355
+1971 */{ 5 , 1 , 27 , 19176 },/* 29 30 29 29 30 29 30 29 30 30 30 29 30 384
+1972 */{ 0 , 2 , 15 , 19152 },/* 29 30 29 29 30 29 30 29 30 30 29 30 0 354
+1973 */{ 0 , 2 , 3 , 42192 },/* 30 29 30 29 29 30 29 29 30 30 29 30 0 354
+1974 */{ 4 , 1 , 23 , 53864 },/* 30 30 29 30 29 29 30 29 29 30 30 29 30 384
+1975 */{ 0 , 2 , 11 , 53840 },/* 30 30 29 30 29 29 30 29 29 30 29 30 0 354
+1976 */{ 8 , 1 , 31 , 54568 },/* 30 30 29 30 29 30 29 30 29 29 30 29 30 384
+1977 */{ 0 , 2 , 18 , 46400 },/* 30 29 30 30 29 30 29 30 29 30 29 29 0 354
+1978 */{ 0 , 2 , 7 , 46752 },/* 30 29 30 30 29 30 30 29 30 29 30 29 0 355
+1979 */{ 6 , 1 , 28 , 38608 },/* 30 29 29 30 29 30 30 29 30 30 29 30 29 384
+1980 */{ 0 , 2 , 16 , 38320 },/* 30 29 29 30 29 30 29 30 30 29 30 30 0 355
+1981 */{ 0 , 2 , 5 , 18864 },/* 29 30 29 29 30 29 29 30 30 29 30 30 0 354
+1982 */{ 4 , 1 , 25 , 42168 },/* 30 29 30 29 29 30 29 29 30 29 30 30 30 384
+1983 */{ 0 , 2 , 13 , 42160 },/* 30 29 30 29 29 30 29 29 30 29 30 30 0 354
+1984 */{ 10 , 2 , 2 , 45656 },/* 30 29 30 30 29 29 30 29 29 30 29 30 30 384
+1985 */{ 0 , 2 , 20 , 27216 },/* 29 30 30 29 30 29 30 29 29 30 29 30 0 354
+1986 */{ 0 , 2 , 9 , 27968 },/* 29 30 30 29 30 30 29 30 29 30 29 29 0 354
+1987 */{ 6 , 1 , 29 , 44448 },/* 30 29 30 29 30 30 29 30 30 29 30 29 29 384
+1988 */{ 0 , 2 , 17 , 43872 },/* 30 29 30 29 30 29 30 30 29 30 30 29 0 355
+1989 */{ 0 , 2 , 6 , 38256 },/* 30 29 29 30 29 30 29 30 29 30 30 30 0 355
+1990 */{ 5 , 1 , 27 , 18808 },/* 29 30 29 29 30 29 29 30 29 30 30 30 30 384
+1991 */{ 0 , 2 , 15 , 18800 },/* 29 30 29 29 30 29 29 30 29 30 30 30 0 354
+1992 */{ 0 , 2 , 4 , 25776 },/* 29 30 30 29 29 30 29 29 30 29 30 30 0 354
+1993 */{ 3 , 1 , 23 , 27216 },/* 29 30 30 29 30 29 30 29 29 30 29 30 29 383
+1994 */{ 0 , 2 , 10 , 59984 },/* 30 30 30 29 30 29 30 29 29 30 29 30 0 355
+1995 */{ 8 , 1 , 31 , 27432 },/* 29 30 30 29 30 29 30 30 29 29 30 29 30 384
+1996 */{ 0 , 2 , 19 , 23232 },/* 29 30 29 30 30 29 30 29 30 30 29 29 0 354
+1997 */{ 0 , 2 , 7 , 43872 },/* 30 29 30 29 30 29 30 30 29 30 30 29 0 355
+1998 */{ 5 , 1 , 28 , 37736 },/* 30 29 29 30 29 29 30 30 29 30 30 29 30 384
+1999 */{ 0 , 2 , 16 , 37600 },/* 30 29 29 30 29 29 30 29 30 30 30 29 0 354
+2000 */{ 0 , 2 , 5 , 51552 },/* 30 30 29 29 30 29 29 30 29 30 30 29 0 354
+2001 */{ 4 , 1 , 24 , 54440 },/* 30 30 29 30 29 30 29 29 30 29 30 29 30 384
+2002 */{ 0 , 2 , 12 , 54432 },/* 30 30 29 30 29 30 29 29 30 29 30 29 0 354
+2003 */{ 0 , 2 , 1 , 55888 },/* 30 30 29 30 30 29 30 29 29 30 29 30 0 355
+2004 */{ 2 , 1 , 22 , 23208 },/* 29 30 29 30 30 29 30 29 30 29 30 29 30 384
+2005 */{ 0 , 2 , 9 , 22176 },/* 29 30 29 30 29 30 30 29 30 29 30 29 0 354
+2006 */{ 7 , 1 , 29 , 43736 },/* 30 29 30 29 30 29 30 29 30 30 29 30 30 385
+2007 */{ 0 , 2 , 18 , 9680 },/* 29 29 30 29 29 30 29 30 30 30 29 30 0 354
+2008 */{ 0 , 2 , 7 , 37584 },/* 30 29 29 30 29 29 30 29 30 30 29 30 0 354
+2009 */{ 5 , 1 , 26 , 51544 },/* 30 30 29 29 30 29 29 30 29 30 29 30 30 384
+2010 */{ 0 , 2 , 14 , 43344 },/* 30 29 30 29 30 29 29 30 29 30 29 30 0 354
+2011 */{ 0 , 2 , 3 , 46240 },/* 30 29 30 30 29 30 29 29 30 29 30 29 0 354
+2012 */{ 4 , 1 , 23 , 46416 },/* 30 29 30 30 29 30 29 30 29 30 29 30 29 384
+2013 */{ 0 , 2 , 10 , 44368 },/* 30 29 30 29 30 30 29 30 29 30 29 30 0 355
+2014 */{ 9 , 1 , 31 , 21928 },/* 29 30 29 30 29 30 29 30 30 29 30 29 30 384
+2015 */{ 0 , 2 , 19 , 19360 },/* 29 30 29 29 30 29 30 30 30 29 30 29 0 354
+2016 */{ 0 , 2 , 8 , 42416 },/* 30 29 30 29 29 30 29 30 30 29 30 30 0 355
+2017 */{ 6 , 1 , 28 , 21176 },/* 29 30 29 30 29 29 30 29 30 29 30 30 30 384
+2018 */{ 0 , 2 , 16 , 21168 },/* 29 30 29 30 29 29 30 29 30 29 30 30 0 354
+2019 */{ 0 , 2 , 5 , 43312 },/* 30 29 30 29 30 29 29 30 29 29 30 30 0 354
+2020 */{ 4 , 1 , 25 , 29864 },/* 29 30 30 30 29 30 29 29 30 29 30 29 30 384
+2021 */{ 0 , 2 , 12 , 27296 },/* 29 30 30 29 30 29 30 29 30 29 30 29 0 354
+2022 */{ 0 , 2 , 1 , 44368 },/* 30 29 30 29 30 30 29 30 29 30 29 30 0 355
+2023 */{ 2 , 1 , 22 , 19880 },/* 29 30 29 29 30 30 29 30 30 29 30 29 30 384
+2024 */{ 0 , 2 , 10 , 19296 },/* 29 30 29 29 30 29 30 30 29 30 30 29 0 354
+2025 */{ 6 , 1 , 29 , 42352 },/* 30 29 30 29 29 30 29 30 29 30 30 30 29 384
+2026 */{ 0 , 2 , 17 , 42208 },/* 30 29 30 29 29 30 29 29 30 30 30 29 0 354
+2027 */{ 0 , 2 , 6 , 53856 },/* 30 30 29 30 29 29 30 29 29 30 30 29 0 354
+2028 */{ 5 , 1 , 26 , 59696 },/* 30 30 30 29 30 29 29 30 29 29 30 30 29 384
+2029 */{ 0 , 2 , 13 , 54576 },/* 30 30 29 30 29 30 29 30 29 29 30 30 0 355
+2030 */{ 0 , 2 , 3 , 23200 },/* 29 30 29 30 30 29 30 29 30 29 30 29 0 354
+2031 */{ 3 , 1 , 23 , 27472 },/* 29 30 30 29 30 29 30 30 29 30 29 30 29 384
+2032 */{ 0 , 2 , 11 , 38608 },/* 30 29 29 30 29 30 30 29 30 30 29 30 0 355
+2033 */{ 11 , 1 , 31 , 19176 },/* 29 30 29 29 30 29 30 29 30 30 30 29 30 384
+2034 */{ 0 , 2 , 19 , 19152 },/* 29 30 29 29 30 29 30 29 30 30 29 30 0 354
+2035 */{ 0 , 2 , 8 , 42192 },/* 30 29 30 29 29 30 29 29 30 30 29 30 0 354
+2036 */{ 6 , 1 , 28 , 53848 },/* 30 30 29 30 29 29 30 29 29 30 29 30 30 384
+2037 */{ 0 , 2 , 15 , 53840 },/* 30 30 29 30 29 29 30 29 29 30 29 30 0 354
+2038 */{ 0 , 2 , 4 , 54560 },/* 30 30 29 30 29 30 29 30 29 29 30 29 0 354
+2039 */{ 5 , 1 , 24 , 55968 },/* 30 30 29 30 30 29 30 29 30 29 30 29 29 384
+2040 */{ 0 , 2 , 12 , 46496 },/* 30 29 30 30 29 30 29 30 30 29 30 29 0 355
+2041 */{ 0 , 2 , 1 , 22224 },/* 29 30 29 30 29 30 30 29 30 30 29 30 0 355
+2042 */{ 2 , 1 , 22 , 19160 },/* 29 30 29 29 30 29 30 29 30 30 29 30 30 384
+2043 */{ 0 , 2 , 10 , 18864 },/* 29 30 29 29 30 29 29 30 30 29 30 30 0 354
+2044 */{ 7 , 1 , 30 , 42168 },/* 30 29 30 29 29 30 29 29 30 29 30 30 30 384
+2045 */{ 0 , 2 , 17 , 42160 },/* 30 29 30 29 29 30 29 29 30 29 30 30 0 354
+2046 */{ 0 , 2 , 6 , 43600 },/* 30 29 30 29 30 29 30 29 29 30 29 30 0 354
+2047 */{ 5 , 1 , 26 , 46376 },/* 30 29 30 30 29 30 29 30 29 29 30 29 30 384
+2048 */{ 0 , 2 , 14 , 27936 },/* 29 30 30 29 30 30 29 30 29 29 30 29 0 354
+2049 */{ 0 , 2 , 2 , 44448 },/* 30 29 30 29 30 30 29 30 30 29 30 29 0 355
+2050 */{ 3 , 1 , 23 , 21936 },/* 29 30 29 30 29 30 29 30 30 29 30 30 29 384
+2051 */{ 0 , 2 , 11 , 37744 },/* 30 29 29 30 29 29 30 30 29 30 30 30 0 355
+2052 */{ 8 , 2 , 1 , 18808 },/* 29 30 29 29 30 29 29 30 29 30 30 30 30 384
+2053 */{ 0 , 2 , 19 , 18800 },/* 29 30 29 29 30 29 29 30 29 30 30 30 0 354
+2054 */{ 0 , 2 , 8 , 25776 },/* 29 30 30 29 29 30 29 29 30 29 30 30 0 354
+2055 */{ 6 , 1 , 28 , 27216 },/* 29 30 30 29 30 29 30 29 29 30 29 30 29 383
+2056 */{ 0 , 2 , 15 , 59984 },/* 30 30 30 29 30 29 30 29 29 30 29 30 0 355
+2057 */{ 0 , 2 , 4 , 27424 },/* 29 30 30 29 30 29 30 30 29 29 30 29 0 354
+2058 */{ 4 , 1 , 24 , 43872 },/* 30 29 30 29 30 29 30 30 29 30 30 29 29 384
+2059 */{ 0 , 2 , 12 , 43744 },/* 30 29 30 29 30 29 30 29 30 30 30 29 0 355
+2060 */{ 0 , 2 , 2 , 37600 },/* 30 29 29 30 29 29 30 29 30 30 30 29 0 354
+2061 */{ 3 , 1 , 21 , 51568 },/* 30 30 29 29 30 29 29 30 29 30 30 30 29 384
+2062 */{ 0 , 2 , 9 , 51552 },/* 30 30 29 29 30 29 29 30 29 30 30 29 0 354
+2063 */{ 7 , 1 , 29 , 54440 },/* 30 30 29 30 29 30 29 29 30 29 30 29 30 384
+2064 */{ 0 , 2 , 17 , 54432 },/* 30 30 29 30 29 30 29 29 30 29 30 29 0 354
+2065 */{ 0 , 2 , 5 , 55888 },/* 30 30 29 30 30 29 30 29 29 30 29 30 0 355
+2066 */{ 5 , 1 , 26 , 23208 },/* 29 30 29 30 30 29 30 29 30 29 30 29 30 384
+2067 */{ 0 , 2 , 14 , 22176 },/* 29 30 29 30 29 30 30 29 30 29 30 29 0 354
+2068 */{ 0 , 2 , 3 , 42704 },/* 30 29 30 29 29 30 30 29 30 30 29 30 0 355
+2069 */{ 4 , 1 , 23 , 21224 },/* 29 30 29 30 29 29 30 29 30 30 30 29 30 384
+2070 */{ 0 , 2 , 11 , 21200 },/* 29 30 29 30 29 29 30 29 30 30 29 30 0 354
+2071 */{ 8 , 1 , 31 , 43352 },/* 30 29 30 29 30 29 29 30 29 30 29 30 30 384
+2072 */{ 0 , 2 , 19 , 43344 },/* 30 29 30 29 30 29 29 30 29 30 29 30 0 354
+2073 */{ 0 , 2 , 7 , 46240 },/* 30 29 30 30 29 30 29 29 30 29 30 29 0 354
+2074 */{ 6 , 1 , 27 , 46416 },/* 30 29 30 30 29 30 29 30 29 30 29 30 29 384
+2075 */{ 0 , 2 , 15 , 44368 },/* 30 29 30 29 30 30 29 30 29 30 29 30 0 355
+2076 */{ 0 , 2 , 5 , 21920 },/* 29 30 29 30 29 30 29 30 30 29 30 29 0 354
+2077 */{ 4 , 1 , 24 , 42448 },/* 30 29 30 29 29 30 29 30 30 30 29 30 29 384
+2078 */{ 0 , 2 , 12 , 42416 },/* 30 29 30 29 29 30 29 30 30 29 30 30 0 355
+2079 */{ 0 , 2 , 2 , 21168 },/* 29 30 29 30 29 29 30 29 30 29 30 30 0 354
+2080 */{ 3 , 1 , 22 , 43320 },/* 30 29 30 29 30 29 29 30 29 29 30 30 30 384
+2081 */{ 0 , 2 , 9 , 26928 },/* 29 30 30 29 30 29 29 30 29 29 30 30 0 354
+2082 */{ 7 , 1 , 29 , 29336 },/* 29 30 30 30 29 29 30 29 30 29 29 30 30 384
+2083 */{ 0 , 2 , 17 , 27296 },/* 29 30 30 29 30 29 30 29 30 29 30 29 0 354
+2084 */{ 0 , 2 , 6 , 44368 },/* 30 29 30 29 30 30 29 30 29 30 29 30 0 355
+2085 */{ 5 , 1 , 26 , 19880 },/* 29 30 29 29 30 30 29 30 30 29 30 29 30 384
+2086 */{ 0 , 2 , 14 , 19296 },/* 29 30 29 29 30 29 30 30 29 30 30 29 0 354
+2087 */{ 0 , 2 , 3 , 42352 },/* 30 29 30 29 29 30 29 30 29 30 30 30 0 355
+2088 */{ 4 , 1 , 24 , 21104 },/* 29 30 29 30 29 29 30 29 29 30 30 30 29 383
+2089 */{ 0 , 2 , 10 , 53856 },/* 30 30 29 30 29 29 30 29 29 30 30 29 0 354
+2090 */{ 8 , 1 , 30 , 59696 },/* 30 30 30 29 30 29 29 30 29 29 30 30 29 384
+2091 */{ 0 , 2 , 18 , 54560 },/* 30 30 29 30 29 30 29 30 29 29 30 29 0 354
+2092 */{ 0 , 2 , 7 , 55968 },/* 30 30 29 30 30 29 30 29 30 29 30 29 0 355
+2093 */{ 6 , 1 , 27 , 27472 },/* 29 30 30 29 30 29 30 30 29 30 29 30 29 384
+2094 */{ 0 , 2 , 15 , 22224 },/* 29 30 29 30 29 30 30 29 30 30 29 30 0 355
+2095 */{ 0 , 2 , 5 , 19168 },/* 29 30 29 29 30 29 30 29 30 30 30 29 0 354
+2096 */{ 4 , 1 , 25 , 42216 },/* 30 29 30 29 29 30 29 29 30 30 30 29 30 384
+2097 */{ 0 , 2 , 12 , 42192 },/* 30 29 30 29 29 30 29 29 30 30 29 30 0 354
+2098 */{ 0 , 2 , 1 , 53584 },/* 30 30 29 30 29 29 29 30 29 30 29 30 0 354
+2099 */{ 2 , 1 , 21 , 55592 },/* 30 30 29 30 30 29 29 30 29 29 30 29 30 384
+2100 */{ 0 , 2 , 9 , 54560 },/* 30 30 29 30 29 30 29 30 29 29 30 29 0 354
+ */};
+
+
+ internal override int MinCalendarYear
+ {
+ get
+ {
+ return (MIN_LUNISOLAR_YEAR);
+ }
+ }
+
+ internal override int MaxCalendarYear
+ {
+ get
+ {
+ return (MAX_LUNISOLAR_YEAR);
+ }
+ }
+
+ internal override DateTime MinDate
+ {
+ get
+ {
+ return (minDate);
+ }
+ }
+
+ internal override DateTime MaxDate
+ {
+ get
+ {
+ return (maxDate);
+ }
+ }
+
+ internal override EraInfo[] CalEraInfo
+ {
+ get
+ {
+ return (null);
+ }
+ }
+
+ internal override int GetYearInfo(int LunarYear, int Index)
+ {
+ if ((LunarYear < MIN_LUNISOLAR_YEAR) || (LunarYear > MAX_LUNISOLAR_YEAR))
+ {
+ throw new ArgumentOutOfRangeException(
+ "year",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Range, MIN_LUNISOLAR_YEAR, MAX_LUNISOLAR_YEAR));
+ }
+ Contract.EndContractBlock();
+
+ return s_yinfo[LunarYear - MIN_LUNISOLAR_YEAR, Index];
+ }
+
+ internal override int GetYear(int year, DateTime time)
+ {
+ return year;
+ }
+
+ internal override int GetGregorianYear(int year, int era)
+ {
+ if (era != CurrentEra && era != ChineseEra)
+ {
+ throw new ArgumentOutOfRangeException("era", SR.ArgumentOutOfRange_InvalidEraValue);
+ }
+
+ if (year < MIN_LUNISOLAR_YEAR || year > MAX_LUNISOLAR_YEAR)
+ {
+ throw new ArgumentOutOfRangeException(
+ "year",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ SR.ArgumentOutOfRange_Range, MIN_LUNISOLAR_YEAR, MAX_LUNISOLAR_YEAR));
+ }
+ Contract.EndContractBlock();
+
+ return year;
+ }
+
+ public ChineseLunisolarCalendar()
+ {
+ }
+
+ [System.Runtime.InteropServices.ComVisible(false)]
+ public override int GetEra(DateTime time)
+ {
+ CheckTicksRange(time.Ticks);
+ return (ChineseEra);
+ }
+
+ internal override CalendarId ID
+ {
+ get
+ {
+ return (CalendarId.CHINESELUNISOLAR);
+ }
+ }
+
+ internal override CalendarId BaseCalendarID
+ {
+ get
+ {
+ //Use CAL_GREGORIAN just to get CurrentEraValue as 1 since we do not have data under the ID CAL_ChineseLunisolar yet
+ return (CalendarId.GREGORIAN);
+ }
+ }
+
+
+ [System.Runtime.InteropServices.ComVisible(false)]
+ public override int[] Eras
+ {
+ get
+ {
+ return (new int[] { ChineseEra });
+ }
+ }
+ }
+}
diff --git a/src/mscorlib/corefx/System/Globalization/CompareInfo.Unix.cs b/src/mscorlib/corefx/System/Globalization/CompareInfo.Unix.cs
new file mode 100644
index 0000000000..2aaf5a22fa
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/CompareInfo.Unix.cs
@@ -0,0 +1,315 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics.Contracts;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Security;
+
+namespace System.Globalization
+{
+ public partial class CompareInfo
+ {
+ [NonSerialized]
+ private Interop.GlobalizationInterop.SafeSortHandle _sortHandle;
+
+ [NonSerialized]
+ private bool _isAsciiEqualityOrdinal;
+
+ [SecuritySafeCritical]
+ internal CompareInfo(CultureInfo culture)
+ {
+ _name = culture.m_name;
+ InitSort(culture);
+ }
+
+ private void InitSort(CultureInfo culture)
+ {
+ _sortName = culture.SortName;
+ _sortHandle = Interop.GlobalizationInterop.GetSortHandle(GetNullTerminatedUtf8String(_sortName));
+ _isAsciiEqualityOrdinal = (_sortName == "en-US" || _sortName == "");
+ }
+
+ internal static unsafe int IndexOfOrdinal(string source, string value, int startIndex, int count, bool ignoreCase)
+ {
+ Contract.Assert(source != null);
+ Contract.Assert(value != null);
+
+ if (value.Length == 0)
+ {
+ return startIndex;
+ }
+
+ if (count < value.Length)
+ {
+ return -1;
+ }
+
+ if (ignoreCase)
+ {
+ fixed (char* pSource = source)
+ {
+ int index = Interop.GlobalizationInterop.IndexOfOrdinalIgnoreCase(value, value.Length, pSource + startIndex, count, findLast: false);
+ return index != -1 ?
+ startIndex + index :
+ -1;
+ }
+ }
+
+ int endIndex = startIndex + (count - value.Length);
+ for (int i = startIndex; i <= endIndex; i++)
+ {
+ int valueIndex, sourceIndex;
+
+ for (valueIndex = 0, sourceIndex = i;
+ valueIndex < value.Length && source[sourceIndex] == value[valueIndex];
+ valueIndex++, sourceIndex++) ;
+
+ if (valueIndex == value.Length)
+ {
+ return i;
+ }
+ }
+
+ return -1;
+ }
+
+ internal static unsafe int LastIndexOfOrdinal(string source, string value, int startIndex, int count, bool ignoreCase)
+ {
+ Contract.Assert(source != null);
+ Contract.Assert(value != null);
+
+ if (value.Length == 0)
+ {
+ return startIndex;
+ }
+
+ if (count < value.Length)
+ {
+ return -1;
+ }
+
+ // startIndex is the index into source where we start search backwards from.
+ // leftStartIndex is the index into source of the start of the string that is
+ // count characters away from startIndex.
+ int leftStartIndex = startIndex - count + 1;
+
+ if (ignoreCase)
+ {
+ fixed (char* pSource = source)
+ {
+ int lastIndex = Interop.GlobalizationInterop.IndexOfOrdinalIgnoreCase(value, value.Length, pSource + leftStartIndex, count, findLast: true);
+ return lastIndex != -1 ?
+ leftStartIndex + lastIndex :
+ -1;
+ }
+ }
+
+ for (int i = startIndex - value.Length + 1; i >= leftStartIndex; i--)
+ {
+ int valueIndex, sourceIndex;
+
+ for (valueIndex = 0, sourceIndex = i;
+ valueIndex < value.Length && source[sourceIndex] == value[valueIndex];
+ valueIndex++, sourceIndex++) ;
+
+ if (valueIndex == value.Length) {
+ return i;
+ }
+ }
+
+ return -1;
+ }
+
+ private int GetHashCodeOfStringCore(string source, CompareOptions options)
+ {
+ Contract.Assert(source != null);
+ Contract.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0);
+
+ return GetHashCodeOfStringCore(source, options, forceRandomizedHashing: false, additionalEntropy: 0);
+ }
+
+ private static unsafe int CompareStringOrdinalIgnoreCase(char* string1, int count1, char* string2, int count2)
+ {
+ return Interop.GlobalizationInterop.CompareStringOrdinalIgnoreCase(string1, count1, string2, count2);
+ }
+
+ private unsafe int CompareString(string string1, int offset1, int length1, string string2, int offset2, int length2, CompareOptions options)
+ {
+ Contract.Assert(string1 != null);
+ Contract.Assert(string2 != null);
+ Contract.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0);
+
+ fixed (char* pString1 = string1)
+ {
+ fixed (char* pString2 = string2)
+ {
+ return Interop.GlobalizationInterop.CompareString(_sortHandle, pString1 + offset1, length1, pString2 + offset2, length2, options);
+ }
+ }
+ }
+
+ private unsafe int IndexOfCore(string source, string target, int startIndex, int count, CompareOptions options)
+ {
+ Contract.Assert(!string.IsNullOrEmpty(source));
+ Contract.Assert(target != null);
+ Contract.Assert((options & CompareOptions.OrdinalIgnoreCase) == 0);
+
+ if (target.Length == 0)
+ {
+ return startIndex;
+ }
+
+ if (options == CompareOptions.Ordinal)
+ {
+ return IndexOfOrdinal(source, target, startIndex, count, ignoreCase: false);
+ }
+
+ if (_isAsciiEqualityOrdinal && CanUseAsciiOrdinalForOptions(options) && source.IsFastSort() && target.IsFastSort())
+ {
+ return IndexOf(source, target, startIndex, count, GetOrdinalCompareOptions(options));
+ }
+
+ fixed (char* pSource = source)
+ {
+ int index = Interop.GlobalizationInterop.IndexOf(_sortHandle, target, target.Length, pSource + startIndex, count, options);
+
+ return index != -1 ? index + startIndex : -1;
+ }
+ }
+
+ private unsafe int LastIndexOfCore(string source, string target, int startIndex, int count, CompareOptions options)
+ {
+ Contract.Assert(!string.IsNullOrEmpty(source));
+ Contract.Assert(target != null);
+ Contract.Assert((options & CompareOptions.OrdinalIgnoreCase) == 0);
+
+ if (target.Length == 0)
+ {
+ return startIndex;
+ }
+
+ if (options == CompareOptions.Ordinal)
+ {
+ return LastIndexOfOrdinal(source, target, startIndex, count, ignoreCase: false);
+ }
+
+ if (_isAsciiEqualityOrdinal && CanUseAsciiOrdinalForOptions(options) && source.IsFastSort() && target.IsFastSort())
+ {
+ return LastIndexOf(source, target, startIndex, count, GetOrdinalCompareOptions(options));
+ }
+
+ // startIndex is the index into source where we start search backwards from. leftStartIndex is the index into source
+ // of the start of the string that is count characters away from startIndex.
+ int leftStartIndex = (startIndex - count + 1);
+
+ fixed (char* pSource = source)
+ {
+ int lastIndex = Interop.GlobalizationInterop.LastIndexOf(_sortHandle, target, target.Length, pSource + (startIndex - count + 1), count, options);
+
+ return lastIndex != -1 ? lastIndex + leftStartIndex : -1;
+ }
+ }
+
+ [SecuritySafeCritical]
+ private bool StartsWith(string source, string prefix, CompareOptions options)
+ {
+ Contract.Assert(!string.IsNullOrEmpty(source));
+ Contract.Assert(!string.IsNullOrEmpty(prefix));
+ Contract.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0);
+
+ if (_isAsciiEqualityOrdinal && CanUseAsciiOrdinalForOptions(options) && source.IsFastSort() && prefix.IsFastSort())
+ {
+ return IsPrefix(source, prefix, GetOrdinalCompareOptions(options));
+ }
+
+ return Interop.GlobalizationInterop.StartsWith(_sortHandle, prefix, prefix.Length, source, source.Length, options);
+ }
+
+ [SecuritySafeCritical]
+ private bool EndsWith(string source, string suffix, CompareOptions options)
+ {
+ Contract.Assert(!string.IsNullOrEmpty(source));
+ Contract.Assert(!string.IsNullOrEmpty(suffix));
+ Contract.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0);
+
+ if (_isAsciiEqualityOrdinal && CanUseAsciiOrdinalForOptions(options) && source.IsFastSort() && suffix.IsFastSort())
+ {
+ return IsSuffix(source, suffix, GetOrdinalCompareOptions(options));
+ }
+
+ return Interop.GlobalizationInterop.EndsWith(_sortHandle, suffix, suffix.Length, source, source.Length, options);
+ }
+
+ // -----------------------------
+ // ---- PAL layer ends here ----
+ // -----------------------------
+
+ [SecuritySafeCritical]
+ internal unsafe int GetHashCodeOfStringCore(string source, CompareOptions options, bool forceRandomizedHashing, long additionalEntropy)
+ {
+ Contract.Assert(source != null);
+ Contract.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0);
+
+ if (source.Length == 0)
+ {
+ return 0;
+ }
+
+ int sortKeyLength = Interop.GlobalizationInterop.GetSortKey(_sortHandle, source, source.Length, null, 0, options);
+
+ // As an optimization, for small sort keys we allocate the buffer on the stack.
+ if (sortKeyLength <= 256)
+ {
+ byte* pSortKey = stackalloc byte[sortKeyLength];
+ Interop.GlobalizationInterop.GetSortKey(_sortHandle, source, source.Length, pSortKey, sortKeyLength, options);
+ return InternalHashSortKey(pSortKey, sortKeyLength, false, additionalEntropy);
+ }
+
+ byte[] sortKey = new byte[sortKeyLength];
+
+ fixed(byte* pSortKey = sortKey)
+ {
+ Interop.GlobalizationInterop.GetSortKey(_sortHandle, source, source.Length, pSortKey, sortKeyLength, options);
+ return InternalHashSortKey(pSortKey, sortKeyLength, false, additionalEntropy);
+ }
+ }
+
+ [DllImport(JitHelpers.QCall)]
+ [SuppressUnmanagedCodeSecurity]
+ private static unsafe extern int InternalHashSortKey(byte* sortKey, int sortKeyLength, [MarshalAs(UnmanagedType.Bool)] bool forceRandomizedHashing, long additionalEntropy);
+
+ private static CompareOptions GetOrdinalCompareOptions(CompareOptions options)
+ {
+ if ((options & CompareOptions.IgnoreCase) == CompareOptions.IgnoreCase)
+ {
+ return CompareOptions.OrdinalIgnoreCase;
+ }
+ else
+ {
+ return CompareOptions.Ordinal;
+ }
+ }
+
+ private static bool CanUseAsciiOrdinalForOptions(CompareOptions options)
+ {
+ // Unlike the other Ignore options, IgnoreSymbols impacts ASCII characters (e.g. ').
+ return (options & CompareOptions.IgnoreSymbols) == 0;
+ }
+
+ private static byte[] GetNullTerminatedUtf8String(string s)
+ {
+ int byteLen = System.Text.Encoding.UTF8.GetByteCount(s);
+
+ // Allocate an extra byte (which defaults to 0) as the null terminator.
+ byte[] buffer = new byte[byteLen + 1];
+
+ int bytesWritten = System.Text.Encoding.UTF8.GetBytes(s, 0, s.Length, buffer, 0);
+
+ Contract.Assert(bytesWritten == byteLen);
+
+ return buffer;
+ }
+ }
+}
diff --git a/src/mscorlib/corefx/System/Globalization/CompareInfo.Windows.cs b/src/mscorlib/corefx/System/Globalization/CompareInfo.Windows.cs
new file mode 100644
index 0000000000..744a48b107
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/CompareInfo.Windows.cs
@@ -0,0 +1,395 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics.Contracts;
+
+namespace System.Globalization
+{
+ public partial class CompareInfo
+ {
+ internal unsafe CompareInfo(CultureInfo culture)
+ {
+ _name = culture._name;
+ InitSort(culture);
+ }
+
+ private void InitSort(CultureInfo culture)
+ {
+ _sortName = culture.SortName;
+
+ const uint LCMAP_SORTHANDLE = 0x20000000;
+
+ _name = culture._name;
+ _sortName = culture.SortName;
+
+ IntPtr handle;
+ int ret = Interop.mincore.LCMapStringEx(_sortName, LCMAP_SORTHANDLE, null, 0, &handle, IntPtr.Size, null, null, IntPtr.Zero);
+ _sortHandle = ret > 0 ? handle : IntPtr.Zero;
+ }
+
+ private static unsafe int FindStringOrdinal(
+ uint dwFindStringOrdinalFlags,
+ string stringSource,
+ int offset,
+ int cchSource,
+ string value,
+ int cchValue,
+ bool bIgnoreCase)
+ {
+ fixed (char* pSource = stringSource)
+ fixed (char* pValue = value)
+ {
+ int ret = Interop.mincore.FindStringOrdinal(
+ dwFindStringOrdinalFlags,
+ pSource + offset,
+ cchSource,
+ pValue,
+ cchValue,
+ bIgnoreCase ? 1 : 0);
+ return ret < 0 ? ret : ret + offset;
+ }
+ }
+
+ internal static int IndexOfOrdinal(string source, string value, int startIndex, int count, bool ignoreCase)
+ {
+ Contract.Assert(source != null);
+ Contract.Assert(value != null);
+
+ return FindStringOrdinal(FIND_FROMSTART, source, startIndex, count, value, value.Length, ignoreCase);
+ }
+
+ internal static int LastIndexOfOrdinal(string source, string value, int startIndex, int count, bool ignoreCase)
+ {
+ Contract.Assert(source != null);
+ Contract.Assert(value != null);
+
+ return FindStringOrdinal(FIND_FROMEND, source, startIndex - count + 1, count, value, value.Length, ignoreCase);
+ }
+
+ private unsafe int GetHashCodeOfStringCore(string source, CompareOptions options)
+ {
+ Contract.Assert(source != null);
+ Contract.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0);
+
+ if (source.Length == 0)
+ {
+ return 0;
+ }
+
+ int tmpHash = 0;
+
+ fixed (char* pSource = source)
+ {
+ if (Interop.mincore.LCMapStringEx(_sortHandle != IntPtr.Zero ? null : _sortName,
+ LCMAP_HASH | (uint)GetNativeCompareFlags(options),
+ pSource, source.Length,
+ &tmpHash, sizeof(int),
+ null, null, _sortHandle) == 0)
+ {
+ Environment.FailFast("LCMapStringEx failed!");
+ }
+ }
+
+ return tmpHash;
+ }
+
+ private static unsafe int CompareStringOrdinalIgnoreCase(char* string1, int count1, char* string2, int count2)
+ {
+ // Use the OS to compare and then convert the result to expected value by subtracting 2
+ return Interop.mincore.CompareStringOrdinal(string1, count1, string2, count2, true) - 2;
+ }
+
+ private unsafe int CompareString(string string1, int offset1, int length1, string string2, int offset2, int length2, CompareOptions options)
+ {
+ Contract.Assert(string1 != null);
+ Contract.Assert(string2 != null);
+ Contract.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0);
+
+ string localeName = _sortHandle != IntPtr.Zero ? null : _sortName;
+
+ fixed (char* pLocaleName = localeName)
+ fixed (char* pString1 = string1)
+ fixed (char* pString2 = string2)
+ {
+ int result = Interop.mincore.CompareStringEx(
+ pLocaleName,
+ (uint)GetNativeCompareFlags(options),
+ pString1 + offset1,
+ length1,
+ pString2 + offset2,
+ length2,
+ null,
+ null,
+ _sortHandle);
+
+ if (result == 0)
+ {
+ Environment.FailFast("CompareStringEx failed");
+ }
+
+ // Map CompareStringEx return value to -1, 0, 1.
+ return result - 2;
+ }
+ }
+
+ private unsafe int FindString(
+ uint dwFindNLSStringFlags,
+ string lpStringSource,
+ int startSource,
+ int cchSource,
+ string lpStringValue,
+ int startValue,
+ int cchValue)
+ {
+ string localeName = _sortHandle != IntPtr.Zero ? null : _sortName;
+
+ fixed (char* pLocaleName = localeName)
+ fixed (char* pSource = lpStringSource)
+ fixed (char* pValue = lpStringValue)
+ {
+ char* pS = pSource + startSource;
+ char* pV = pValue + startValue;
+
+ return Interop.mincore.FindNLSStringEx(
+ pLocaleName,
+ dwFindNLSStringFlags,
+ pS,
+ cchSource,
+ pV,
+ cchValue,
+ null,
+ null,
+ null,
+ _sortHandle);
+ }
+ }
+
+ private int IndexOfCore(string source, string target, int startIndex, int count, CompareOptions options)
+ {
+ Contract.Assert(!string.IsNullOrEmpty(source));
+ Contract.Assert(target != null);
+ Contract.Assert((options & CompareOptions.OrdinalIgnoreCase) == 0);
+
+ // TODO: Consider moving this up to the relevent APIs we need to ensure this behavior for
+ // and add a precondition that target is not empty.
+ if (target.Length == 0)
+ return startIndex; // keep Whidbey compatibility
+
+ if ((options & CompareOptions.Ordinal) != 0)
+ {
+ return FastIndexOfString(source, target, startIndex, count, target.Length, findLastIndex: false);
+ }
+ else
+ {
+ int retValue = FindString(FIND_FROMSTART | (uint)GetNativeCompareFlags(options),
+ source,
+ startIndex,
+ count,
+ target,
+ 0,
+ target.Length);
+ if (retValue >= 0)
+ {
+ return retValue + startIndex;
+ }
+ }
+
+ return -1;
+ }
+
+ private int LastIndexOfCore(string source, string target, int startIndex, int count, CompareOptions options)
+ {
+ Contract.Assert(!string.IsNullOrEmpty(source));
+ Contract.Assert(target != null);
+ Contract.Assert((options & CompareOptions.OrdinalIgnoreCase) == 0);
+
+ // TODO: Consider moving this up to the relevent APIs we need to ensure this behavior for
+ // and add a precondition that target is not empty.
+ if (target.Length == 0)
+ return startIndex; // keep Whidbey compatibility
+
+ if ((options & CompareOptions.Ordinal) != 0)
+ {
+ return FastIndexOfString(source, target, startIndex, count, target.Length, findLastIndex: true);
+ }
+ else
+ {
+ int retValue = FindString(FIND_FROMEND | (uint)GetNativeCompareFlags(options),
+ source,
+ startIndex - count + 1,
+ count,
+ target,
+ 0,
+ target.Length);
+
+ if (retValue >= 0)
+ {
+ return retValue + startIndex - (count - 1);
+ }
+ }
+
+ return -1;
+ }
+
+ private bool StartsWith(string source, string prefix, CompareOptions options)
+ {
+ Contract.Assert(!string.IsNullOrEmpty(source));
+ Contract.Assert(!string.IsNullOrEmpty(prefix));
+ Contract.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0);
+
+ return FindString(FIND_STARTSWITH | (uint)GetNativeCompareFlags(options),
+ source,
+ 0,
+ source.Length,
+ prefix,
+ 0,
+ prefix.Length) >= 0;
+ }
+
+ private bool EndsWith(string source, string suffix, CompareOptions options)
+ {
+ Contract.Assert(!string.IsNullOrEmpty(source));
+ Contract.Assert(!string.IsNullOrEmpty(suffix));
+ Contract.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0);
+
+ return FindString(FIND_ENDSWITH | (uint)GetNativeCompareFlags(options),
+ source,
+ 0,
+ source.Length,
+ suffix,
+ 0,
+ suffix.Length) >= 0;
+ }
+
+ // PAL ends here
+ [NonSerialized]
+ private readonly IntPtr _sortHandle;
+
+ private const uint LCMAP_HASH = 0x00040000;
+
+ private const int FIND_STARTSWITH = 0x00100000;
+ private const int FIND_ENDSWITH = 0x00200000;
+ private const int FIND_FROMSTART = 0x00400000;
+ private const int FIND_FROMEND = 0x00800000;
+
+ // TODO: Instead of this method could we just have upstack code call IndexOfOrdinal with ignoreCase = false?
+ private static unsafe int FastIndexOfString(string source, string target, int startIndex, int sourceCount, int targetCount, bool findLastIndex)
+ {
+ int retValue = -1;
+
+ int sourceStartIndex = findLastIndex ? startIndex - sourceCount + 1 : startIndex;
+
+#if !TEST_CODEGEN_OPTIMIZATION
+ fixed (char* pSource = source, spTarget = target)
+ {
+ char* spSubSource = pSource + sourceStartIndex;
+#else
+ String.StringPointer spSubSource = source.GetStringPointer(sourceStartIndex);
+ String.StringPointer spTarget = target.GetStringPointer();
+#endif
+ if (findLastIndex)
+ {
+ int startPattern = (sourceCount - 1) - targetCount + 1;
+ if (startPattern < 0)
+ return -1;
+
+ char patternChar0 = spTarget[0];
+ for (int ctrSrc = startPattern; ctrSrc >= 0; ctrSrc--)
+ {
+ if (spSubSource[ctrSrc] != patternChar0)
+ continue;
+
+ int ctrPat;
+ for (ctrPat = 1; ctrPat < targetCount; ctrPat++)
+ {
+ if (spSubSource[ctrSrc + ctrPat] != spTarget[ctrPat])
+ break;
+ }
+ if (ctrPat == targetCount)
+ {
+ retValue = ctrSrc;
+ break;
+ }
+ }
+
+ if (retValue >= 0)
+ {
+ retValue += startIndex - sourceCount + 1;
+ }
+ }
+ else
+ {
+ int endPattern = (sourceCount - 1) - targetCount + 1;
+ if (endPattern < 0)
+ return -1;
+
+ char patternChar0 = spTarget[0];
+ for (int ctrSrc = 0; ctrSrc <= endPattern; ctrSrc++)
+ {
+ if (spSubSource[ctrSrc] != patternChar0)
+ continue;
+ int ctrPat;
+ for (ctrPat = 1; ctrPat < targetCount; ctrPat++)
+ {
+ if (spSubSource[ctrSrc + ctrPat] != spTarget[ctrPat])
+ break;
+ }
+ if (ctrPat == targetCount)
+ {
+ retValue = ctrSrc;
+ break;
+ }
+ }
+
+ if (retValue >= 0)
+ {
+ retValue += startIndex;
+ }
+ }
+#if !TEST_CODEGEN_OPTIMIZATION
+ }
+
+ return retValue;
+#endif // TEST_CODEGEN_OPTIMIZATION
+ }
+
+ private const int COMPARE_OPTIONS_ORDINAL = 0x40000000; // Ordinal
+ private const int NORM_IGNORECASE = 0x00000001; // Ignores case. (use LINGUISTIC_IGNORECASE instead)
+ private const int NORM_IGNOREKANATYPE = 0x00010000; // Does not differentiate between Hiragana and Katakana characters. Corresponding Hiragana and Katakana will compare as equal.
+ private const int NORM_IGNORENONSPACE = 0x00000002; // Ignores nonspacing. This flag also removes Japanese accent characters. (use LINGUISTIC_IGNOREDIACRITIC instead)
+ private const int NORM_IGNORESYMBOLS = 0x00000004; // Ignores symbols.
+ private const int NORM_IGNOREWIDTH = 0x00020000; // Does not differentiate between a single-byte character and the same character as a double-byte character.
+ private const int NORM_LINGUISTIC_CASING = 0x08000000; // use linguistic rules for casing
+ private const int SORT_STRINGSORT = 0x00001000; // Treats punctuation the same as symbols.
+
+ private static int GetNativeCompareFlags(CompareOptions options)
+ {
+ // Use "linguistic casing" by default (load the culture's casing exception tables)
+ int nativeCompareFlags = NORM_LINGUISTIC_CASING;
+
+ if ((options & CompareOptions.IgnoreCase) != 0) { nativeCompareFlags |= NORM_IGNORECASE; }
+ if ((options & CompareOptions.IgnoreKanaType) != 0) { nativeCompareFlags |= NORM_IGNOREKANATYPE; }
+ if ((options & CompareOptions.IgnoreNonSpace) != 0) { nativeCompareFlags |= NORM_IGNORENONSPACE; }
+ if ((options & CompareOptions.IgnoreSymbols) != 0) { nativeCompareFlags |= NORM_IGNORESYMBOLS; }
+ if ((options & CompareOptions.IgnoreWidth) != 0) { nativeCompareFlags |= NORM_IGNOREWIDTH; }
+ if ((options & CompareOptions.StringSort) != 0) { nativeCompareFlags |= SORT_STRINGSORT; }
+
+ // TODO: Can we try for GetNativeCompareFlags to never
+ // take Ordinal or OrdinalIgnoreCase. This value is not part of Win32, we just handle it special
+ // in some places.
+ // Suffix & Prefix shouldn't use this, make sure to turn off the NORM_LINGUISTIC_CASING flag
+ if (options == CompareOptions.Ordinal) { nativeCompareFlags = COMPARE_OPTIONS_ORDINAL; }
+
+ Contract.Assert(((options & ~(CompareOptions.IgnoreCase |
+ CompareOptions.IgnoreKanaType |
+ CompareOptions.IgnoreNonSpace |
+ CompareOptions.IgnoreSymbols |
+ CompareOptions.IgnoreWidth |
+ CompareOptions.StringSort)) == 0) ||
+ (options == CompareOptions.Ordinal), "[CompareInfo.GetNativeCompareFlags]Expected all flags to be handled");
+
+ return nativeCompareFlags;
+ }
+ }
+}
diff --git a/src/mscorlib/corefx/System/Globalization/CompareInfo.cs b/src/mscorlib/corefx/System/Globalization/CompareInfo.cs
new file mode 100644
index 0000000000..77778af23c
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/CompareInfo.cs
@@ -0,0 +1,925 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+////////////////////////////////////////////////////////////////////////////
+//
+//
+//
+// Purpose: This class implements a set of methods for comparing
+// strings.
+//
+//
+////////////////////////////////////////////////////////////////////////////
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Diagnostics.Contracts;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.Serialization;
+using System.Threading;
+
+namespace System.Globalization
+{
+ [Flags]
+ [Serializable]
+ [System.Runtime.InteropServices.ComVisible(true)]
+ public enum CompareOptions
+ {
+ None = 0x00000000,
+ IgnoreCase = 0x00000001,
+ IgnoreNonSpace = 0x00000002,
+ IgnoreSymbols = 0x00000004,
+ IgnoreKanaType = 0x00000008, // ignore kanatype
+ IgnoreWidth = 0x00000010, // ignore width
+ OrdinalIgnoreCase = 0x10000000, // This flag can not be used with other flags.
+ StringSort = 0x20000000, // use string sort method
+ Ordinal = 0x40000000, // This flag can not be used with other flags.
+ }
+
+ [Serializable]
+ [System.Runtime.InteropServices.ComVisible(true)]
+ public partial class CompareInfo : IDeserializationCallback
+ {
+ // Mask used to check if IndexOf()/LastIndexOf()/IsPrefix()/IsPostfix() has the right flags.
+ private const CompareOptions ValidIndexMaskOffFlags =
+ ~(CompareOptions.IgnoreCase | CompareOptions.IgnoreSymbols | CompareOptions.IgnoreNonSpace |
+ CompareOptions.IgnoreWidth | CompareOptions.IgnoreKanaType);
+
+ // Mask used to check if Compare() has the right flags.
+ private const CompareOptions ValidCompareMaskOffFlags =
+ ~(CompareOptions.IgnoreCase | CompareOptions.IgnoreSymbols | CompareOptions.IgnoreNonSpace |
+ CompareOptions.IgnoreWidth | CompareOptions.IgnoreKanaType | CompareOptions.StringSort);
+
+ // Mask used to check if GetHashCodeOfString() has the right flags.
+ private const CompareOptions ValidHashCodeOfStringMaskOffFlags =
+ ~(CompareOptions.IgnoreCase | CompareOptions.IgnoreSymbols | CompareOptions.IgnoreNonSpace |
+ CompareOptions.IgnoreWidth | CompareOptions.IgnoreKanaType);
+
+ //
+ // CompareInfos have an interesting identity. They are attached to the locale that created them,
+ // ie: en-US would have an en-US sort. For haw-US (custom), then we serialize it as haw-US.
+ // The interesting part is that since haw-US doesn't have its own sort, it has to point at another
+ // locale, which is what SCOMPAREINFO does.
+
+ [OptionalField(VersionAdded = 2)]
+ private String _name; // The name used to construct this CompareInfo
+ [NonSerialized]
+ private String _sortName; // The name that defines our behavior
+
+ /*=================================GetCompareInfo==========================
+ **Action: Get the CompareInfo for the specified culture.
+ **Returns: The CompareInfo for the specified culture.
+ **Arguments:
+ ** name the name of the culture.
+ **Exceptions:
+ ** ArgumentException if name is invalid.
+ ============================================================================*/
+
+ public static CompareInfo GetCompareInfo(String name)
+ {
+ if (name == null)
+ {
+ throw new ArgumentNullException("name");
+ }
+ Contract.EndContractBlock();
+
+ return CultureInfo.GetCultureInfo(name).CompareInfo;
+ }
+
+ [OnDeserializing]
+ private void OnDeserializing(StreamingContext ctx)
+ {
+ _name = null;
+ }
+
+ void IDeserializationCallback.OnDeserialization(Object sender)
+ {
+ OnDeserialized();
+ }
+
+ [OnDeserialized]
+ private void OnDeserialized(StreamingContext ctx)
+ {
+ OnDeserialized();
+ }
+
+ private void OnDeserialized()
+ {
+ if (_name != null)
+ {
+ InitSort(CultureInfo.GetCultureInfo(_name));
+ }
+ }
+
+ [OnSerializing]
+ private void OnSerializing(StreamingContext ctx) { }
+
+ ///////////////////////////----- Name -----/////////////////////////////////
+ //
+ // Returns the name of the culture (well actually, of the sort).
+ // Very important for providing a non-LCID way of identifying
+ // what the sort is.
+ //
+ // Note that this name isn't dereferenced in case the CompareInfo is a different locale
+ // which is consistent with the behaviors of earlier versions. (so if you ask for a sort
+ // and the locale's changed behavior, then you'll get changed behavior, which is like
+ // what happens for a version update)
+ //
+ ////////////////////////////////////////////////////////////////////////
+
+ [System.Runtime.InteropServices.ComVisible(false)]
+ public virtual String Name
+ {
+ get
+ {
+ Contract.Assert(_name != null, "CompareInfo.Name Expected _name to be set");
+ if (_name == "zh-CHT" || _name == "zh-CHS")
+ {
+ return _name;
+ }
+
+ return _sortName;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Compare
+ //
+ // Compares the two strings with the given options. Returns 0 if the
+ // two strings are equal, a number less than 0 if string1 is less
+ // than string2, and a number greater than 0 if string1 is greater
+ // than string2.
+ //
+ ////////////////////////////////////////////////////////////////////////
+
+ public virtual int Compare(String string1, String string2)
+ {
+ return (Compare(string1, string2, CompareOptions.None));
+ }
+
+ public unsafe virtual int Compare(String string1, String string2, CompareOptions options)
+ {
+ if (options == CompareOptions.OrdinalIgnoreCase)
+ {
+ return String.Compare(string1, string2, StringComparison.OrdinalIgnoreCase);
+ }
+
+ // Verify the options before we do any real comparison.
+ if ((options & CompareOptions.Ordinal) != 0)
+ {
+ if (options != CompareOptions.Ordinal)
+ {
+ throw new ArgumentException(SR.Argument_CompareOptionOrdinal, "options");
+ }
+ return String.CompareOrdinal(string1, string2);
+ }
+
+ if ((options & ValidCompareMaskOffFlags) != 0)
+ {
+ throw new ArgumentException(SR.Argument_InvalidFlag, "options");
+ }
+
+ //Our paradigm is that null sorts less than any other string and
+ //that two nulls sort as equal.
+ if (string1 == null)
+ {
+ if (string2 == null)
+ {
+ return (0); // Equal
+ }
+ return (-1); // null < non-null
+ }
+ if (string2 == null)
+ {
+ return (1); // non-null > null
+ }
+
+ return CompareString(string1, 0, string1.Length, string2, 0, string2.Length, options);
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Compare
+ //
+ // Compares the specified regions of the two strings with the given
+ // options.
+ // Returns 0 if the two strings are equal, a number less than 0 if
+ // string1 is less than string2, and a number greater than 0 if
+ // string1 is greater than string2.
+ //
+ ////////////////////////////////////////////////////////////////////////
+
+
+ public unsafe virtual int Compare(String string1, int offset1, int length1, String string2, int offset2, int length2)
+ {
+ return Compare(string1, offset1, length1, string2, offset2, length2, 0);
+ }
+
+
+ public unsafe virtual int Compare(String string1, int offset1, String string2, int offset2, CompareOptions options)
+ {
+ return Compare(string1, offset1, string1 == null ? 0 : string1.Length - offset1,
+ string2, offset2, string2 == null ? 0 : string2.Length - offset2, options);
+ }
+
+
+ public unsafe virtual int Compare(String string1, int offset1, String string2, int offset2)
+ {
+ return Compare(string1, offset1, string2, offset2, 0);
+ }
+
+
+ public unsafe virtual int Compare(String string1, int offset1, int length1, String string2, int offset2, int length2, CompareOptions options)
+ {
+ if (options == CompareOptions.OrdinalIgnoreCase)
+ {
+ int result = String.Compare(string1, offset1, string2, offset2, length1 < length2 ? length1 : length2, StringComparison.OrdinalIgnoreCase);
+ if ((length1 != length2) && result == 0)
+ return (length1 > length2 ? 1 : -1);
+ return (result);
+ }
+
+ // Verify inputs
+ if (length1 < 0 || length2 < 0)
+ {
+ throw new ArgumentOutOfRangeException((length1 < 0) ? "length1" : "length2", SR.ArgumentOutOfRange_NeedPosNum);
+ }
+ if (offset1 < 0 || offset2 < 0)
+ {
+ throw new ArgumentOutOfRangeException((offset1 < 0) ? "offset1" : "offset2", SR.ArgumentOutOfRange_NeedPosNum);
+ }
+ if (offset1 > (string1 == null ? 0 : string1.Length) - length1)
+ {
+ throw new ArgumentOutOfRangeException("string1", SR.ArgumentOutOfRange_OffsetLength);
+ }
+ if (offset2 > (string2 == null ? 0 : string2.Length) - length2)
+ {
+ throw new ArgumentOutOfRangeException("string2", SR.ArgumentOutOfRange_OffsetLength);
+ }
+ if ((options & CompareOptions.Ordinal) != 0)
+ {
+ if (options != CompareOptions.Ordinal)
+ {
+ throw new ArgumentException(SR.Argument_CompareOptionOrdinal,
+ "options");
+ }
+ }
+ else if ((options & ValidCompareMaskOffFlags) != 0)
+ {
+ throw new ArgumentException(SR.Argument_InvalidFlag, "options");
+ }
+
+ //
+ // Check for the null case.
+ //
+ if (string1 == null)
+ {
+ if (string2 == null)
+ {
+ return (0);
+ }
+ return (-1);
+ }
+ if (string2 == null)
+ {
+ return (1);
+ }
+
+ if (options == CompareOptions.Ordinal)
+ {
+ return CompareOrdinal(string1, offset1, length1,
+ string2, offset2, length2);
+ }
+ return CompareString(string1, offset1, length1,
+ string2, offset2, length2,
+ options);
+ }
+
+ private static int CompareOrdinal(string string1, int offset1, int length1, string string2, int offset2, int length2)
+ {
+ int result = String.CompareOrdinal(string1, offset1, string2, offset2,
+ (length1 < length2 ? length1 : length2));
+ if ((length1 != length2) && result == 0)
+ {
+ return (length1 > length2 ? 1 : -1);
+ }
+ return (result);
+ }
+
+ //
+ // CompareOrdinalIgnoreCase compare two string oridnally with ignoring the case.
+ // it assumes the strings are Ascii string till we hit non Ascii character in strA or strB and then we continue the comparison by
+ // calling the OS.
+ //
+ internal static unsafe int CompareOrdinalIgnoreCase(string strA, int indexA, int lengthA, string strB, int indexB, int lengthB)
+ {
+ Contract.Assert(indexA + lengthA <= strA.Length);
+ Contract.Assert(indexB + lengthB <= strB.Length);
+
+ int length = Math.Min(lengthA, lengthB);
+ int range = length;
+
+ fixed (char* ap = strA) fixed (char* bp = strB)
+ {
+ char* a = ap + indexA;
+ char* b = bp + indexB;
+
+ while (length != 0 && (*a <= 0x80) && (*b <= 0x80))
+ {
+ int charA = *a;
+ int charB = *b;
+
+ if (charA == charB)
+ {
+ a++; b++;
+ length--;
+ continue;
+ }
+
+ // uppercase both chars - notice that we need just one compare per char
+ if ((uint)(charA - 'a') <= (uint)('z' - 'a')) charA -= 0x20;
+ if ((uint)(charB - 'a') <= (uint)('z' - 'a')) charB -= 0x20;
+
+ //Return the (case-insensitive) difference between them.
+ if (charA != charB)
+ return charA - charB;
+
+ // Next char
+ a++; b++;
+ length--;
+ }
+
+ if (length == 0)
+ return lengthA - lengthB;
+
+ range -= length;
+
+ return CompareStringOrdinalIgnoreCase(a, lengthA - range, b, lengthB - range);
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // IsPrefix
+ //
+ // Determines whether prefix is a prefix of string. If prefix equals
+ // String.Empty, true is returned.
+ //
+ ////////////////////////////////////////////////////////////////////////
+ public unsafe virtual bool IsPrefix(String source, String prefix, CompareOptions options)
+ {
+ if (source == null || prefix == null)
+ {
+ throw new ArgumentNullException((source == null ? "source" : "prefix"),
+ SR.ArgumentNull_String);
+ }
+ Contract.EndContractBlock();
+
+ if (prefix.Length == 0)
+ {
+ return (true);
+ }
+
+ if (source.Length == 0)
+ {
+ return false;
+ }
+
+ if (options == CompareOptions.OrdinalIgnoreCase)
+ {
+ return source.StartsWith(prefix, StringComparison.OrdinalIgnoreCase);
+ }
+
+ if (options == CompareOptions.Ordinal)
+ {
+ return source.StartsWith(prefix, StringComparison.Ordinal);
+ }
+
+ if ((options & ValidIndexMaskOffFlags) != 0)
+ {
+ throw new ArgumentException(SR.Argument_InvalidFlag, "options");
+ }
+
+ return StartsWith(source, prefix, options);
+ }
+
+ public virtual bool IsPrefix(String source, String prefix)
+ {
+ return (IsPrefix(source, prefix, 0));
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // IsSuffix
+ //
+ // Determines whether suffix is a suffix of string. If suffix equals
+ // String.Empty, true is returned.
+ //
+ ////////////////////////////////////////////////////////////////////////
+ public unsafe virtual bool IsSuffix(String source, String suffix, CompareOptions options)
+ {
+ if (source == null || suffix == null)
+ {
+ throw new ArgumentNullException((source == null ? "source" : "suffix"),
+ SR.ArgumentNull_String);
+ }
+ Contract.EndContractBlock();
+
+ if (suffix.Length == 0)
+ {
+ return (true);
+ }
+
+ if (source.Length == 0)
+ {
+ return false;
+ }
+
+ if (options == CompareOptions.OrdinalIgnoreCase)
+ {
+ return source.EndsWith(suffix, StringComparison.OrdinalIgnoreCase);
+ }
+
+ if (options == CompareOptions.Ordinal)
+ {
+ return source.EndsWith(suffix, StringComparison.Ordinal);
+ }
+
+ if ((options & ValidIndexMaskOffFlags) != 0)
+ {
+ throw new ArgumentException(SR.Argument_InvalidFlag, "options");
+ }
+
+ return EndsWith(source, suffix, options);
+ }
+
+
+ public virtual bool IsSuffix(String source, String suffix)
+ {
+ return (IsSuffix(source, suffix, 0));
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // IndexOf
+ //
+ // Returns the first index where value is found in string. The
+ // search starts from startIndex and ends at endIndex. Returns -1 if
+ // the specified value is not found. If value equals String.Empty,
+ // startIndex is returned. Throws IndexOutOfRange if startIndex or
+ // endIndex is less than zero or greater than the length of string.
+ // Throws ArgumentException if value is null.
+ //
+ ////////////////////////////////////////////////////////////////////////
+
+
+ public unsafe virtual int IndexOf(String source, char value)
+ {
+ if (source == null)
+ throw new ArgumentNullException("source");
+ Contract.EndContractBlock();
+
+ return IndexOf(source, value, 0, source.Length, CompareOptions.None);
+ }
+
+
+ public unsafe virtual int IndexOf(String source, String value)
+ {
+ if (source == null)
+ throw new ArgumentNullException("source");
+ Contract.EndContractBlock();
+
+ return IndexOf(source, value, 0, source.Length, CompareOptions.None);
+ }
+
+
+ public unsafe virtual int IndexOf(String source, char value, CompareOptions options)
+ {
+ if (source == null)
+ throw new ArgumentNullException("source");
+ Contract.EndContractBlock();
+
+ return IndexOf(source, value, 0, source.Length, options);
+ }
+
+
+ public unsafe virtual int IndexOf(String source, String value, CompareOptions options)
+ {
+ if (source == null)
+ throw new ArgumentNullException("source");
+ Contract.EndContractBlock();
+
+ return IndexOf(source, value, 0, source.Length, options);
+ }
+
+
+ public unsafe virtual int IndexOf(String source, char value, int startIndex, CompareOptions options)
+ {
+ if (source == null)
+ throw new ArgumentNullException("source");
+ Contract.EndContractBlock();
+
+ return IndexOf(source, value, startIndex, source.Length - startIndex, options);
+ }
+
+
+ public unsafe virtual int IndexOf(String source, String value, int startIndex, CompareOptions options)
+ {
+ if (source == null)
+ throw new ArgumentNullException("source");
+ Contract.EndContractBlock();
+
+ return IndexOf(source, value, startIndex, source.Length - startIndex, options);
+ }
+
+
+ public unsafe virtual int IndexOf(String source, char value, int startIndex, int count)
+ {
+ return IndexOf(source, value, startIndex, count, CompareOptions.None);
+ }
+
+
+ public unsafe virtual int IndexOf(String source, String value, int startIndex, int count)
+ {
+ return IndexOf(source, value, startIndex, count, CompareOptions.None);
+ }
+
+ public unsafe virtual int IndexOf(String source, char value, int startIndex, int count, CompareOptions options)
+ {
+ // Validate inputs
+ if (source == null)
+ throw new ArgumentNullException("source");
+
+ if (startIndex < 0 || startIndex > source.Length)
+ throw new ArgumentOutOfRangeException("startIndex", SR.ArgumentOutOfRange_Index);
+
+ if (count < 0 || startIndex > source.Length - count)
+ throw new ArgumentOutOfRangeException("count", SR.ArgumentOutOfRange_Count);
+ Contract.EndContractBlock();
+
+ if (options == CompareOptions.OrdinalIgnoreCase)
+ {
+ return source.IndexOf(value.ToString(), startIndex, count, StringComparison.OrdinalIgnoreCase);
+ }
+
+ // Validate CompareOptions
+ // Ordinal can't be selected with other flags
+ if ((options & ValidIndexMaskOffFlags) != 0 && (options != CompareOptions.Ordinal))
+ throw new ArgumentException(SR.Argument_InvalidFlag, "options");
+
+ return IndexOfCore(source, new string(value, 1), startIndex, count, options);
+ }
+
+
+ public unsafe virtual int IndexOf(String source, String value, int startIndex, int count, CompareOptions options)
+ {
+ // Validate inputs
+ if (source == null)
+ throw new ArgumentNullException("source");
+ if (value == null)
+ throw new ArgumentNullException("value");
+
+ if (startIndex > source.Length)
+ {
+ throw new ArgumentOutOfRangeException("startIndex", SR.ArgumentOutOfRange_Index);
+ }
+ Contract.EndContractBlock();
+
+ // In Everett we used to return -1 for empty string even if startIndex is negative number so we keeping same behavior here.
+ // We return 0 if both source and value are empty strings for Everett compatibility too.
+ if (source.Length == 0)
+ {
+ if (value.Length == 0)
+ {
+ return 0;
+ }
+ return -1;
+ }
+
+ if (startIndex < 0)
+ {
+ throw new ArgumentOutOfRangeException("startIndex", SR.ArgumentOutOfRange_Index);
+ }
+
+ if (count < 0 || startIndex > source.Length - count)
+ throw new ArgumentOutOfRangeException("count", SR.ArgumentOutOfRange_Count);
+
+ if (options == CompareOptions.OrdinalIgnoreCase)
+ {
+ return IndexOfOrdinal(source, value, startIndex, count, ignoreCase: true);
+ }
+
+ // Validate CompareOptions
+ // Ordinal can't be selected with other flags
+ if ((options & ValidIndexMaskOffFlags) != 0 && (options != CompareOptions.Ordinal))
+ throw new ArgumentException(SR.Argument_InvalidFlag, "options");
+
+ return IndexOfCore(source, value, startIndex, count, options);
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // LastIndexOf
+ //
+ // Returns the last index where value is found in string. The
+ // search starts from startIndex and ends at endIndex. Returns -1 if
+ // the specified value is not found. If value equals String.Empty,
+ // endIndex is returned. Throws IndexOutOfRange if startIndex or
+ // endIndex is less than zero or greater than the length of string.
+ // Throws ArgumentException if value is null.
+ //
+ ////////////////////////////////////////////////////////////////////////
+
+
+ public unsafe virtual int LastIndexOf(String source, char value)
+ {
+ if (source == null)
+ throw new ArgumentNullException("source");
+ Contract.EndContractBlock();
+
+ // Can't start at negative index, so make sure we check for the length == 0 case.
+ return LastIndexOf(source, value, source.Length - 1,
+ source.Length, CompareOptions.None);
+ }
+
+
+ public virtual int LastIndexOf(String source, String value)
+ {
+ if (source == null)
+ throw new ArgumentNullException("source");
+ Contract.EndContractBlock();
+
+ // Can't start at negative index, so make sure we check for the length == 0 case.
+ return LastIndexOf(source, value, source.Length - 1,
+ source.Length, CompareOptions.None);
+ }
+
+
+ public virtual int LastIndexOf(String source, char value, CompareOptions options)
+ {
+ if (source == null)
+ throw new ArgumentNullException("source");
+ Contract.EndContractBlock();
+
+ // Can't start at negative index, so make sure we check for the length == 0 case.
+ return LastIndexOf(source, value, source.Length - 1,
+ source.Length, options);
+ }
+
+ public unsafe virtual int LastIndexOf(String source, String value, CompareOptions options)
+ {
+ if (source == null)
+ throw new ArgumentNullException("source");
+ Contract.EndContractBlock();
+
+ // Can't start at negative index, so make sure we check for the length == 0 case.
+ return LastIndexOf(source, value, source.Length - 1,
+ source.Length, options);
+ }
+
+
+ public unsafe virtual int LastIndexOf(String source, char value, int startIndex, CompareOptions options)
+ {
+ return LastIndexOf(source, value, startIndex, startIndex + 1, options);
+ }
+
+
+ public unsafe virtual int LastIndexOf(String source, String value, int startIndex, CompareOptions options)
+ {
+ return LastIndexOf(source, value, startIndex, startIndex + 1, options);
+ }
+
+
+ public unsafe virtual int LastIndexOf(String source, char value, int startIndex, int count)
+ {
+ return LastIndexOf(source, value, startIndex, count, CompareOptions.None);
+ }
+
+
+ public unsafe virtual int LastIndexOf(String source, String value, int startIndex, int count)
+ {
+ return LastIndexOf(source, value, startIndex, count, CompareOptions.None);
+ }
+
+
+ public unsafe virtual int LastIndexOf(String source, char value, int startIndex, int count, CompareOptions options)
+ {
+ // Verify Arguments
+ if (source == null)
+ throw new ArgumentNullException("source");
+ Contract.EndContractBlock();
+
+ // Validate CompareOptions
+ // Ordinal can't be selected with other flags
+ if ((options & ValidIndexMaskOffFlags) != 0 &&
+ (options != CompareOptions.Ordinal) &&
+ (options != CompareOptions.OrdinalIgnoreCase))
+ throw new ArgumentException(SR.Argument_InvalidFlag, "options");
+
+ // Special case for 0 length input strings
+ if (source.Length == 0 && (startIndex == -1 || startIndex == 0))
+ return -1;
+
+ // Make sure we're not out of range
+ if (startIndex < 0 || startIndex > source.Length)
+ throw new ArgumentOutOfRangeException("startIndex", SR.ArgumentOutOfRange_Index);
+
+ // Make sure that we allow startIndex == source.Length
+ if (startIndex == source.Length)
+ {
+ startIndex--;
+ if (count > 0)
+ count--;
+ }
+
+ // 2nd have of this also catches when startIndex == MAXINT, so MAXINT - 0 + 1 == -1, which is < 0.
+ if (count < 0 || startIndex - count + 1 < 0)
+ throw new ArgumentOutOfRangeException("count", SR.ArgumentOutOfRange_Count);
+
+ if (options == CompareOptions.OrdinalIgnoreCase)
+ {
+ return source.LastIndexOf(value.ToString(), startIndex, count, StringComparison.OrdinalIgnoreCase);
+ }
+
+ return LastIndexOfCore(source, value.ToString(), startIndex, count, options);
+ }
+
+
+ public unsafe virtual int LastIndexOf(String source, String value, int startIndex, int count, CompareOptions options)
+ {
+ // Verify Arguments
+ if (source == null)
+ throw new ArgumentNullException("source");
+ if (value == null)
+ throw new ArgumentNullException("value");
+ Contract.EndContractBlock();
+
+ // Validate CompareOptions
+ // Ordinal can't be selected with other flags
+ if ((options & ValidIndexMaskOffFlags) != 0 &&
+ (options != CompareOptions.Ordinal) &&
+ (options != CompareOptions.OrdinalIgnoreCase))
+ throw new ArgumentException(SR.Argument_InvalidFlag, "options");
+
+ // Special case for 0 length input strings
+ if (source.Length == 0 && (startIndex == -1 || startIndex == 0))
+ return (value.Length == 0) ? 0 : -1;
+
+ // Make sure we're not out of range
+ if (startIndex < 0 || startIndex > source.Length)
+ throw new ArgumentOutOfRangeException("startIndex", SR.ArgumentOutOfRange_Index);
+
+ // Make sure that we allow startIndex == source.Length
+ if (startIndex == source.Length)
+ {
+ startIndex--;
+ if (count > 0)
+ count--;
+
+ // If we are looking for nothing, just return 0
+ if (value.Length == 0 && count >= 0 && startIndex - count + 1 >= 0)
+ return startIndex;
+ }
+
+ // 2nd half of this also catches when startIndex == MAXINT, so MAXINT - 0 + 1 == -1, which is < 0.
+ if (count < 0 || startIndex - count + 1 < 0)
+ throw new ArgumentOutOfRangeException("count", SR.ArgumentOutOfRange_Count);
+
+ if (options == CompareOptions.OrdinalIgnoreCase)
+ {
+ return LastIndexOfOrdinal(source, value, startIndex, count, ignoreCase: true);
+ }
+
+ return LastIndexOfCore(source, value, startIndex, count, options);
+ }
+
+
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Equals
+ //
+ // Implements Object.Equals(). Returns a boolean indicating whether
+ // or not object refers to the same CompareInfo as the current
+ // instance.
+ //
+ ////////////////////////////////////////////////////////////////////////
+
+
+ public override bool Equals(Object value)
+ {
+ CompareInfo that = value as CompareInfo;
+
+ if (that != null)
+ {
+ return this.Name == that.Name;
+ }
+
+ return (false);
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // GetHashCode
+ //
+ // Implements Object.GetHashCode(). Returns the hash code for the
+ // CompareInfo. The hash code is guaranteed to be the same for
+ // CompareInfo A and B where A.Equals(B) is true.
+ //
+ ////////////////////////////////////////////////////////////////////////
+
+
+ public override int GetHashCode()
+ {
+ return (this.Name.GetHashCode());
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // GetHashCodeOfString
+ //
+ // This internal method allows a method that allows the equivalent of creating a Sortkey for a
+ // string from CompareInfo, and generate a hashcode value from it. It is not very convenient
+ // to use this method as is and it creates an unnecessary Sortkey object that will be GC'ed.
+ //
+ // The hash code is guaranteed to be the same for string A and B where A.Equals(B) is true and both
+ // the CompareInfo and the CompareOptions are the same. If two different CompareInfo objects
+ // treat the string the same way, this implementation will treat them differently (the same way that
+ // Sortkey does at the moment).
+ //
+ // This method will never be made public itself, but public consumers of it could be created, e.g.:
+ //
+ // string.GetHashCode(CultureInfo)
+ // string.GetHashCode(CompareInfo)
+ // string.GetHashCode(CultureInfo, CompareOptions)
+ // string.GetHashCode(CompareInfo, CompareOptions)
+ // etc.
+ //
+ // (the methods above that take a CultureInfo would use CultureInfo.CompareInfo)
+ //
+ ////////////////////////////////////////////////////////////////////////
+ internal int GetHashCodeOfString(string source, CompareOptions options)
+ {
+ //
+ // Parameter validation
+ //
+ if (null == source)
+ {
+ throw new ArgumentNullException("source");
+ }
+
+ if ((options & ValidHashCodeOfStringMaskOffFlags) != 0)
+ {
+ throw new ArgumentException(SR.Argument_InvalidFlag, "options");
+ }
+ Contract.EndContractBlock();
+
+ return GetHashCodeOfStringCore(source, options);
+ }
+
+ public virtual int GetHashCode(string source, CompareOptions options)
+ {
+ if (source == null)
+ {
+ throw new ArgumentNullException("source");
+ }
+
+ if (options == CompareOptions.Ordinal)
+ {
+ return source.GetHashCode();
+ }
+
+ if (options == CompareOptions.OrdinalIgnoreCase)
+ {
+ return TextInfo.GetHashCodeOrdinalIgnoreCase(source);
+ }
+
+ //
+ // GetHashCodeOfString does more parameters validation. basically will throw when
+ // having Ordinal, OrdinalIgnoreCase and StringSort
+ //
+
+ return GetHashCodeOfString(source, options);
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // ToString
+ //
+ // Implements Object.ToString(). Returns a string describing the
+ // CompareInfo.
+ //
+ ////////////////////////////////////////////////////////////////////////
+ public override String ToString()
+ {
+ return ("CompareInfo - " + this.Name);
+ }
+ }
+}
diff --git a/src/mscorlib/corefx/System/Globalization/CultureData.Unix.cs b/src/mscorlib/corefx/System/Globalization/CultureData.Unix.cs
new file mode 100644
index 0000000000..58aae2f40b
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/CultureData.Unix.cs
@@ -0,0 +1,304 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.Contracts;
+using System.Runtime.InteropServices;
+using System.Security;
+using System.Text;
+
+namespace System.Globalization
+{
+ internal partial class CultureData
+ {
+ // ICU constants
+ const int ICU_ULOC_KEYWORD_AND_VALUES_CAPACITY = 100; // max size of keyword or value
+ const int ICU_ULOC_FULLNAME_CAPACITY = 157; // max size of locale name
+ const string ICU_COLLATION_KEYWORD = "@collation=";
+
+ /// <summary>
+ /// This method uses the sRealName field (which is initialized by the constructor before this is called) to
+ /// initialize the rest of the state of CultureData based on the underlying OS globalization library.
+ /// </summary>
+ [SecuritySafeCritical]
+ private unsafe bool InitCultureData()
+ {
+ Contract.Assert(_sRealName != null);
+
+ string alternateSortName = string.Empty;
+ string realNameBuffer = _sRealName;
+
+ // Basic validation
+ if (realNameBuffer.Contains("@"))
+ {
+ return false; // don't allow ICU variants to come in directly
+ }
+
+ // Replace _ (alternate sort) with @collation= for ICU
+ int index = realNameBuffer.IndexOf('_');
+ if (index > 0)
+ {
+ if (index >= (realNameBuffer.Length - 1) // must have characters after _
+ || realNameBuffer.Substring(index + 1).Contains("_")) // only one _ allowed
+ {
+ return false; // fail
+ }
+ alternateSortName = realNameBuffer.Substring(index + 1);
+ realNameBuffer = realNameBuffer.Substring(0, index) + ICU_COLLATION_KEYWORD + alternateSortName;
+ }
+
+ // Get the locale name from ICU
+ if (!GetLocaleName(realNameBuffer, out _sWindowsName))
+ {
+ return false; // fail
+ }
+
+ // Replace the ICU collation keyword with an _
+ index = _sWindowsName.IndexOf(ICU_COLLATION_KEYWORD, StringComparison.Ordinal);
+ if (index >= 0)
+ {
+ _sName = _sWindowsName.Substring(0, index) + "_" + alternateSortName;
+ }
+ else
+ {
+ _sName = _sWindowsName;
+ }
+ _sRealName = _sName;
+ _sSpecificCulture = _sRealName; // we don't attempt to find a non-neutral locale if a neutral is passed in (unlike win32)
+
+ _iLanguage = this.ILANGUAGE;
+ if (_iLanguage == 0)
+ {
+ _iLanguage = LOCALE_CUSTOM_UNSPECIFIED;
+ }
+
+ _bNeutral = (this.SISO3166CTRYNAME.Length == 0);
+
+ // Remove the sort from sName unless custom culture
+ if (!_bNeutral)
+ {
+ if (!IsCustomCultureId(_iLanguage))
+ {
+ _sName = _sWindowsName.Substring(0, index);
+ }
+ }
+ return true;
+ }
+
+ [SecuritySafeCritical]
+ internal static bool GetLocaleName(string localeName, out string windowsName)
+ {
+ // Get the locale name from ICU
+ StringBuilder sb = StringBuilderCache.Acquire(ICU_ULOC_FULLNAME_CAPACITY);
+ if (!Interop.GlobalizationInterop.GetLocaleName(localeName, sb, sb.Capacity))
+ {
+ StringBuilderCache.Release(sb);
+ windowsName = null;
+ return false; // fail
+ }
+
+ // Success - use the locale name returned which may be different than realNameBuffer (casing)
+ windowsName = StringBuilderCache.GetStringAndRelease(sb); // the name passed to subsequent ICU calls
+ return true;
+ }
+
+ [SecuritySafeCritical]
+ internal static bool GetDefaultLocaleName(out string windowsName)
+ {
+ // Get the default (system) locale name from ICU
+ StringBuilder sb = StringBuilderCache.Acquire(ICU_ULOC_FULLNAME_CAPACITY);
+ if (!Interop.GlobalizationInterop.GetDefaultLocaleName(sb, sb.Capacity))
+ {
+ StringBuilderCache.Release(sb);
+ windowsName = null;
+ return false; // fail
+ }
+
+ // Success - use the locale name returned which may be different than realNameBuffer (casing)
+ windowsName = StringBuilderCache.GetStringAndRelease(sb); // the name passed to subsequent ICU calls
+ return true;
+ }
+
+ private string GetLocaleInfo(LocaleStringData type)
+ {
+ Contract.Assert(_sWindowsName != null, "[CultureData.GetLocaleInfo] Expected _sWindowsName to be populated already");
+ return GetLocaleInfo(_sWindowsName, type);
+ }
+
+ // For LOCALE_SPARENT we need the option of using the "real" name (forcing neutral names) instead of the
+ // "windows" name, which can be specific for downlevel (< windows 7) os's.
+ [SecuritySafeCritical]
+ private string GetLocaleInfo(string localeName, LocaleStringData type)
+ {
+ Contract.Assert(localeName != null, "[CultureData.GetLocaleInfo] Expected localeName to be not be null");
+
+ switch (type)
+ {
+ case LocaleStringData.NegativeInfinitySymbol:
+ // not an equivalent in ICU; prefix the PositiveInfinitySymbol with NegativeSign
+ return GetLocaleInfo(localeName, LocaleStringData.NegativeSign) +
+ GetLocaleInfo(localeName, LocaleStringData.PositiveInfinitySymbol);
+ }
+
+ StringBuilder sb = StringBuilderCache.Acquire(ICU_ULOC_KEYWORD_AND_VALUES_CAPACITY);
+
+ bool result = Interop.GlobalizationInterop.GetLocaleInfoString(localeName, (uint)type, sb, sb.Capacity);
+ if (!result)
+ {
+ // Failed, just use empty string
+ StringBuilderCache.Release(sb);
+ Contract.Assert(false, "[CultureData.GetLocaleInfo(LocaleStringData)] Failed");
+ return String.Empty;
+ }
+ return StringBuilderCache.GetStringAndRelease(sb);
+ }
+
+ [SecuritySafeCritical]
+ private int GetLocaleInfo(LocaleNumberData type)
+ {
+ Contract.Assert(_sWindowsName != null, "[CultureData.GetLocaleInfo(LocaleNumberData)] Expected _sWindowsName to be populated already");
+
+ switch (type)
+ {
+ case LocaleNumberData.CalendarType:
+ // returning 0 will cause the first supported calendar to be returned, which is the preferred calendar
+ return 0;
+ }
+
+
+ int value = 0;
+ bool result = Interop.GlobalizationInterop.GetLocaleInfoInt(_sWindowsName, (uint)type, ref value);
+ if (!result)
+ {
+ // Failed, just use 0
+ Contract.Assert(false, "[CultureData.GetLocaleInfo(LocaleNumberData)] failed");
+ }
+
+ return value;
+ }
+
+ [SecuritySafeCritical]
+ private int[] GetLocaleInfo(LocaleGroupingData type)
+ {
+ Contract.Assert(_sWindowsName != null, "[CultureData.GetLocaleInfo(LocaleGroupingData)] Expected _sWindowsName to be populated already");
+
+ int primaryGroupingSize = 0;
+ int secondaryGroupingSize = 0;
+ bool result = Interop.GlobalizationInterop.GetLocaleInfoGroupingSizes(_sWindowsName, (uint)type, ref primaryGroupingSize, ref secondaryGroupingSize);
+ if (!result)
+ {
+ Contract.Assert(false, "[CultureData.GetLocaleInfo(LocaleGroupingData type)] failed");
+ }
+
+ if (secondaryGroupingSize == 0)
+ {
+ return new int[] { primaryGroupingSize };
+ }
+
+ return new int[] { primaryGroupingSize, secondaryGroupingSize };
+ }
+
+ private string GetTimeFormatString()
+ {
+ return GetTimeFormatString(false);
+ }
+
+ [SecuritySafeCritical]
+ private string GetTimeFormatString(bool shortFormat)
+ {
+ Contract.Assert(_sWindowsName != null, "[CultureData.GetTimeFormatString(bool shortFormat)] Expected _sWindowsName to be populated already");
+
+ StringBuilder sb = StringBuilderCache.Acquire(ICU_ULOC_KEYWORD_AND_VALUES_CAPACITY);
+
+ bool result = Interop.GlobalizationInterop.GetLocaleTimeFormat(_sWindowsName, shortFormat, sb, sb.Capacity);
+ if (!result)
+ {
+ // Failed, just use empty string
+ StringBuilderCache.Release(sb);
+ Contract.Assert(false, "[CultureData.GetTimeFormatString(bool shortFormat)] Failed");
+ return String.Empty;
+ }
+
+ return ConvertIcuTimeFormatString(StringBuilderCache.GetStringAndRelease(sb));
+ }
+
+ private int GetFirstDayOfWeek()
+ {
+ return this.GetLocaleInfo(LocaleNumberData.FirstDayOfWeek);
+ }
+
+ private String[] GetTimeFormats()
+ {
+ string format = GetTimeFormatString(false);
+ return new string[] { format };
+ }
+
+ private String[] GetShortTimeFormats()
+ {
+ string format = GetTimeFormatString(true);
+ return new string[] { format };
+ }
+
+ private static CultureData GetCultureDataFromRegionName(String regionName)
+ {
+ // no support to lookup by region name, other than the hard-coded list in CultureData
+ return null;
+ }
+
+ private static string GetLanguageDisplayName(string cultureName)
+ {
+ return new CultureInfo(cultureName).m_cultureData.GetLocaleInfo(cultureName, LocaleStringData.LocalizedDisplayName);
+ }
+
+ private static string GetRegionDisplayName(string isoCountryCode)
+ {
+ // use the fallback which is to return NativeName
+ return null;
+ }
+
+ private static CultureInfo GetUserDefaultCulture()
+ {
+ return CultureInfo.GetUserDefaultCulture();
+ }
+
+ private static string ConvertIcuTimeFormatString(string icuFormatString)
+ {
+ StringBuilder sb = StringBuilderCache.Acquire(ICU_ULOC_FULLNAME_CAPACITY);
+ bool amPmAdded = false;
+
+ for (int i = 0; i < icuFormatString.Length; i++)
+ {
+ switch(icuFormatString[i])
+ {
+ case ':':
+ case '.':
+ case 'H':
+ case 'h':
+ case 'm':
+ case 's':
+ sb.Append(icuFormatString[i]);
+ break;
+
+ case ' ':
+ case '\u00A0':
+ // Convert nonbreaking spaces into regular spaces
+ sb.Append(' ');
+ break;
+
+ case 'a': // AM/PM
+ if (!amPmAdded)
+ {
+ amPmAdded = true;
+ sb.Append("tt");
+ }
+ break;
+
+ }
+ }
+
+ return StringBuilderCache.GetStringAndRelease(sb);
+ }
+ }
+}
diff --git a/src/mscorlib/corefx/System/Globalization/CultureData.Windows.cs b/src/mscorlib/corefx/System/Globalization/CultureData.Windows.cs
new file mode 100644
index 0000000000..9969ecbd81
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/CultureData.Windows.cs
@@ -0,0 +1,561 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.Diagnostics.Contracts;
+using System.Runtime.InteropServices;
+using System.Text;
+using Internal.Runtime.Augments;
+
+namespace System.Globalization
+{
+ internal partial class CultureData
+ {
+ private const uint LOCALE_NOUSEROVERRIDE = 0x80000000;
+ private const uint LOCALE_RETURN_NUMBER = 0x20000000;
+ private const uint LOCALE_SISO3166CTRYNAME = 0x0000005A;
+
+ private const uint TIME_NOSECONDS = 0x00000002;
+
+ /// <summary>
+ /// Check with the OS to see if this is a valid culture.
+ /// If so we populate a limited number of fields. If its not valid we return false.
+ ///
+ /// The fields we populate:
+ ///
+ /// sWindowsName -- The name that windows thinks this culture is, ie:
+ /// en-US if you pass in en-US
+ /// de-DE_phoneb if you pass in de-DE_phoneb
+ /// fj-FJ if you pass in fj (neutral, on a pre-Windows 7 machine)
+ /// fj if you pass in fj (neutral, post-Windows 7 machine)
+ ///
+ /// sRealName -- The name you used to construct the culture, in pretty form
+ /// en-US if you pass in EN-us
+ /// en if you pass in en
+ /// de-DE_phoneb if you pass in de-DE_phoneb
+ ///
+ /// sSpecificCulture -- The specific culture for this culture
+ /// en-US for en-US
+ /// en-US for en
+ /// de-DE_phoneb for alt sort
+ /// fj-FJ for fj (neutral)
+ ///
+ /// sName -- The IETF name of this culture (ie: no sort info, could be neutral)
+ /// en-US if you pass in en-US
+ /// en if you pass in en
+ /// de-DE if you pass in de-DE_phoneb
+ ///
+ /// bNeutral -- TRUE if it is a neutral locale
+ ///
+ /// For a neutral we just populate the neutral name, but we leave the windows name pointing to the
+ /// windows locale that's going to provide data for us.
+ /// </summary>
+ private unsafe bool InitCultureData()
+ {
+ const int LOCALE_NAME_MAX_LENGTH = 85;
+
+ const uint LOCALE_ILANGUAGE = 0x00000001;
+ const uint LOCALE_INEUTRAL = 0x00000071;
+ const uint LOCALE_SNAME = 0x0000005c;
+
+ int result;
+ string realNameBuffer = _sRealName;
+ char* pBuffer = stackalloc char[LOCALE_NAME_MAX_LENGTH];
+
+ result = Interop.mincore.GetLocaleInfoEx(realNameBuffer, LOCALE_SNAME, pBuffer, LOCALE_NAME_MAX_LENGTH);
+
+ // Did it fail?
+ if (result == 0)
+ {
+ return false;
+ }
+
+ // It worked, note that the name is the locale name, so use that (even for neutrals)
+ // We need to clean up our "real" name, which should look like the windows name right now
+ // so overwrite the input with the cleaned up name
+ _sRealName = new String(pBuffer, 0, result - 1);
+ realNameBuffer = _sRealName;
+
+ // Check for neutrality, don't expect to fail
+ // (buffer has our name in it, so we don't have to do the gc. stuff)
+
+ result = Interop.mincore.GetLocaleInfoEx(realNameBuffer, LOCALE_INEUTRAL | LOCALE_RETURN_NUMBER, pBuffer, sizeof(int) / sizeof(char));
+ if (result == 0)
+ {
+ return false;
+ }
+
+ // Remember our neutrality
+ _bNeutral = *((uint*)pBuffer) != 0;
+
+ // Note: Parents will be set dynamically
+
+ // Start by assuming the windows name'll be the same as the specific name since windows knows
+ // about specifics on all versions. Only for downlevel Neutral locales does this have to change.
+ _sWindowsName = realNameBuffer;
+
+ // Neutrals and non-neutrals are slightly different
+ if (_bNeutral)
+ {
+ // Neutral Locale
+
+ // IETF name looks like neutral name
+ _sName = realNameBuffer;
+
+ // Specific locale name is whatever ResolveLocaleName (win7+) returns.
+ // (Buffer has our name in it, and we can recycle that because windows resolves it before writing to the buffer)
+ result = Interop.mincore.ResolveLocaleName(realNameBuffer, pBuffer, LOCALE_NAME_MAX_LENGTH);
+
+ // 0 is failure, 1 is invariant (""), which we expect
+ if (result < 1)
+ {
+ return false;
+ }
+ // We found a locale name, so use it.
+ // In vista this should look like a sort name (de-DE_phoneb) or a specific culture (en-US) and be in the "pretty" form
+ _sSpecificCulture = new String(pBuffer, 0, result - 1);
+ }
+ else
+ {
+ // Specific Locale
+
+ // Specific culture's the same as the locale name since we know its not neutral
+ // On mac we'll use this as well, even for neutrals. There's no obvious specific
+ // culture to use and this isn't exposed, but behaviorally this is correct on mac.
+ // Note that specifics include the sort name (de-DE_phoneb)
+ _sSpecificCulture = realNameBuffer;
+
+ _sName = realNameBuffer;
+
+ // We need the IETF name (sname)
+ // If we aren't an alt sort locale then this is the same as the windows name.
+ // If we are an alt sort locale then this is the same as the part before the _ in the windows name
+ // This is for like de-DE_phoneb and es-ES_tradnl that hsouldn't have the _ part
+
+ result = Interop.mincore.GetLocaleInfoEx(realNameBuffer, LOCALE_ILANGUAGE | LOCALE_RETURN_NUMBER, pBuffer, sizeof(int) / sizeof(char));
+ if (result == 0)
+ {
+ return false;
+ }
+
+ _iLanguage = *((int*)pBuffer);
+
+ if (!IsCustomCultureId(_iLanguage))
+ {
+ // not custom locale
+ int index = realNameBuffer.IndexOf('_');
+ if (index > 0 && index < realNameBuffer.Length)
+ {
+ _sName = realNameBuffer.Substring(0, index);
+ }
+ }
+ }
+
+ // It succeeded.
+ return true;
+ }
+
+ private string GetLocaleInfo(LocaleStringData type)
+ {
+ Contract.Assert(_sWindowsName != null, "[CultureData.DoGetLocaleInfo] Expected _sWindowsName to be populated by already");
+ return GetLocaleInfo(_sWindowsName, type);
+ }
+
+ // For LOCALE_SPARENT we need the option of using the "real" name (forcing neutral names) instead of the
+ // "windows" name, which can be specific for downlevel (< windows 7) os's.
+ private string GetLocaleInfo(string localeName, LocaleStringData type)
+ {
+ uint lctype = (uint)type;
+
+ return GetLocaleInfoFromLCType(localeName, lctype, UseUserOverride);
+ }
+
+ private int GetLocaleInfo(LocaleNumberData type)
+ {
+ uint lctype = (uint)type;
+
+ // Fix lctype if we don't want overrides
+ if (!UseUserOverride)
+ {
+ lctype |= LOCALE_NOUSEROVERRIDE;
+ }
+
+ // Ask OS for data, note that we presume it returns success, so we have to know that
+ // sWindowsName is valid before calling.
+ Contract.Assert(_sWindowsName != null, "[CultureData.DoGetLocaleInfoInt] Expected _sWindowsName to be populated by already");
+ int result = Interop.mincore.GetLocaleInfoExInt(_sWindowsName, lctype);
+
+ return result;
+ }
+
+ private int[] GetLocaleInfo(LocaleGroupingData type)
+ {
+ return ConvertWin32GroupString(GetLocaleInfoFromLCType(_sWindowsName, (uint)type, UseUserOverride));
+ }
+
+ private string GetTimeFormatString()
+ {
+ const uint LOCALE_STIMEFORMAT = 0x00001003;
+
+ return ReescapeWin32String(GetLocaleInfoFromLCType(_sWindowsName, LOCALE_STIMEFORMAT, UseUserOverride));
+ }
+
+ private int GetFirstDayOfWeek()
+ {
+ Contract.Assert(_sWindowsName != null, "[CultureData.DoGetLocaleInfoInt] Expected _sWindowsName to be populated by already");
+
+ const uint LOCALE_IFIRSTDAYOFWEEK = 0x0000100C;
+
+ int result = Interop.mincore.GetLocaleInfoExInt(_sWindowsName, LOCALE_IFIRSTDAYOFWEEK | (!UseUserOverride ? LOCALE_NOUSEROVERRIDE : 0));
+
+ // Win32 and .NET disagree on the numbering for days of the week, so we have to convert.
+ return ConvertFirstDayOfWeekMonToSun(result);
+ }
+
+ private String[] GetTimeFormats()
+ {
+ // Note that this gets overrides for us all the time
+ Contract.Assert(_sWindowsName != null, "[CultureData.DoEnumTimeFormats] Expected _sWindowsName to be populated by already");
+ String[] result = ReescapeWin32Strings(nativeEnumTimeFormats(_sWindowsName, 0, UseUserOverride));
+
+ return result;
+ }
+
+ private String[] GetShortTimeFormats()
+ {
+ // Note that this gets overrides for us all the time
+ Contract.Assert(_sWindowsName != null, "[CultureData.DoEnumShortTimeFormats] Expected _sWindowsName to be populated by already");
+ String[] result = ReescapeWin32Strings(nativeEnumTimeFormats(_sWindowsName, TIME_NOSECONDS, UseUserOverride));
+
+ return result;
+ }
+
+ // Enumerate all system cultures and then try to find out which culture has
+ // region name match the requested region name
+ private static CultureData GetCultureDataFromRegionName(String regionName)
+ {
+ Contract.Assert(regionName != null);
+
+ const uint LOCALE_SUPPLEMENTAL = 0x00000002;
+ const uint LOCALE_SPECIFICDATA = 0x00000020;
+
+ EnumLocaleData context = new EnumLocaleData();
+ context.cultureName = null;
+ context.regionName = regionName;
+
+ GCHandle contextHandle = GCHandle.Alloc(context);
+ try
+ {
+ IntPtr callback = AddrofIntrinsics.AddrOf<Func<IntPtr, uint, IntPtr, Interop.BOOL>>(EnumSystemLocalesProc);
+ Interop.mincore.EnumSystemLocalesEx(callback, LOCALE_SPECIFICDATA | LOCALE_SUPPLEMENTAL, (IntPtr)contextHandle, IntPtr.Zero);
+ }
+ finally
+ {
+ contextHandle.Free();
+ }
+
+ if (context.cultureName != null)
+ {
+ // we got a matched culture
+ return GetCultureData(context.cultureName, true);
+ }
+
+ return null;
+ }
+
+ private static string GetLanguageDisplayName(string cultureName)
+ {
+ return WinRTInterop.Callbacks.GetLanguageDisplayName(cultureName);
+ }
+
+ private static string GetRegionDisplayName(string isoCountryCode)
+ {
+ return WinRTInterop.Callbacks.GetRegionDisplayName(isoCountryCode);
+ }
+
+ private static CultureInfo GetUserDefaultCulture()
+ {
+ return (CultureInfo)WinRTInterop.Callbacks.GetUserDefaultCulture();
+ }
+
+ // PAL methods end here.
+
+ private static string GetLocaleInfoFromLCType(string localeName, uint lctype, bool useUserOveride)
+ {
+ Contract.Assert(localeName != null, "[CultureData.GetLocaleInfoFromLCType] Expected localeName to be not be null");
+
+ // Fix lctype if we don't want overrides
+ if (!useUserOveride)
+ {
+ lctype |= LOCALE_NOUSEROVERRIDE;
+ }
+
+ // Ask OS for data
+ string result = Interop.mincore.GetLocaleInfoEx(localeName, lctype);
+ if (result == null)
+ {
+ // Failed, just use empty string
+ result = String.Empty;
+ }
+
+ return result;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Reescape a Win32 style quote string as a NLS+ style quoted string
+ //
+ // This is also the escaping style used by custom culture data files
+ //
+ // NLS+ uses \ to escape the next character, whether in a quoted string or
+ // not, so we always have to change \ to \\.
+ //
+ // NLS+ uses \' to escape a quote inside a quoted string so we have to change
+ // '' to \' (if inside a quoted string)
+ //
+ // We don't build the stringbuilder unless we find something to change
+ ////////////////////////////////////////////////////////////////////////////
+ internal static String ReescapeWin32String(String str)
+ {
+ // If we don't have data, then don't try anything
+ if (str == null)
+ return null;
+
+ StringBuilder result = null;
+
+ bool inQuote = false;
+ for (int i = 0; i < str.Length; i++)
+ {
+ // Look for quote
+ if (str[i] == '\'')
+ {
+ // Already in quote?
+ if (inQuote)
+ {
+ // See another single quote. Is this '' of 'fred''s' or '''', or is it an ending quote?
+ if (i + 1 < str.Length && str[i + 1] == '\'')
+ {
+ // Found another ', so we have ''. Need to add \' instead.
+ // 1st make sure we have our stringbuilder
+ if (result == null)
+ result = new StringBuilder(str, 0, i, str.Length * 2);
+
+ // Append a \' and keep going (so we don't turn off quote mode)
+ result.Append("\\'");
+ i++;
+ continue;
+ }
+
+ // Turning off quote mode, fall through to add it
+ inQuote = false;
+ }
+ else
+ {
+ // Found beginning quote, fall through to add it
+ inQuote = true;
+ }
+ }
+ // Is there a single \ character?
+ else if (str[i] == '\\')
+ {
+ // Found a \, need to change it to \\
+ // 1st make sure we have our stringbuilder
+ if (result == null)
+ result = new StringBuilder(str, 0, i, str.Length * 2);
+
+ // Append our \\ to the string & continue
+ result.Append("\\\\");
+ continue;
+ }
+
+ // If we have a builder we need to add our character
+ if (result != null)
+ result.Append(str[i]);
+ }
+
+ // Unchanged string? , just return input string
+ if (result == null)
+ return str;
+
+ // String changed, need to use the builder
+ return result.ToString();
+ }
+
+ internal static String[] ReescapeWin32Strings(String[] array)
+ {
+ if (array != null)
+ {
+ for (int i = 0; i < array.Length; i++)
+ {
+ array[i] = ReescapeWin32String(array[i]);
+ }
+ }
+
+ return array;
+ }
+
+ // If we get a group from windows, then its in 3;0 format with the 0 backwards
+ // of how NLS+ uses it (ie: if the string has a 0, then the int[] shouldn't and vice versa)
+ // EXCEPT in the case where the list only contains 0 in which NLS and NLS+ have the same meaning.
+ private static int[] ConvertWin32GroupString(String win32Str)
+ {
+ // None of these cases make any sense
+ if (win32Str == null || win32Str.Length == 0)
+ {
+ return (new int[] { 3 });
+ }
+
+ if (win32Str[0] == '0')
+ {
+ return (new int[] { 0 });
+ }
+
+ // Since its in n;n;n;n;n format, we can always get the length quickly
+ int[] values;
+ if (win32Str[win32Str.Length - 1] == '0')
+ {
+ // Trailing 0 gets dropped. 1;0 -> 1
+ values = new int[(win32Str.Length / 2)];
+ }
+ else
+ {
+ // Need extra space for trailing zero 1 -> 1;0
+ values = new int[(win32Str.Length / 2) + 2];
+ values[values.Length - 1] = 0;
+ }
+
+ int i;
+ int j;
+ for (i = 0, j = 0; i < win32Str.Length && j < values.Length; i += 2, j++)
+ {
+ // Note that this # shouldn't ever be zero, 'cause 0 is only at end
+ // But we'll test because its registry that could be anything
+ if (win32Str[i] < '1' || win32Str[i] > '9')
+ return new int[] { 3 };
+
+ values[j] = (int)(win32Str[i] - '0');
+ }
+
+ return (values);
+ }
+
+ private static int ConvertFirstDayOfWeekMonToSun(int iTemp)
+ {
+ // Convert Mon-Sun to Sun-Sat format
+ iTemp++;
+ if (iTemp > 6)
+ {
+ // Wrap Sunday and convert invalid data to Sunday
+ iTemp = 0;
+ }
+ return iTemp;
+ }
+
+
+ // Context for EnumCalendarInfoExEx callback.
+ private class EnumLocaleData
+ {
+ public string regionName;
+ public string cultureName;
+ }
+
+ // EnumSystemLocaleEx callback.
+ [NativeCallable(CallingConvention = CallingConvention.StdCall)]
+ private static unsafe Interop.BOOL EnumSystemLocalesProc(IntPtr lpLocaleString, uint flags, IntPtr contextHandle)
+ {
+ EnumLocaleData context = (EnumLocaleData)((GCHandle)contextHandle).Target;
+ try
+ {
+ string cultureName = new string((char*)lpLocaleString);
+ string regionName = Interop.mincore.GetLocaleInfoEx(cultureName, LOCALE_SISO3166CTRYNAME);
+ if (regionName != null && regionName.Equals(context.regionName, StringComparison.OrdinalIgnoreCase))
+ {
+ context.cultureName = cultureName;
+ return Interop.BOOL.FALSE; // we found a match, then stop the enumeration
+ }
+
+ return Interop.BOOL.TRUE;
+ }
+ catch (Exception)
+ {
+ return Interop.BOOL.FALSE;
+ }
+ }
+
+ // Context for EnumTimeFormatsEx callback.
+ private class EnumData
+ {
+ public LowLevelList<string> strings;
+ }
+
+ // EnumTimeFormatsEx callback itself.
+ [NativeCallable(CallingConvention = CallingConvention.StdCall)]
+ private static unsafe Interop.BOOL EnumTimeCallback(IntPtr lpTimeFormatString, IntPtr lParam)
+ {
+ EnumData context = (EnumData)((GCHandle)lParam).Target;
+
+ try
+ {
+ context.strings.Add(new string((char*)lpTimeFormatString));
+ return Interop.BOOL.TRUE;
+ }
+ catch (Exception)
+ {
+ return Interop.BOOL.FALSE;
+ }
+ }
+
+ private static unsafe String[] nativeEnumTimeFormats(String localeName, uint dwFlags, bool useUserOverride)
+ {
+ const uint LOCALE_SSHORTTIME = 0x00000079;
+ const uint LOCALE_STIMEFORMAT = 0x00001003;
+
+ EnumData data = new EnumData();
+ data.strings = new LowLevelList<string>();
+
+ GCHandle dataHandle = GCHandle.Alloc(data);
+ try
+ {
+ // Now call the enumeration API. Work is done by our callback function
+ IntPtr callback = AddrofIntrinsics.AddrOf<Func<IntPtr, IntPtr, Interop.BOOL>>(EnumTimeCallback);
+ Interop.mincore.EnumTimeFormatsEx(callback, localeName, (uint)dwFlags, (IntPtr)dataHandle);
+ }
+ finally
+ {
+ dataHandle.Free();
+ }
+
+ if (data.strings.Count > 0)
+ {
+ // Now we need to allocate our stringarray and populate it
+ string[] results = data.strings.ToArray();
+
+ if (!useUserOverride && data.strings.Count > 1)
+ {
+ // Since there is no "NoUserOverride" aware EnumTimeFormatsEx, we always get an override
+ // The override is the first entry if it is overriden.
+ // We can check if we have overrides by checking the GetLocaleInfo with no override
+ // If we do have an override, we don't know if it is a user defined override or if the
+ // user has just selected one of the predefined formats so we can't just remove it
+ // but we can move it down.
+ uint lcType = (dwFlags == TIME_NOSECONDS) ? LOCALE_SSHORTTIME : LOCALE_STIMEFORMAT;
+ string timeFormatNoUserOverride = GetLocaleInfoFromLCType(localeName, lcType, useUserOverride);
+ if (timeFormatNoUserOverride != "")
+ {
+ string firstTimeFormat = results[0];
+ if (timeFormatNoUserOverride != firstTimeFormat)
+ {
+ results[0] = results[1];
+ results[1] = firstTimeFormat;
+ }
+ }
+ }
+
+ return results;
+ }
+
+ return null;
+ }
+ }
+}
diff --git a/src/mscorlib/corefx/System/Globalization/CultureData.cs b/src/mscorlib/corefx/System/Globalization/CultureData.cs
new file mode 100644
index 0000000000..eb71318fdb
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/CultureData.cs
@@ -0,0 +1,2174 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Diagnostics.Contracts;
+
+namespace System.Globalization
+{
+
+#if INSIDE_CLR
+ using StringStringDictionary = Dictionary<string, string>;
+ using StringCultureDataDictionary = Dictionary<String, CultureData>;
+ using Lock = Object;
+#else
+ using StringStringDictionary = LowLevelDictionary<string, string>;
+ using StringCultureDataDictionary = LowLevelDictionary<string, CultureData>;
+#endif
+
+ //
+ // List of culture data
+ // Note the we cache overrides.
+ // Note that localized names (resource names) aren't available from here.
+ //
+
+ //
+ // Our names are a tad confusing.
+ //
+ // sWindowsName -- The name that windows thinks this culture is, ie:
+ // en-US if you pass in en-US
+ // de-DE_phoneb if you pass in de-DE_phoneb
+ // fj-FJ if you pass in fj (neutral, on a pre-Windows 7 machine)
+ // fj if you pass in fj (neutral, post-Windows 7 machine)
+ //
+ // sRealName -- The name you used to construct the culture, in pretty form
+ // en-US if you pass in EN-us
+ // en if you pass in en
+ // de-DE_phoneb if you pass in de-DE_phoneb
+ //
+ // sSpecificCulture -- The specific culture for this culture
+ // en-US for en-US
+ // en-US for en
+ // de-DE_phoneb for alt sort
+ // fj-FJ for fj (neutral)
+ //
+ // sName -- The IETF name of this culture (ie: no sort info, could be neutral)
+ // en-US if you pass in en-US
+ // en if you pass in en
+ // de-DE if you pass in de-DE_phoneb
+ //
+ internal partial class CultureData
+ {
+ private const int undef = -1;
+ private const int LOCALE_CUSTOM_UNSPECIFIED = 0x1000;
+ private const int LOCALE_CUSTOM_DEFAULT = 0x0c00;
+
+ // Override flag
+ private String _sRealName; // Name you passed in (ie: en-US, en, or de-DE_phoneb)
+ private String _sWindowsName; // Name OS thinks the object is (ie: de-DE_phoneb, or en-US (even if en was passed in))
+
+ // Identity
+ private String _sName; // locale name (ie: en-us, NO sort info, but could be neutral)
+ private String _sParent; // Parent name (which may be a custom locale/culture)
+ private String _sLocalizedDisplayName; // Localized pretty name for this locale
+ private String _sEnglishDisplayName; // English pretty name for this locale
+ private String _sNativeDisplayName; // Native pretty name for this locale
+ private String _sSpecificCulture; // The culture name to be used in CultureInfo.CreateSpecificCulture(), en-US form if neutral, sort name if sort
+
+ // Language
+ private String _sISO639Language; // ISO 639 Language Name
+ private String _sLocalizedLanguage; // Localized name for this language
+ private String _sEnglishLanguage; // English name for this language
+ private String _sNativeLanguage; // Native name of this language
+
+ // Region
+ private String _sRegionName; // (RegionInfo)
+ private String _sLocalizedCountry; // localized country name
+ private String _sEnglishCountry; // english country name (RegionInfo)
+ private String _sNativeCountry; // native country name
+ private String _sISO3166CountryName; // ISO 3166 (RegionInfo), ie: US
+
+ // Numbers
+ private String _sPositiveSign; // (user can override) positive sign
+ private String _sNegativeSign; // (user can override) negative sign
+ private String[] _saNativeDigits; // (user can override) native characters for digits 0-9
+ // (nfi populates these 5, don't have to be = undef)
+ private int _iDigits; // (user can override) number of fractional digits
+ private int _iNegativeNumber; // (user can override) negative number format
+ private int[] _waGrouping; // (user can override) grouping of digits
+ private String _sDecimalSeparator; // (user can override) decimal separator
+ private String _sThousandSeparator; // (user can override) thousands separator
+ private String _sNaN; // Not a Number
+ private String _sPositiveInfinity; // + Infinity
+ private String _sNegativeInfinity; // - Infinity
+
+ // Percent
+ private int _iNegativePercent = undef; // Negative Percent (0-3)
+ private int _iPositivePercent = undef; // Positive Percent (0-11)
+ private String _sPercent; // Percent (%) symbol
+ private String _sPerMille; // PerMille symbol
+
+ // Currency
+ private String _sCurrency; // (user can override) local monetary symbol
+ private String _sIntlMonetarySymbol; // international monetary symbol (RegionInfo)
+ // (nfi populates these 4, don't have to be = undef)
+ private int _iCurrencyDigits; // (user can override) # local monetary fractional digits
+ private int _iCurrency; // (user can override) positive currency format
+ private int _iNegativeCurrency; // (user can override) negative currency format
+ private int[] _waMonetaryGrouping; // (user can override) monetary grouping of digits
+ private String _sMonetaryDecimal; // (user can override) monetary decimal separator
+ private String _sMonetaryThousand; // (user can override) monetary thousands separator
+
+ // Misc
+ private int _iMeasure = undef; // (user can override) system of measurement 0=metric, 1=US (RegionInfo)
+ private String _sListSeparator; // (user can override) list separator
+
+ // Time
+ private String _sAM1159; // (user can override) AM designator
+ private String _sPM2359; // (user can override) PM designator
+ private String _sTimeSeparator;
+ private volatile String[] _saLongTimes; // (user can override) time format
+ private volatile String[] _saShortTimes; // short time format
+ private volatile String[] _saDurationFormats; // time duration format
+
+ // Calendar specific data
+ private int _iFirstDayOfWeek = undef; // (user can override) first day of week (gregorian really)
+ private int _iFirstWeekOfYear = undef; // (user can override) first week of year (gregorian really)
+ private volatile CalendarId[] _waCalendars; // all available calendar type(s). The first one is the default calendar
+
+ // Store for specific data about each calendar
+ private CalendarData[] _calendars; // Store for specific calendar data
+
+ // Text information
+ private int _iReadingLayout = undef; // Reading layout data
+ // 0 - Left to right (eg en-US)
+ // 1 - Right to left (eg arabic locales)
+ // 2 - Vertical top to bottom with columns to the left and also left to right (ja-JP locales)
+ // 3 - Vertical top to bottom with columns proceeding to the right
+
+ // CoreCLR depends on this even though its not exposed publicly.
+
+ private int _iLanguage; // locale ID (0409) - NO sort information
+ private bool _bUseOverrides; // use user overrides?
+ private bool _bNeutral; // Flags for the culture (ie: neutral or not right now)
+
+
+ // Region Name to Culture Name mapping table
+ // (In future would be nice to be in registry or something)
+
+ //Using a property so we avoid creating the dictionary untill we need it
+ private static StringStringDictionary RegionNames
+ {
+ get
+ {
+ if (s_RegionNames == null)
+ {
+ StringStringDictionary regionNames = new StringStringDictionary(211 /* prime */);
+
+ regionNames.Add("029", "en-029");
+ regionNames.Add("AE", "ar-AE");
+ regionNames.Add("AF", "prs-AF");
+ regionNames.Add("AL", "sq-AL");
+ regionNames.Add("AM", "hy-AM");
+ regionNames.Add("AR", "es-AR");
+ regionNames.Add("AT", "de-AT");
+ regionNames.Add("AU", "en-AU");
+ regionNames.Add("AZ", "az-Cyrl-AZ");
+ regionNames.Add("BA", "bs-Latn-BA");
+ regionNames.Add("BD", "bn-BD");
+ regionNames.Add("BE", "nl-BE");
+ regionNames.Add("BG", "bg-BG");
+ regionNames.Add("BH", "ar-BH");
+ regionNames.Add("BN", "ms-BN");
+ regionNames.Add("BO", "es-BO");
+ regionNames.Add("BR", "pt-BR");
+ regionNames.Add("BY", "be-BY");
+ regionNames.Add("BZ", "en-BZ");
+ regionNames.Add("CA", "en-CA");
+ regionNames.Add("CH", "it-CH");
+ regionNames.Add("CL", "es-CL");
+ regionNames.Add("CN", "zh-CN");
+ regionNames.Add("CO", "es-CO");
+ regionNames.Add("CR", "es-CR");
+ regionNames.Add("CS", "sr-Cyrl-CS");
+ regionNames.Add("CZ", "cs-CZ");
+ regionNames.Add("DE", "de-DE");
+ regionNames.Add("DK", "da-DK");
+ regionNames.Add("DO", "es-DO");
+ regionNames.Add("DZ", "ar-DZ");
+ regionNames.Add("EC", "es-EC");
+ regionNames.Add("EE", "et-EE");
+ regionNames.Add("EG", "ar-EG");
+ regionNames.Add("ES", "es-ES");
+ regionNames.Add("ET", "am-ET");
+ regionNames.Add("FI", "fi-FI");
+ regionNames.Add("FO", "fo-FO");
+ regionNames.Add("FR", "fr-FR");
+ regionNames.Add("GB", "en-GB");
+ regionNames.Add("GE", "ka-GE");
+ regionNames.Add("GL", "kl-GL");
+ regionNames.Add("GR", "el-GR");
+ regionNames.Add("GT", "es-GT");
+ regionNames.Add("HK", "zh-HK");
+ regionNames.Add("HN", "es-HN");
+ regionNames.Add("HR", "hr-HR");
+ regionNames.Add("HU", "hu-HU");
+ regionNames.Add("ID", "id-ID");
+ regionNames.Add("IE", "en-IE");
+ regionNames.Add("IL", "he-IL");
+ regionNames.Add("IN", "hi-IN");
+ regionNames.Add("IQ", "ar-IQ");
+ regionNames.Add("IR", "fa-IR");
+ regionNames.Add("IS", "is-IS");
+ regionNames.Add("IT", "it-IT");
+ regionNames.Add("IV", "");
+ regionNames.Add("JM", "en-JM");
+ regionNames.Add("JO", "ar-JO");
+ regionNames.Add("JP", "ja-JP");
+ regionNames.Add("KE", "sw-KE");
+ regionNames.Add("KG", "ky-KG");
+ regionNames.Add("KH", "km-KH");
+ regionNames.Add("KR", "ko-KR");
+ regionNames.Add("KW", "ar-KW");
+ regionNames.Add("KZ", "kk-KZ");
+ regionNames.Add("LA", "lo-LA");
+ regionNames.Add("LB", "ar-LB");
+ regionNames.Add("LI", "de-LI");
+ regionNames.Add("LK", "si-LK");
+ regionNames.Add("LT", "lt-LT");
+ regionNames.Add("LU", "lb-LU");
+ regionNames.Add("LV", "lv-LV");
+ regionNames.Add("LY", "ar-LY");
+ regionNames.Add("MA", "ar-MA");
+ regionNames.Add("MC", "fr-MC");
+ regionNames.Add("ME", "sr-Latn-ME");
+ regionNames.Add("MK", "mk-MK");
+ regionNames.Add("MN", "mn-MN");
+ regionNames.Add("MO", "zh-MO");
+ regionNames.Add("MT", "mt-MT");
+ regionNames.Add("MV", "dv-MV");
+ regionNames.Add("MX", "es-MX");
+ regionNames.Add("MY", "ms-MY");
+ regionNames.Add("NG", "ig-NG");
+ regionNames.Add("NI", "es-NI");
+ regionNames.Add("NL", "nl-NL");
+ regionNames.Add("NO", "nn-NO");
+ regionNames.Add("NP", "ne-NP");
+ regionNames.Add("NZ", "en-NZ");
+ regionNames.Add("OM", "ar-OM");
+ regionNames.Add("PA", "es-PA");
+ regionNames.Add("PE", "es-PE");
+ regionNames.Add("PH", "en-PH");
+ regionNames.Add("PK", "ur-PK");
+ regionNames.Add("PL", "pl-PL");
+ regionNames.Add("PR", "es-PR");
+ regionNames.Add("PT", "pt-PT");
+ regionNames.Add("PY", "es-PY");
+ regionNames.Add("QA", "ar-QA");
+ regionNames.Add("RO", "ro-RO");
+ regionNames.Add("RS", "sr-Latn-RS");
+ regionNames.Add("RU", "ru-RU");
+ regionNames.Add("RW", "rw-RW");
+ regionNames.Add("SA", "ar-SA");
+ regionNames.Add("SE", "sv-SE");
+ regionNames.Add("SG", "zh-SG");
+ regionNames.Add("SI", "sl-SI");
+ regionNames.Add("SK", "sk-SK");
+ regionNames.Add("SN", "wo-SN");
+ regionNames.Add("SV", "es-SV");
+ regionNames.Add("SY", "ar-SY");
+ regionNames.Add("TH", "th-TH");
+ regionNames.Add("TJ", "tg-Cyrl-TJ");
+ regionNames.Add("TM", "tk-TM");
+ regionNames.Add("TN", "ar-TN");
+ regionNames.Add("TR", "tr-TR");
+ regionNames.Add("TT", "en-TT");
+ regionNames.Add("TW", "zh-TW");
+ regionNames.Add("UA", "uk-UA");
+ regionNames.Add("US", "en-US");
+ regionNames.Add("UY", "es-UY");
+ regionNames.Add("UZ", "uz-Cyrl-UZ");
+ regionNames.Add("VE", "es-VE");
+ regionNames.Add("VN", "vi-VN");
+ regionNames.Add("YE", "ar-YE");
+ regionNames.Add("ZA", "af-ZA");
+ regionNames.Add("ZW", "en-ZW");
+
+ s_RegionNames = regionNames;
+ }
+
+ return s_RegionNames;
+ }
+ }
+
+ // Cache of regions we've already looked up
+ private static volatile StringCultureDataDictionary s_cachedRegions;
+ private static volatile StringStringDictionary s_RegionNames;
+
+ internal static CultureData GetCultureDataForRegion(String cultureName, bool useUserOverride)
+ {
+ // First do a shortcut for Invariant
+ if (String.IsNullOrEmpty(cultureName))
+ {
+ return CultureData.Invariant;
+ }
+
+ //
+ // First check if GetCultureData() can find it (ie: its a real culture)
+ //
+ CultureData retVal = GetCultureData(cultureName, useUserOverride);
+ if (retVal != null && (retVal.IsNeutralCulture == false)) return retVal;
+
+ //
+ // Not a specific culture, perhaps it's region-only name
+ // (Remember this isn't a core clr path where that's not supported)
+ //
+
+ // If it was neutral remember that so that RegionInfo() can throw the right exception
+ CultureData neutral = retVal;
+
+ // Try the hash table next
+ String hashName = AnsiToLower(useUserOverride ? cultureName : cultureName + '*');
+ StringCultureDataDictionary tempHashTable = s_cachedRegions;
+ if (tempHashTable == null)
+ {
+ // No table yet, make a new one
+ tempHashTable = new StringCultureDataDictionary();
+ }
+ else
+ {
+ // Check the hash table
+ lock (s_lock)
+ {
+ tempHashTable.TryGetValue(hashName, out retVal);
+ }
+ if (retVal != null)
+ {
+ return retVal;
+ }
+ }
+
+ //
+ // Not found in the hash table, look it up the hard way
+ //
+
+ // If not a valid mapping from the registry we'll have to try the hard coded table
+ if (retVal == null || (retVal.IsNeutralCulture == true))
+ {
+ // Not a valid mapping, try the hard coded table
+ string name;
+ if (RegionNames.TryGetValue(cultureName, out name))
+ {
+ // Make sure we can get culture data for it
+ retVal = GetCultureData(name, useUserOverride);
+ }
+ }
+
+ // If not found in the hard coded table we'll have to find a culture that works for us
+ if (retVal == null || (retVal.IsNeutralCulture == true))
+ {
+ retVal = GetCultureDataFromRegionName(cultureName);
+ }
+
+ // If we found one we can use, then cache it for next time
+ if (retVal != null && (retVal.IsNeutralCulture == false))
+ {
+ // first add it to the cache
+ lock (s_lock)
+ {
+ tempHashTable[hashName] = retVal;
+ }
+
+ // Copy the hashtable to the corresponding member variables. This will potentially overwrite
+ // new tables simultaneously created by a new thread, but maximizes thread safety.
+ s_cachedRegions = tempHashTable;
+ }
+ else
+ {
+ // Unable to find a matching culture/region, return null or neutral
+ // (regionInfo throws a more specific exception on neutrals)
+ retVal = neutral;
+ }
+
+ // Return the found culture to use, null, or the neutral culture.
+ return retVal;
+ }
+
+
+ /////////////////////////////////////////////////////////////////////////
+ // Build our invariant information
+ //
+ // We need an invariant instance, which we build hard-coded
+ /////////////////////////////////////////////////////////////////////////
+ internal static CultureData Invariant
+ {
+ get
+ {
+ if (s_Invariant == null)
+ {
+ // Make a new culturedata
+ CultureData invariant = new CultureData();
+
+ // Basics
+ // Note that we override the resources since this IS NOT supposed to change (by definition)
+ invariant._bUseOverrides = false;
+ invariant._sRealName = ""; // Name you passed in (ie: en-US, en, or de-DE_phoneb)
+ invariant._sWindowsName = ""; // Name OS thinks the object is (ie: de-DE_phoneb, or en-US (even if en was passed in))
+
+ // Identity
+ invariant._sName = ""; // locale name (ie: en-us)
+ invariant._sParent = ""; // Parent name (which may be a custom locale/culture)
+ invariant._bNeutral = false; // Flags for the culture (ie: neutral or not right now)
+ invariant._sEnglishDisplayName = "Invariant Language (Invariant Country)"; // English pretty name for this locale
+ invariant._sNativeDisplayName = "Invariant Language (Invariant Country)"; // Native pretty name for this locale
+ invariant._sSpecificCulture = ""; // The culture name to be used in CultureInfo.CreateSpecificCulture()
+
+ // Language
+ invariant._sISO639Language = "iv"; // ISO 639 Language Name
+ invariant._sLocalizedLanguage = "Invariant Language"; // Display name for this Language
+ invariant._sEnglishLanguage = "Invariant Language"; // English name for this language
+ invariant._sNativeLanguage = "Invariant Language"; // Native name of this language
+
+ // Region
+ invariant._sRegionName = "IV"; // (RegionInfo)
+ invariant._sEnglishCountry = "Invariant Country"; // english country name (RegionInfo)
+ invariant._sNativeCountry = "Invariant Country"; // native country name (Windows Only)
+ invariant._sISO3166CountryName = "IV"; // (RegionInfo), ie: US
+
+ // Numbers
+ invariant._sPositiveSign = "+"; // positive sign
+ invariant._sNegativeSign = "-"; // negative sign
+ invariant._saNativeDigits = new String[] { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" }; // native characters for digits 0-9
+ invariant._iDigits = 2; // number of fractional digits
+ invariant._iNegativeNumber = 1; // negative number format
+ invariant._waGrouping = new int[] { 3 }; // grouping of digits
+ invariant._sDecimalSeparator = "."; // decimal separator
+ invariant._sThousandSeparator = ","; // thousands separator
+ invariant._sNaN = "NaN"; // Not a Number
+ invariant._sPositiveInfinity = "Infinity"; // + Infinity
+ invariant._sNegativeInfinity = "-Infinity"; // - Infinity
+
+ // Percent
+ invariant._iNegativePercent = 0; // Negative Percent (0-3)
+ invariant._iPositivePercent = 0; // Positive Percent (0-11)
+ invariant._sPercent = "%"; // Percent (%) symbol
+ invariant._sPerMille = "\x2030"; // PerMille symbol
+
+ // Currency
+ invariant._sCurrency = "\x00a4"; // local monetary symbol: for international monetary symbol
+ invariant._sIntlMonetarySymbol = "XDR"; // international monetary symbol (RegionInfo)
+ invariant._iCurrencyDigits = 2; // # local monetary fractional digits
+ invariant._iCurrency = 0; // positive currency format
+ invariant._iNegativeCurrency = 0; // negative currency format
+ invariant._waMonetaryGrouping = new int[] { 3 }; // monetary grouping of digits
+ invariant._sMonetaryDecimal = "."; // monetary decimal separator
+ invariant._sMonetaryThousand = ","; // monetary thousands separator
+
+ // Misc
+ invariant._iMeasure = 0; // system of measurement 0=metric, 1=US (RegionInfo)
+ invariant._sListSeparator = ","; // list separator
+
+ // Time
+ invariant._sAM1159 = "AM"; // AM designator
+ invariant._sPM2359 = "PM"; // PM designator
+ invariant._saLongTimes = new String[] { "HH:mm:ss" }; // time format
+ invariant._saShortTimes = new String[] { "HH:mm", "hh:mm tt", "H:mm", "h:mm tt" }; // short time format
+ invariant._saDurationFormats = new String[] { "HH:mm:ss" }; // time duration format
+
+
+ // Calendar specific data
+ invariant._iFirstDayOfWeek = 0; // first day of week
+ invariant._iFirstWeekOfYear = 0; // first week of year
+ invariant._waCalendars = new CalendarId[] { CalendarId.GREGORIAN }; // all available calendar type(s). The first one is the default calendar
+
+ // Store for specific data about each calendar
+ invariant._calendars = new CalendarData[CalendarData.MAX_CALENDARS];
+ invariant._calendars[0] = CalendarData.Invariant;
+
+ // Text information
+ invariant._iReadingLayout = 0;
+
+ // These are desktop only, not coreclr
+
+ invariant._iLanguage = 0x007f; // locale ID (0409) - NO sort information
+ // Remember it
+ s_Invariant = invariant;
+ }
+ return s_Invariant;
+ }
+ }
+ private volatile static CultureData s_Invariant;
+
+ ///////////////
+ // Constructors //
+ ///////////////
+ // Cache of cultures we've already looked up
+ private static volatile StringCultureDataDictionary s_cachedCultures;
+ private static readonly Lock s_lock = new Lock();
+
+ internal static CultureData GetCultureData(String cultureName, bool useUserOverride)
+ {
+ // First do a shortcut for Invariant
+ if (String.IsNullOrEmpty(cultureName))
+ {
+ return CultureData.Invariant;
+ }
+
+ // Try the hash table first
+ String hashName = AnsiToLower(useUserOverride ? cultureName : cultureName + '*');
+ StringCultureDataDictionary tempHashTable = s_cachedCultures;
+ if (tempHashTable == null)
+ {
+ // No table yet, make a new one
+ tempHashTable = new StringCultureDataDictionary();
+ }
+ else
+ {
+ // Check the hash table
+ bool ret;
+ CultureData retVal;
+ lock (s_lock)
+ {
+ ret = tempHashTable.TryGetValue(hashName, out retVal);
+ }
+ if (ret && retVal != null)
+ {
+ return retVal;
+ }
+ }
+
+ // Not found in the hash table, need to see if we can build one that works for us
+ CultureData culture = CreateCultureData(cultureName, useUserOverride);
+ if (culture == null)
+ {
+ return null;
+ }
+
+ // Found one, add it to the cache
+ lock (s_lock)
+ {
+ tempHashTable[hashName] = culture;
+ }
+
+ // Copy the hashtable to the corresponding member variables. This will potentially overwrite
+ // new tables simultaneously created by a new thread, but maximizes thread safety.
+ s_cachedCultures = tempHashTable;
+
+ return culture;
+ }
+
+ private static CultureData CreateCultureData(string cultureName, bool useUserOverride)
+ {
+ CultureData culture = new CultureData();
+ culture._bUseOverrides = useUserOverride;
+ culture._sRealName = cultureName;
+
+ // Ask native code if that one's real
+ if (culture.InitCultureData() == false)
+ {
+ if (culture.InitCompatibilityCultureData() == false)
+ {
+ return null;
+ }
+ }
+
+ return culture;
+ }
+
+ private bool InitCompatibilityCultureData()
+ {
+ // for compatibility handle the deprecated ids: zh-chs, zh-cht
+ string cultureName = _sRealName;
+
+ string fallbackCultureName;
+ string realCultureName;
+ switch (AnsiToLower(cultureName))
+ {
+ case "zh-chs":
+ fallbackCultureName = "zh-Hans";
+ realCultureName = "zh-CHS";
+ break;
+ case "zh-cht":
+ fallbackCultureName = "zh-Hant";
+ realCultureName = "zh-CHT";
+ break;
+ default:
+ return false;
+ }
+
+ _sRealName = fallbackCultureName;
+ if (InitCultureData() == false)
+ {
+ return false;
+ }
+ // fixup our data
+ _sName = realCultureName; // the name that goes back to the user
+ _sParent = fallbackCultureName;
+
+ return true;
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // All the accessors
+ //
+ // Accessors for our data object items
+ //
+ ////////////////////////////////////////////////////////////////////////
+
+ ///////////
+ // Identity //
+ ///////////
+
+ // The real name used to construct the locale (ie: de-DE_phoneb)
+ internal String CultureName
+ {
+ get
+ {
+ Contract.Assert(_sRealName != null, "[CultureData.CultureName] Expected _sRealName to be populated by already");
+ // since windows doesn't know about zh-CHS and zh-CHT,
+ // we leave sRealName == zh-Hanx but we still need to
+ // pretend that it was zh-CHX.
+ switch (_sName)
+ {
+ case "zh-CHS":
+ case "zh-CHT":
+ return _sName;
+ }
+ return _sRealName;
+ }
+ }
+
+ // Are overrides enabled?
+ internal bool UseUserOverride
+ {
+ get
+ {
+ return _bUseOverrides;
+ }
+ }
+
+ // locale name (ie: de-DE, NO sort information)
+ internal String SNAME
+ {
+ get
+ {
+ if (_sName == null)
+ {
+ _sName = String.Empty;
+ }
+ return _sName;
+ }
+ }
+
+ // Parent name (which may be a custom locale/culture)
+ internal String SPARENT
+ {
+ get
+ {
+ if (_sParent == null)
+ {
+ // Ask using the real name, so that we get parents of neutrals
+ _sParent = GetLocaleInfo(_sRealName, LocaleStringData.ParentName);
+ }
+ return _sParent;
+ }
+ }
+
+ // Localized pretty name for this locale (ie: Inglis (estados Unitos))
+ internal String SLOCALIZEDDISPLAYNAME
+ {
+ get
+ {
+ if (_sLocalizedDisplayName == null)
+ {
+ if (this.IsSupplementalCustomCulture)
+ {
+ if (this.IsNeutralCulture)
+ {
+ _sLocalizedDisplayName = this.SNATIVELANGUAGE;
+ }
+ else
+ {
+ _sLocalizedDisplayName = this.SNATIVEDISPLAYNAME;
+ }
+ }
+ else
+ {
+ try
+ {
+ const string ZH_CHT = "zh-CHT";
+ const string ZH_CHS = "zh-CHS";
+
+ if (SNAME.Equals(ZH_CHT, StringComparison.OrdinalIgnoreCase))
+ {
+ _sLocalizedDisplayName = GetLanguageDisplayName("zh-Hant");
+ }
+ else if (SNAME.Equals(ZH_CHS, StringComparison.OrdinalIgnoreCase))
+ {
+ _sLocalizedDisplayName = GetLanguageDisplayName("zh-Hans");
+ }
+ else
+ {
+ _sLocalizedDisplayName = GetLanguageDisplayName(SNAME);
+ }
+ }
+ catch (Exception)
+ {
+ // do nothing
+ }
+ }
+ // If it hasn't been found (Windows 8 and up), fallback to the system
+ if (String.IsNullOrEmpty(_sLocalizedDisplayName))
+ {
+ // If its neutral use the language name
+ if (this.IsNeutralCulture)
+ {
+ _sLocalizedDisplayName = this.SLOCALIZEDLANGUAGE;
+ }
+ else
+ {
+ // Usually the UI culture shouldn't be different than what we got from WinRT except
+ // if DefaultThreadCurrentUICulture was set
+ CultureInfo ci;
+
+ if (CultureInfo.DefaultThreadCurrentUICulture != null &&
+ ((ci = GetUserDefaultCulture()) != null) &&
+ !CultureInfo.DefaultThreadCurrentUICulture.Name.Equals(ci.Name))
+ {
+ _sLocalizedDisplayName = this.SNATIVEDISPLAYNAME;
+ }
+ else
+ {
+ _sLocalizedDisplayName = GetLocaleInfo(LocaleStringData.LocalizedDisplayName);
+ }
+ }
+ }
+ }
+
+ return _sLocalizedDisplayName;
+ }
+ }
+
+ // English pretty name for this locale (ie: English (United States))
+ internal String SENGDISPLAYNAME
+ {
+ get
+ {
+ if (_sEnglishDisplayName == null)
+ {
+ // If its neutral use the language name
+ if (this.IsNeutralCulture)
+ {
+ _sEnglishDisplayName = this.SENGLISHLANGUAGE;
+ // differentiate the legacy display names
+ switch (_sName)
+ {
+ case "zh-CHS":
+ case "zh-CHT":
+ _sEnglishDisplayName += " Legacy";
+ break;
+ }
+ }
+ else
+ {
+ _sEnglishDisplayName = GetLocaleInfo(LocaleStringData.EnglishDisplayName);
+
+ // if it isn't found build one:
+ if (String.IsNullOrEmpty(_sEnglishDisplayName))
+ {
+ // Our existing names mostly look like:
+ // "English" + "United States" -> "English (United States)"
+ // "Azeri (Latin)" + "Azerbaijan" -> "Azeri (Latin, Azerbaijan)"
+ if (this.SENGLISHLANGUAGE[this.SENGLISHLANGUAGE.Length - 1] == ')')
+ {
+ // "Azeri (Latin)" + "Azerbaijan" -> "Azeri (Latin, Azerbaijan)"
+ _sEnglishDisplayName =
+ this.SENGLISHLANGUAGE.Substring(0, _sEnglishLanguage.Length - 1) +
+ ", " + this.SENGCOUNTRY + ")";
+ }
+ else
+ {
+ // "English" + "United States" -> "English (United States)"
+ _sEnglishDisplayName = this.SENGLISHLANGUAGE + " (" + this.SENGCOUNTRY + ")";
+ }
+ }
+ }
+ }
+ return _sEnglishDisplayName;
+ }
+ }
+
+ // Native pretty name for this locale (ie: Deutsch (Deutschland))
+ internal String SNATIVEDISPLAYNAME
+ {
+ get
+ {
+ if (_sNativeDisplayName == null)
+ {
+ // If its neutral use the language name
+ if (this.IsNeutralCulture)
+ {
+ _sNativeDisplayName = this.SNATIVELANGUAGE;
+ // differentiate the legacy display names
+ switch (_sName)
+ {
+ case "zh-CHS":
+ _sNativeDisplayName += " \u65E7\u7248";
+ break;
+ case "zh-CHT":
+ _sNativeDisplayName += " \u820A\u7248";
+ break;
+ }
+ }
+ else
+ {
+ _sNativeDisplayName = GetLocaleInfo(LocaleStringData.NativeDisplayName);
+
+ // if it isn't found build one:
+ if (String.IsNullOrEmpty(_sNativeDisplayName))
+ {
+ // These should primarily be "Deutsch (Deutschland)" type names
+ _sNativeDisplayName = this.SNATIVELANGUAGE + " (" + this.SNATIVECOUNTRY + ")";
+ }
+ }
+ }
+ return _sNativeDisplayName;
+ }
+ }
+
+ /////////////
+ // Language //
+ /////////////
+
+ // iso 639 language name, ie: en
+ internal String SISO639LANGNAME
+ {
+ get
+ {
+ if (_sISO639Language == null)
+ {
+ _sISO639Language = GetLocaleInfo(LocaleStringData.Iso639LanguageName);
+ }
+ return _sISO639Language;
+ }
+ }
+
+ // Localized name for this language (Windows Only) ie: Inglis
+ // This is only valid for Windows 8 and higher neutrals:
+ internal String SLOCALIZEDLANGUAGE
+ {
+ get
+ {
+ if (_sLocalizedLanguage == null)
+ {
+ // Usually the UI culture shouldn't be different than what we got from WinRT except
+ // if DefaultThreadCurrentUICulture was set
+ CultureInfo ci;
+
+ if (CultureInfo.DefaultThreadCurrentUICulture != null &&
+ ((ci = GetUserDefaultCulture()) != null) &&
+ !CultureInfo.DefaultThreadCurrentUICulture.Name.Equals(ci.Name))
+ {
+ _sLocalizedLanguage = SNATIVELANGUAGE;
+ }
+ else
+ {
+ _sLocalizedLanguage = GetLocaleInfo(LocaleStringData.LocalizedLanguageName);
+ }
+ }
+
+ return _sLocalizedLanguage;
+ }
+ }
+
+ // English name for this language (Windows Only) ie: German
+ internal String SENGLISHLANGUAGE
+ {
+ get
+ {
+ if (_sEnglishLanguage == null)
+ {
+ _sEnglishLanguage = GetLocaleInfo(LocaleStringData.EnglishLanguageName);
+ }
+ return _sEnglishLanguage;
+ }
+ }
+
+ // Native name of this language (Windows Only) ie: Deutsch
+ internal String SNATIVELANGUAGE
+ {
+ get
+ {
+ if (_sNativeLanguage == null)
+ {
+ _sNativeLanguage = GetLocaleInfo(LocaleStringData.NativeLanguageName);
+ }
+ return _sNativeLanguage;
+ }
+ }
+
+ ///////////
+ // Region //
+ ///////////
+
+ // region name (eg US)
+ internal String SREGIONNAME
+ {
+ get
+ {
+ if (_sRegionName == null)
+ {
+ _sRegionName = GetLocaleInfo(LocaleStringData.Iso3166CountryName);
+ }
+ return _sRegionName;
+ }
+ }
+
+
+ // localized name for the country
+ internal string SLOCALIZEDCOUNTRY
+ {
+ get
+ {
+ if (_sLocalizedCountry == null)
+ {
+ try
+ {
+ _sLocalizedCountry = GetRegionDisplayName(SISO3166CTRYNAME);
+ }
+ catch (Exception)
+ {
+ // do nothing. we'll fallback
+ }
+
+ if (_sLocalizedCountry == null)
+ {
+ _sLocalizedCountry = SNATIVECOUNTRY;
+ }
+ }
+ return _sLocalizedCountry;
+ }
+ }
+
+ // english country name (RegionInfo) ie: Germany
+ internal String SENGCOUNTRY
+ {
+ get
+ {
+ if (_sEnglishCountry == null)
+ {
+ _sEnglishCountry = GetLocaleInfo(LocaleStringData.EnglishCountryName);
+ }
+ return _sEnglishCountry;
+ }
+ }
+
+ // native country name (RegionInfo) ie: Deutschland
+ internal String SNATIVECOUNTRY
+ {
+ get
+ {
+ if (_sNativeCountry == null)
+ {
+ _sNativeCountry = GetLocaleInfo(LocaleStringData.NativeCountryName);
+ }
+ return _sNativeCountry;
+ }
+ }
+
+ // ISO 3166 Country Name
+ internal String SISO3166CTRYNAME
+ {
+ get
+ {
+ if (_sISO3166CountryName == null)
+ {
+ _sISO3166CountryName = GetLocaleInfo(LocaleStringData.Iso3166CountryName);
+ }
+ return _sISO3166CountryName;
+ }
+ }
+
+ /////////////
+ // Numbers //
+ ////////////
+
+ // internal String sPositiveSign ; // (user can override) positive sign
+ // internal String sNegativeSign ; // (user can override) negative sign
+ // internal String[] saNativeDigits ; // (user can override) native characters for digits 0-9
+ // internal int iDigits ; // (user can override) number of fractional digits
+ // internal int iNegativeNumber ; // (user can override) negative number format
+
+
+
+ // (user can override) grouping of digits
+ internal int[] WAGROUPING
+ {
+ get
+ {
+ if (_waGrouping == null)
+ {
+ _waGrouping = GetLocaleInfo(LocaleGroupingData.Digit);
+ }
+ return _waGrouping;
+ }
+ }
+
+
+ // internal String sDecimalSeparator ; // (user can override) decimal separator
+ // internal String sThousandSeparator ; // (user can override) thousands separator
+
+ // Not a Number
+ internal String SNAN
+ {
+ get
+ {
+ if (_sNaN == null)
+ {
+ _sNaN = GetLocaleInfo(LocaleStringData.NaNSymbol);
+ }
+ return _sNaN;
+ }
+ }
+
+ // + Infinity
+ internal String SPOSINFINITY
+ {
+ get
+ {
+ if (_sPositiveInfinity == null)
+ {
+ _sPositiveInfinity = GetLocaleInfo(LocaleStringData.PositiveInfinitySymbol);
+ }
+ return _sPositiveInfinity;
+ }
+ }
+
+ // - Infinity
+ internal String SNEGINFINITY
+ {
+ get
+ {
+ if (_sNegativeInfinity == null)
+ {
+ _sNegativeInfinity = GetLocaleInfo(LocaleStringData.NegativeInfinitySymbol);
+ }
+ return _sNegativeInfinity;
+ }
+ }
+
+
+ ////////////
+ // Percent //
+ ///////////
+
+ // Negative Percent (0-3)
+ internal int INEGATIVEPERCENT
+ {
+ get
+ {
+ if (_iNegativePercent == undef)
+ {
+ // Note that <= Windows Vista this is synthesized by native code
+ _iNegativePercent = GetLocaleInfo(LocaleNumberData.NegativePercentFormat);
+ }
+ return _iNegativePercent;
+ }
+ }
+
+ // Positive Percent (0-11)
+ internal int IPOSITIVEPERCENT
+ {
+ get
+ {
+ if (_iPositivePercent == undef)
+ {
+ // Note that <= Windows Vista this is synthesized by native code
+ _iPositivePercent = GetLocaleInfo(LocaleNumberData.PositivePercentFormat);
+ }
+ return _iPositivePercent;
+ }
+ }
+
+ // Percent (%) symbol
+ internal String SPERCENT
+ {
+ get
+ {
+ if (_sPercent == null)
+ {
+ _sPercent = GetLocaleInfo(LocaleStringData.PercentSymbol);
+ }
+ return _sPercent;
+ }
+ }
+
+ // PerMille symbol
+ internal String SPERMILLE
+ {
+ get
+ {
+ if (_sPerMille == null)
+ {
+ _sPerMille = GetLocaleInfo(LocaleStringData.PerMilleSymbol);
+ }
+ return _sPerMille;
+ }
+ }
+
+ /////////////
+ // Currency //
+ /////////////
+
+ // (user can override) local monetary symbol, eg: $
+ internal String SCURRENCY
+ {
+ get
+ {
+ if (_sCurrency == null)
+ {
+ _sCurrency = GetLocaleInfo(LocaleStringData.MonetarySymbol);
+ }
+ return _sCurrency;
+ }
+ }
+
+ // international monetary symbol (RegionInfo), eg: USD
+ internal String SINTLSYMBOL
+ {
+ get
+ {
+ if (_sIntlMonetarySymbol == null)
+ {
+ _sIntlMonetarySymbol = GetLocaleInfo(LocaleStringData.Iso4217MonetarySymbol);
+ }
+ return _sIntlMonetarySymbol;
+ }
+ }
+
+ // internal int iCurrencyDigits ; // (user can override) # local monetary fractional digits
+ // internal int iCurrency ; // (user can override) positive currency format
+ // internal int iNegativeCurrency ; // (user can override) negative currency format
+
+ // (user can override) monetary grouping of digits
+ internal int[] WAMONGROUPING
+ {
+ get
+ {
+ if (_waMonetaryGrouping == null)
+ {
+ _waMonetaryGrouping = GetLocaleInfo(LocaleGroupingData.Monetary);
+ }
+ return _waMonetaryGrouping;
+ }
+ }
+
+ // (user can override) system of measurement 0=metric, 1=US (RegionInfo)
+ internal int IMEASURE
+ {
+ get
+ {
+ if (_iMeasure == undef)
+ {
+ _iMeasure = GetLocaleInfo(LocaleNumberData.MeasurementSystem);
+ }
+ return _iMeasure;
+ }
+ }
+
+ // (user can override) list Separator
+ internal String SLIST
+ {
+ get
+ {
+ if (_sListSeparator == null)
+ {
+ _sListSeparator = GetLocaleInfo(LocaleStringData.ListSeparator);
+ }
+ return _sListSeparator;
+ }
+ }
+
+
+ ////////////////////////////
+ // Calendar/Time (Gregorian) //
+ ////////////////////////////
+
+ // (user can override) AM designator
+ internal String SAM1159
+ {
+ get
+ {
+ if (_sAM1159 == null)
+ {
+ _sAM1159 = GetLocaleInfo(LocaleStringData.AMDesignator);
+ }
+ return _sAM1159;
+ }
+ }
+
+ // (user can override) PM designator
+ internal String SPM2359
+ {
+ get
+ {
+ if (_sPM2359 == null)
+ {
+ _sPM2359 = GetLocaleInfo(LocaleStringData.PMDesignator);
+ }
+ return _sPM2359;
+ }
+ }
+
+ // (user can override) time format
+ internal String[] LongTimes
+ {
+ get
+ {
+ if (_saLongTimes == null)
+ {
+ String[] longTimes = GetTimeFormats();
+ if (longTimes == null || longTimes.Length == 0)
+ {
+ _saLongTimes = Invariant._saLongTimes;
+ }
+ else
+ {
+ _saLongTimes = longTimes;
+ }
+ }
+ return _saLongTimes;
+ }
+ }
+
+ // short time format
+ // Short times (derived from long times format)
+ // TODO: NLS Arrowhead - On Windows 7 we should have short times so this isn't necessary
+ internal String[] ShortTimes
+ {
+ get
+ {
+ if (_saShortTimes == null)
+ {
+ // Try to get the short times from the OS/culture.dll
+ String[] shortTimes = null;
+ shortTimes = GetShortTimeFormats();
+
+ if (shortTimes == null || shortTimes.Length == 0)
+ {
+ //
+ // If we couldn't find short times, then compute them from long times
+ // (eg: CORECLR on < Win7 OS & fallback for missing culture.dll)
+ //
+ shortTimes = DeriveShortTimesFromLong();
+ }
+
+ /* The above logic doesn't make sense on Mac, since the OS can provide us a "short time pattern".
+ * currently this is the 4th element in the array returned by LongTimes. We'll add this to our array
+ * if it doesn't exist.
+ */
+ shortTimes = AdjustShortTimesForMac(shortTimes);
+
+ // Found short times, use them
+ _saShortTimes = shortTimes;
+ }
+ return _saShortTimes;
+ }
+ }
+
+ private string[] AdjustShortTimesForMac(string[] shortTimes)
+ {
+ return shortTimes;
+ }
+
+ private string[] DeriveShortTimesFromLong()
+ {
+ // Our logic is to look for h,H,m,s,t. If we find an s, then we check the string
+ // between it and the previous marker, if any. If its a short, unescaped separator,
+ // then we don't retain that part.
+ // We then check after the ss and remove anything before the next h,H,m,t...
+ string[] shortTimes = new string[LongTimes.Length];
+
+ for (int i = 0; i < LongTimes.Length; i++)
+ {
+ shortTimes[i] = StripSecondsFromPattern(LongTimes[i]);
+ }
+ return shortTimes;
+ }
+
+ private static string StripSecondsFromPattern(string time)
+ {
+ bool bEscape = false;
+ int iLastToken = -1;
+
+ // Find the seconds
+ for (int j = 0; j < time.Length; j++)
+ {
+ // Change escape mode?
+ if (time[j] == '\'')
+ {
+ // Continue
+ bEscape = !bEscape;
+ continue;
+ }
+
+ // See if there was a single \
+ if (time[j] == '\\')
+ {
+ // Skip next char
+ j++;
+ continue;
+ }
+
+ if (bEscape)
+ {
+ continue;
+ }
+
+ switch (time[j])
+ {
+ // Check for seconds
+ case 's':
+ // Found seconds, see if there was something unescaped and short between
+ // the last marker and the seconds. Windows says separator can be a
+ // maximum of three characters (without null)
+ // If 1st or last characters were ', then ignore it
+ if ((j - iLastToken) <= 4 && (j - iLastToken) > 1 &&
+ (time[iLastToken + 1] != '\'') &&
+ (time[j - 1] != '\''))
+ {
+ // There was something there we want to remember
+ if (iLastToken >= 0)
+ {
+ j = iLastToken + 1;
+ }
+ }
+
+ bool containsSpace;
+ int endIndex = GetIndexOfNextTokenAfterSeconds(time, j, out containsSpace);
+
+ string sep;
+
+ if (containsSpace)
+ {
+ sep = " ";
+ }
+ else
+ {
+ sep = "";
+ }
+
+ time = time.Substring(0, j) + sep + time.Substring(endIndex);
+ break;
+ case 'm':
+ case 'H':
+ case 'h':
+ iLastToken = j;
+ break;
+ }
+ }
+ return time;
+ }
+
+ private static int GetIndexOfNextTokenAfterSeconds(string time, int index, out bool containsSpace)
+ {
+ bool bEscape = false;
+ containsSpace = false;
+ for (; index < time.Length; index++)
+ {
+ switch (time[index])
+ {
+ case '\'':
+ bEscape = !bEscape;
+ continue;
+ case '\\':
+ index++;
+ if (time[index] == ' ')
+ {
+ containsSpace = true;
+ }
+ continue;
+ case ' ':
+ containsSpace = true;
+ break;
+ case 't':
+ case 'm':
+ case 'H':
+ case 'h':
+ if (bEscape)
+ {
+ continue;
+ }
+ return index;
+ }
+ }
+ containsSpace = false;
+ return index;
+ }
+
+ // (user can override) first day of week
+ internal int IFIRSTDAYOFWEEK
+ {
+ get
+ {
+ if (_iFirstDayOfWeek == undef)
+ {
+ _iFirstDayOfWeek = GetFirstDayOfWeek();
+ }
+ return _iFirstDayOfWeek;
+ }
+ }
+
+ // (user can override) first week of year
+ internal int IFIRSTWEEKOFYEAR
+ {
+ get
+ {
+ if (_iFirstWeekOfYear == undef)
+ {
+ _iFirstWeekOfYear = GetLocaleInfo(LocaleNumberData.FirstWeekOfYear);
+ }
+ return _iFirstWeekOfYear;
+ }
+ }
+
+ // (user can override default only) short date format
+ internal String[] ShortDates(CalendarId calendarId)
+ {
+ return GetCalendar(calendarId).saShortDates;
+ }
+
+ // (user can override default only) long date format
+ internal String[] LongDates(CalendarId calendarId)
+ {
+ return GetCalendar(calendarId).saLongDates;
+ }
+
+ // (user can override) date year/month format.
+ internal String[] YearMonths(CalendarId calendarId)
+ {
+ return GetCalendar(calendarId).saYearMonths;
+ }
+
+ // day names
+ internal string[] DayNames(CalendarId calendarId)
+ {
+ return GetCalendar(calendarId).saDayNames;
+ }
+
+ // abbreviated day names
+ internal string[] AbbreviatedDayNames(CalendarId calendarId)
+ {
+ // Get abbreviated day names for this calendar from the OS if necessary
+ return GetCalendar(calendarId).saAbbrevDayNames;
+ }
+
+ // The super short day names
+ internal string[] SuperShortDayNames(CalendarId calendarId)
+ {
+ return GetCalendar(calendarId).saSuperShortDayNames;
+ }
+
+ // month names
+ internal string[] MonthNames(CalendarId calendarId)
+ {
+ return GetCalendar(calendarId).saMonthNames;
+ }
+
+ // Genitive month names
+ internal string[] GenitiveMonthNames(CalendarId calendarId)
+ {
+ return GetCalendar(calendarId).saMonthGenitiveNames;
+ }
+
+ // month names
+ internal string[] AbbreviatedMonthNames(CalendarId calendarId)
+ {
+ return GetCalendar(calendarId).saAbbrevMonthNames;
+ }
+
+ // Genitive month names
+ internal string[] AbbreviatedGenitiveMonthNames(CalendarId calendarId)
+ {
+ return GetCalendar(calendarId).saAbbrevMonthGenitiveNames;
+ }
+
+ // Leap year month names
+ // Note: This only applies to Hebrew, and it basically adds a "1" to the 6th month name
+ // the non-leap names skip the 7th name in the normal month name array
+ internal string[] LeapYearMonthNames(CalendarId calendarId)
+ {
+ return GetCalendar(calendarId).saLeapYearMonthNames;
+ }
+
+ // month/day format (single string, no override)
+ internal String MonthDay(CalendarId calendarId)
+ {
+ return GetCalendar(calendarId).sMonthDay;
+ }
+
+
+
+ /////////////
+ // Calendars //
+ /////////////
+
+ // all available calendar type(s), The first one is the default calendar.
+ internal CalendarId[] CalendarIds
+ {
+ get
+ {
+ if (_waCalendars == null)
+ {
+ // We pass in an array of ints, and native side fills it up with count calendars.
+ // We then have to copy that list to a new array of the right size.
+ // Default calendar should be first
+ CalendarId[] calendars = new CalendarId[23];
+ Contract.Assert(_sWindowsName != null, "[CultureData.CalendarIds] Expected _sWindowsName to be populated by already");
+ int count = CalendarData.GetCalendars(_sWindowsName, _bUseOverrides, calendars);
+
+ // See if we had a calendar to add.
+ if (count == 0)
+ {
+ // Failed for some reason, just grab Gregorian from Invariant
+ _waCalendars = Invariant._waCalendars;
+ }
+ else
+ {
+ // The OS may not return calendar 4 for zh-TW, but we've always allowed it.
+ // TODO: Is this hack necessary long-term?
+ if (_sWindowsName == "zh-TW")
+ {
+ bool found = false;
+
+ // Do we need to insert calendar 4?
+ for (int i = 0; i < count; i++)
+ {
+ // Stop if we found calendar four
+ if (calendars[i] == CalendarId.TAIWAN)
+ {
+ found = true;
+ break;
+ }
+ }
+
+ // If not found then insert it
+ if (!found)
+ {
+ // Insert it as the 2nd calendar
+ count++;
+ // Copy them from the 2nd position to the end, -1 for skipping 1st, -1 for one being added.
+ Array.Copy(calendars, 1, calendars, 2, 23 - 1 - 1);
+ calendars[1] = CalendarId.TAIWAN;
+ }
+ }
+
+ // It worked, remember the list
+ CalendarId[] temp = new CalendarId[count];
+ Array.Copy(calendars, temp, count);
+
+ // Want 1st calendar to be default
+ // Prior to Vista the enumeration didn't have default calendar first
+ if (temp.Length > 1)
+ {
+ CalendarId i = (CalendarId)GetLocaleInfo(LocaleNumberData.CalendarType);
+ if (temp[1] == i)
+ {
+ temp[1] = temp[0];
+ temp[0] = i;
+ }
+ }
+
+ _waCalendars = temp;
+ }
+ }
+
+ return _waCalendars;
+ }
+ }
+
+ internal CalendarData GetCalendar(CalendarId calendarId)
+ {
+ Contract.Assert(calendarId > 0 && calendarId <= CalendarId.LAST_CALENDAR,
+ "[CultureData.GetCalendar] Expect calendarId to be in a valid range");
+
+ // arrays are 0 based, calendarIds are 1 based
+ int calendarIndex = (int)calendarId - 1;
+
+ // Have to have calendars
+ if (_calendars == null)
+ {
+ _calendars = new CalendarData[CalendarData.MAX_CALENDARS];
+ }
+
+ // we need the following local variable to avoid returning null
+ // when another thread creates a new array of CalendarData (above)
+ // right after we insert the newly created CalendarData (below)
+ CalendarData calendarData = _calendars[calendarIndex];
+ // Make sure that calendar has data
+ if (calendarData == null)
+ {
+ Contract.Assert(_sWindowsName != null, "[CultureData.GetCalendar] Expected _sWindowsName to be populated by already");
+ calendarData = new CalendarData(_sWindowsName, calendarId, this.UseUserOverride);
+ _calendars[calendarIndex] = calendarData;
+ }
+
+ return calendarData;
+ }
+
+ ///////////////////
+ // Text Information //
+ ///////////////////
+
+ // IsRightToLeft
+ internal bool IsRightToLeft
+ {
+ get
+ {
+ // Returns one of the following 4 reading layout values:
+ // 0 - Left to right (eg en-US)
+ // 1 - Right to left (eg arabic locales)
+ // 2 - Vertical top to bottom with columns to the left and also left to right (ja-JP locales)
+ // 3 - Vertical top to bottom with columns proceeding to the right
+ return (this.IREADINGLAYOUT == 1);
+ }
+ }
+
+ // IREADINGLAYOUT
+ // Returns one of the following 4 reading layout values:
+ // 0 - Left to right (eg en-US)
+ // 1 - Right to left (eg arabic locales)
+ // 2 - Vertical top to bottom with columns to the left and also left to right (ja-JP locales)
+ // 3 - Vertical top to bottom with columns proceeding to the right
+ //
+ // If exposed as a public API, we'd have an enum with those 4 values
+ private int IREADINGLAYOUT
+ {
+ get
+ {
+ if (_iReadingLayout == undef)
+ {
+ Contract.Assert(_sRealName != null, "[CultureData.IsRightToLeft] Expected _sRealName to be populated by already");
+ _iReadingLayout = GetLocaleInfo(LocaleNumberData.ReadingLayout);
+ }
+
+ return (_iReadingLayout);
+ }
+ }
+
+ // The TextInfo name never includes that alternate sort and is always specific
+ // For customs, it uses the SortLocale (since the textinfo is not exposed in Win7)
+ // en -> en-US
+ // en-US -> en-US
+ // fj (custom neutral) -> en-US (assuming that en-US is the sort locale for fj)
+ // fj_FJ (custom specific) -> en-US (assuming that en-US is the sort locale for fj-FJ)
+ // es-ES_tradnl -> es-ES
+ internal String STEXTINFO // Text info name to use for text information
+ {
+ get
+ {
+ // Note: Custom cultures might point at another culture's textinfo, however windows knows how
+ // to redirect it to the desired textinfo culture, so this is OK.
+ Contract.Assert(_sWindowsName != null, "[CultureData.STEXTINFO] Expected _sWindowsName to be populated by already");
+ return (_sWindowsName);
+ }
+ }
+
+ // Compare info name (including sorting key) to use if custom
+ internal String SCOMPAREINFO
+ {
+ get
+ {
+ Contract.Assert(_sWindowsName != null, "[CultureData.SCOMPAREINFO] Expected _sWindowsName to be populated by already");
+ return (_sWindowsName);
+ }
+ }
+
+ internal bool IsSupplementalCustomCulture
+ {
+ get
+ {
+ return IsCustomCultureId(this.ILANGUAGE);
+ }
+ }
+
+ internal int ILANGUAGE
+ {
+ get
+ {
+ return _iLanguage;
+ }
+ }
+
+ internal bool IsNeutralCulture
+ {
+ get
+ {
+ // InitCultureData told us if we're neutral or not
+ return _bNeutral;
+ }
+ }
+
+ internal bool IsInvariantCulture
+ {
+ get
+ {
+ return String.IsNullOrEmpty(this.SNAME);
+ }
+ }
+
+ // Get an instance of our default calendar
+ internal Calendar DefaultCalendar
+ {
+ get
+ {
+ CalendarId defaultCalId = (CalendarId)GetLocaleInfo(LocaleNumberData.CalendarType);
+
+ if (defaultCalId == 0)
+ {
+ defaultCalId = this.CalendarIds[0];
+ }
+
+ return CultureInfo.GetCalendarInstance(defaultCalId);
+ }
+ }
+
+ // All of our era names
+ internal String[] EraNames(CalendarId calendarId)
+ {
+ Contract.Assert(calendarId > 0, "[CultureData.saEraNames] Expected Calendar.ID > 0");
+
+ return this.GetCalendar(calendarId).saEraNames;
+ }
+
+ internal String[] AbbrevEraNames(CalendarId calendarId)
+ {
+ Contract.Assert(calendarId > 0, "[CultureData.saAbbrevEraNames] Expected Calendar.ID > 0");
+
+ return this.GetCalendar(calendarId).saAbbrevEraNames;
+ }
+
+ internal String[] AbbreviatedEnglishEraNames(CalendarId calendarId)
+ {
+ Contract.Assert(calendarId > 0, "[CultureData.saAbbrevEraNames] Expected Calendar.ID > 0");
+
+ return this.GetCalendar(calendarId).saAbbrevEnglishEraNames;
+ }
+
+ //// String array DEFAULTS
+ //// Note: GetDTFIOverrideValues does the user overrides for these, so we don't have to.
+
+
+ // Time separator (derived from time format)
+ internal String TimeSeparator
+ {
+ get
+ {
+ if (_sTimeSeparator == null)
+ {
+ string longTimeFormat = GetTimeFormatString();
+ if (String.IsNullOrEmpty(longTimeFormat))
+ {
+ longTimeFormat = LongTimes[0];
+ }
+
+ // Compute STIME from time format
+ _sTimeSeparator = GetTimeSeparator(longTimeFormat);
+ }
+ return _sTimeSeparator;
+ }
+ }
+
+ // Date separator (derived from short date format)
+ internal String DateSeparator(CalendarId calendarId)
+ {
+ return GetDateSeparator(ShortDates(calendarId)[0]);
+ }
+
+ //////////////////////////////////////
+ // Helper Functions to get derived properties //
+ //////////////////////////////////////
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Unescape a NLS style quote string
+ //
+ // This removes single quotes:
+ // 'fred' -> fred
+ // 'fred -> fred
+ // fred' -> fred
+ // fred's -> freds
+ //
+ // This removes the first \ of escaped characters:
+ // fred\'s -> fred's
+ // a\\b -> a\b
+ // a\b -> ab
+ //
+ // We don't build the stringbuilder unless we find a ' or a \. If we find a ' or a \, we
+ // always build a stringbuilder because we need to remove the ' or \.
+ //
+ ////////////////////////////////////////////////////////////////////////////
+ private static String UnescapeNlsString(String str, int start, int end)
+ {
+ Contract.Requires(str != null);
+ Contract.Requires(start >= 0);
+ Contract.Requires(end >= 0);
+ StringBuilder result = null;
+
+ for (int i = start; i < str.Length && i <= end; i++)
+ {
+ switch (str[i])
+ {
+ case '\'':
+ if (result == null)
+ {
+ result = new StringBuilder(str, start, i - start, str.Length);
+ }
+ break;
+ case '\\':
+ if (result == null)
+ {
+ result = new StringBuilder(str, start, i - start, str.Length);
+ }
+ ++i;
+ if (i < str.Length)
+ {
+ result.Append(str[i]);
+ }
+ break;
+ default:
+ if (result != null)
+ {
+ result.Append(str[i]);
+ }
+ break;
+ }
+ }
+
+ if (result == null)
+ return (str.Substring(start, end - start + 1));
+
+ return (result.ToString());
+ }
+
+ private static String GetTimeSeparator(String format)
+ {
+ // Time format separator (ie: : in 12:39:00)
+ //
+ // We calculate this from the provided time format
+ //
+
+ //
+ // Find the time separator so that we can pretend we know STIME.
+ //
+ return GetSeparator(format, "Hhms");
+ }
+
+ private static String GetDateSeparator(String format)
+ {
+ // Date format separator (ie: / in 9/1/03)
+ //
+ // We calculate this from the provided short date
+ //
+
+ //
+ // Find the date separator so that we can pretend we know SDATE.
+ //
+ return GetSeparator(format, "dyM");
+ }
+
+ private static string GetSeparator(string format, string timeParts)
+ {
+ int index = IndexOfTimePart(format, 0, timeParts);
+
+ if (index != -1)
+ {
+ // Found a time part, find out when it changes
+ char cTimePart = format[index];
+
+ do
+ {
+ index++;
+ } while (index < format.Length && format[index] == cTimePart);
+
+ int separatorStart = index;
+
+ // Now we need to find the end of the separator
+ if (separatorStart < format.Length)
+ {
+ int separatorEnd = IndexOfTimePart(format, separatorStart, timeParts);
+ if (separatorEnd != -1)
+ {
+ // From [separatorStart, count) is our string, except we need to unescape
+ return UnescapeNlsString(format, separatorStart, separatorEnd - 1);
+ }
+ }
+ }
+
+ return String.Empty;
+ }
+
+ private static int IndexOfTimePart(string format, int startIndex, string timeParts)
+ {
+ Contract.Assert(startIndex >= 0, "startIndex cannot be negative");
+ Contract.Assert(timeParts.IndexOfAny(new char[] { '\'', '\\' }) == -1, "timeParts cannot include quote characters");
+ bool inQuote = false;
+ for (int i = startIndex; i < format.Length; ++i)
+ {
+ // See if we have a time Part
+ if (!inQuote && timeParts.IndexOf(format[i]) != -1)
+ {
+ return i;
+ }
+ switch (format[i])
+ {
+ case '\\':
+ if (i + 1 < format.Length)
+ {
+ ++i;
+ switch (format[i])
+ {
+ case '\'':
+ case '\\':
+ break;
+ default:
+ --i; //backup since we will move over this next
+ break;
+ }
+ }
+ break;
+ case '\'':
+ inQuote = !inQuote;
+ break;
+ }
+ }
+
+ return -1;
+ }
+
+ private static bool IsCustomCultureId(int cultureId)
+ {
+ return (cultureId == LOCALE_CUSTOM_DEFAULT || cultureId == LOCALE_CUSTOM_UNSPECIFIED);
+ }
+
+ internal void GetNFIValues(NumberFormatInfo nfi)
+ {
+ if (this.IsInvariantCulture)
+ {
+ // FUTURE: NumberFormatInfo already has default values for many of these fields. Can we not do this?
+ // if we do need to do this, then why don't we set nfi.nativeDigits in this case?
+ nfi.positiveSign = _sPositiveSign;
+ nfi.negativeSign = _sNegativeSign;
+
+ nfi.numberGroupSeparator = _sThousandSeparator;
+ nfi.numberDecimalSeparator = _sDecimalSeparator;
+ nfi.numberDecimalDigits = _iDigits;
+ nfi.numberNegativePattern = _iNegativeNumber;
+
+ nfi.currencySymbol = _sCurrency;
+ nfi.currencyGroupSeparator = _sMonetaryThousand;
+ nfi.currencyDecimalSeparator = _sMonetaryDecimal;
+ nfi.currencyDecimalDigits = _iCurrencyDigits;
+ nfi.currencyNegativePattern = _iNegativeCurrency;
+ nfi.currencyPositivePattern = _iCurrency;
+ }
+ else
+ {
+ Contract.Assert(_sWindowsName != null, "[CultureData.GetNFIValues] Expected _sWindowsName to be populated by already");
+ // String values
+ nfi.positiveSign = GetLocaleInfo(LocaleStringData.PositiveSign);
+ nfi.negativeSign = GetLocaleInfo(LocaleStringData.NegativeSign);
+
+ nfi.numberDecimalSeparator = GetLocaleInfo(LocaleStringData.DecimalSeparator);
+ nfi.numberGroupSeparator = GetLocaleInfo(LocaleStringData.ThousandSeparator);
+ nfi.currencyGroupSeparator = GetLocaleInfo(LocaleStringData.MonetaryThousandSeparator);
+ nfi.currencyDecimalSeparator = GetLocaleInfo(LocaleStringData.MonetaryDecimalSeparator);
+ nfi.currencySymbol = GetLocaleInfo(LocaleStringData.MonetarySymbol);
+
+ // Numeric values
+ nfi.numberDecimalDigits = GetLocaleInfo(LocaleNumberData.FractionalDigitsCount);
+ nfi.currencyDecimalDigits = GetLocaleInfo(LocaleNumberData.MonetaryFractionalDigitsCount);
+ nfi.currencyPositivePattern = GetLocaleInfo(LocaleNumberData.PositiveMonetaryNumberFormat);
+ nfi.currencyNegativePattern = GetLocaleInfo(LocaleNumberData.NegativeMonetaryNumberFormat);
+ nfi.numberNegativePattern = GetLocaleInfo(LocaleNumberData.NegativeNumberFormat);
+
+ // LOCALE_SNATIVEDIGITS (array of 10 single character strings).
+ string digits = GetLocaleInfo(LocaleStringData.Digits);
+ nfi.nativeDigits = new string[10];
+ for (int i = 0; i < nfi.nativeDigits.Length; i++)
+ {
+ nfi.nativeDigits[i] = new string(digits[i], 1);
+ }
+ }
+
+ //
+ // Gather additional data
+ //
+ nfi.numberGroupSizes = this.WAGROUPING;
+ nfi.currencyGroupSizes = this.WAMONGROUPING;
+
+ // prefer the cached value since these do not have user overrides
+ nfi.percentNegativePattern = this.INEGATIVEPERCENT;
+ nfi.percentPositivePattern = this.IPOSITIVEPERCENT;
+ nfi.percentSymbol = this.SPERCENT;
+ nfi.perMilleSymbol = this.SPERMILLE;
+
+ nfi.negativeInfinitySymbol = this.SNEGINFINITY;
+ nfi.positiveInfinitySymbol = this.SPOSINFINITY;
+ nfi.nanSymbol = this.SNAN;
+
+ //
+ // We don't have percent values, so use the number values
+ //
+ nfi.percentDecimalDigits = nfi.numberDecimalDigits;
+ nfi.percentDecimalSeparator = nfi.numberDecimalSeparator;
+ nfi.percentGroupSizes = nfi.numberGroupSizes;
+ nfi.percentGroupSeparator = nfi.numberGroupSeparator;
+
+ //
+ // Clean up a few odd values
+ //
+
+ // Windows usually returns an empty positive sign, but we like it to be "+"
+ if (nfi.positiveSign == null || nfi.positiveSign.Length == 0) nfi.positiveSign = "+";
+
+ //Special case for Italian. The currency decimal separator in the control panel is the empty string. When the user
+ //specifies C4 as the currency format, this results in the number apparently getting multiplied by 10000 because the
+ //decimal point doesn't show up. We'll just hack this here because our default currency format will never use nfi.
+ if (nfi.currencyDecimalSeparator == null || nfi.currencyDecimalSeparator.Length == 0)
+ {
+ nfi.currencyDecimalSeparator = nfi.numberDecimalSeparator;
+ }
+ }
+
+ // Helper
+ // This is ONLY used for caching names and shouldn't be used for anything else
+ internal static string AnsiToLower(string testString)
+ {
+ StringBuilder sb = new StringBuilder(testString.Length);
+
+ for (int ich = 0; ich < testString.Length; ich++)
+ {
+ char ch = testString[ich];
+ sb.Append(ch <= 'Z' && ch >= 'A' ? (char)(ch - 'A' + 'a') : ch);
+ }
+
+ return (sb.ToString());
+ }
+
+ /// <remarks>
+ /// The numeric values of the enum members match their Win32 counterparts. The CultureData Win32 PAL implementation
+ /// takes a dependency on this fact, in order to prevent having to construct a mapping from internal values to LCTypes.
+ /// </remarks>
+ private enum LocaleStringData : uint
+ {
+ /// <summary>localized name of locale, eg "German (Germany)" in UI language (coresponds to LOCALE_SLOCALIZEDDISPLAYNAME)</summary>
+ LocalizedDisplayName = 0x00000002,
+ /// <summary>Display name (language + country usually) in English, eg "German (Germany)" (coresponds to LOCALE_SENGLISHDISPLAYNAME)</summary>
+ EnglishDisplayName = 0x00000072,
+ /// <summary>Display name in native locale language, eg "Deutsch (Deutschland) (coresponds to LOCALE_SNATIVEDISPLAYNAME)</summary>
+ NativeDisplayName = 0x00000073,
+ /// <summary>Language Display Name for a language, eg "German" in UI language (coresponds to LOCALE_SLOCALIZEDLANGUAGENAME)</summary>
+ LocalizedLanguageName = 0x0000006f,
+ /// <summary>English name of language, eg "German" (coresponds to LOCALE_SENGLISHLANGUAGENAME)</summary>
+ EnglishLanguageName = 0x00001001,
+ /// <summary>native name of language, eg "Deutsch" (coresponds to LOCALE_SNATIVELANGUAGENAME)</summary>
+ NativeLanguageName = 0x00000004,
+ /// <summary>English name of country, eg "Germany" (coresponds to LOCALE_SENGLISHCOUNTRYNAME)</summary>
+ EnglishCountryName = 0x00001002,
+ /// <summary>native name of country, eg "Deutschland" (coresponds to LOCALE_SNATIVECOUNTRYNAME)</summary>
+ NativeCountryName = 0x00000008,
+ /// <summary>list item separator (coresponds to LOCALE_SLIST)</summary>
+ ListSeparator = 0x0000000C,
+ /// <summary>decimal separator (coresponds to LOCALE_SDECIMAL)</summary>
+ DecimalSeparator = 0x0000000E,
+ /// <summary>thousand separator (coresponds to LOCALE_STHOUSAND)</summary>
+ ThousandSeparator = 0x0000000F,
+ /// <summary>digit grouping (coresponds to LOCALE_SGROUPING)</summary>
+ Digits = 0x00000013,
+ /// <summary>local monetary symbol (coresponds to LOCALE_SCURRENCY)</summary>
+ MonetarySymbol = 0x00000014,
+ /// <summary>uintl monetary symbol (coresponds to LOCALE_SINTLSYMBOL)</summary>
+ Iso4217MonetarySymbol = 0x00000015,
+ /// <summary>monetary decimal separator (coresponds to LOCALE_SMONDECIMALSEP)</summary>
+ MonetaryDecimalSeparator = 0x00000016,
+ /// <summary>monetary thousand separator (coresponds to LOCALE_SMONTHOUSANDSEP)</summary>
+ MonetaryThousandSeparator = 0x00000017,
+ /// <summary>AM designator (coresponds to LOCALE_S1159)</summary>
+ AMDesignator = 0x00000028,
+ /// <summary>PM designator (coresponds to LOCALE_S2359)</summary>
+ PMDesignator = 0x00000029,
+ /// <summary>positive sign (coresponds to LOCALE_SPOSITIVESIGN)</summary>
+ PositiveSign = 0x00000050,
+ /// <summary>negative sign (coresponds to LOCALE_SNEGATIVESIGN)</summary>
+ NegativeSign = 0x00000051,
+ /// <summary>ISO abbreviated language name (coresponds to LOCALE_SISO639LANGNAME)</summary>
+ Iso639LanguageName = 0x00000059,
+ /// <summary>ISO abbreviated country name (coresponds to LOCALE_SISO3166CTRYNAME)</summary>
+ Iso3166CountryName = 0x0000005A,
+ /// <summary>Not a Number (coresponds to LOCALE_SNAN)</summary>
+ NaNSymbol = 0x00000069,
+ /// <summary>+ Infinity (coresponds to LOCALE_SPOSINFINITY)</summary>
+ PositiveInfinitySymbol = 0x0000006a,
+ /// <summary>- Infinity (coresponds to LOCALE_SNEGINFINITY)</summary>
+ NegativeInfinitySymbol = 0x0000006b,
+ /// <summary>Fallback name for resources (coresponds to LOCALE_SPARENT)</summary>
+ ParentName = 0x0000006d,
+ /// <summary>Returns the percent symbol (coresponds to LOCALE_SPERCENT)</summary>
+ PercentSymbol = 0x00000076,
+ /// <summary>Returns the permille (U+2030) symbol (coresponds to LOCALE_SPERMILLE)</summary>
+ PerMilleSymbol = 0x00000077
+ }
+
+ /// <remarks>
+ /// The numeric values of the enum members match their Win32 counterparts. The CultureData Win32 PAL implementation
+ /// takes a dependency on this fact, in order to prevent having to construct a mapping from internal values to LCTypes.
+ /// </remarks>
+ private enum LocaleGroupingData : uint
+ {
+ /// <summary>digit grouping (coresponds to LOCALE_SGROUPING)</summary>
+ Digit = 0x00000010,
+ /// <summary>monetary grouping (coresponds to LOCALE_SMONGROUPING)</summary>
+ Monetary = 0x00000018,
+ }
+
+ /// <remarks>
+ /// The numeric values of the enum members match their Win32 counterparts. The CultureData Win32 PAL implementation
+ /// takes a dependency on this fact, in order to prevent having to construct a mapping from internal values to LCTypes.
+ /// </remarks>
+ private enum LocaleNumberData : uint
+ {
+ /// <summary>language id (coresponds to LOCALE_ILANGUAGE)</summary>
+ LanguageId = 0x00000001,
+ /// <summary>0 = metric, 1 = US (coresponds to LOCALE_IMEASURE)</summary>
+ MeasurementSystem = 0x0000000D,
+ /// <summary>number of fractional digits (coresponds to LOCALE_IDIGITS)</summary>
+ FractionalDigitsCount = 0x00000011,
+ /// <summary>negative number mode (coresponds to LOCALE_INEGNUMBER)</summary>
+ NegativeNumberFormat = 0x00001010,
+ /// <summary># local monetary digits (coresponds to LOCALE_ICURRDIGITS)</summary>
+ MonetaryFractionalDigitsCount = 0x00000019,
+ /// <summary>positive currency mode (coresponds to LOCALE_ICURRENCY)</summary>
+ PositiveMonetaryNumberFormat = 0x0000001B,
+ /// <summary>negative currency mode (coresponds to LOCALE_INEGCURR)</summary>
+ NegativeMonetaryNumberFormat = 0x0000001C,
+ /// <summary>type of calendar specifier (coresponds to LOCALE_ICALENDARTYPE)</summary>
+ CalendarType = 0x00001009,
+ /// <summary>first day of week specifier (coresponds to LOCALE_IFIRSTDAYOFWEEK)</summary>
+ FirstDayOfWeek = 0x0000100C,
+ /// <summary>first week of year specifier (coresponds to LOCALE_IFIRSTWEEKOFYEAR)</summary>
+ FirstWeekOfYear = 0x0000100D,
+ /// <summary>
+ /// Returns one of the following 4 reading layout values:
+ /// 0 - Left to right (eg en-US)
+ /// 1 - Right to left (eg arabic locales)
+ /// 2 - Vertical top to bottom with columns to the left and also left to right (ja-JP locales)
+ /// 3 - Vertical top to bottom with columns proceeding to the right
+ /// (coresponds to LOCALE_IREADINGLAYOUT)
+ /// </summary>
+ ReadingLayout = 0x00000070,
+ /// <summary>Returns 0-11 for the negative percent format (coresponds to LOCALE_INEGATIVEPERCENT)</summary>
+ NegativePercentFormat = 0x00000074,
+ /// <summary>Returns 0-3 for the positive percent format (coresponds to LOCALE_IPOSITIVEPERCENT)</summary>
+ PositivePercentFormat = 0x00000075
+ }
+ }
+}
diff --git a/src/mscorlib/corefx/System/Globalization/CultureInfo.Unix.cs b/src/mscorlib/corefx/System/Globalization/CultureInfo.Unix.cs
new file mode 100644
index 0000000000..6911688b08
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/CultureInfo.Unix.cs
@@ -0,0 +1,31 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.Globalization
+{
+ public partial class CultureInfo : IFormatProvider
+ {
+ private static CultureInfo GetUserDefaultCultureCacheOverride()
+ {
+ return null; // ICU doesn't provide a user override
+ }
+
+ internal static CultureInfo GetUserDefaultCulture()
+ {
+ CultureInfo cultureInfo = null;
+ string localeName;
+ if (CultureData.GetDefaultLocaleName(out localeName))
+ {
+ cultureInfo = GetCultureByName(localeName, true);
+ cultureInfo.m_isReadOnly = true;
+ }
+ else
+ {
+ cultureInfo = CultureInfo.InvariantCulture;
+ }
+
+ return cultureInfo;
+ }
+ }
+}
diff --git a/src/mscorlib/corefx/System/Globalization/CultureInfo.Windows.cs b/src/mscorlib/corefx/System/Globalization/CultureInfo.Windows.cs
new file mode 100644
index 0000000000..16c8a06e08
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/CultureInfo.Windows.cs
@@ -0,0 +1,53 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Internal.Runtime.Augments;
+
+namespace System.Globalization
+{
+ public partial class CultureInfo : IFormatProvider
+ {
+ /// <summary>
+ /// Gets the default user culture from WinRT, if available.
+ /// </summary>
+ /// <remarks>
+ /// This method may return null, if there is no default user culture or if WinRT isn't available.
+ /// </remarks>
+ private static CultureInfo GetUserDefaultCultureCacheOverride()
+ {
+ WinRTInteropCallbacks callbacks = WinRTInterop.UnsafeCallbacks;
+ if (callbacks != null && callbacks.IsAppxModel())
+ {
+ return (CultureInfo)callbacks.GetUserDefaultCulture();
+ }
+
+ return null;
+ }
+
+ private static CultureInfo GetUserDefaultCulture()
+ {
+ const uint LOCALE_SNAME = 0x0000005c;
+ const string LOCALE_NAME_USER_DEFAULT = null;
+ const string LOCALE_NAME_SYSTEM_DEFAULT = "!x-sys-default-locale";
+
+ string strDefault = Interop.mincore.GetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT, LOCALE_SNAME);
+ if (strDefault == null)
+ {
+ strDefault = Interop.mincore.GetLocaleInfoEx(LOCALE_NAME_SYSTEM_DEFAULT, LOCALE_SNAME);
+
+ if (strDefault == null)
+ {
+ // If system default doesn't work, use invariant
+ return CultureInfo.InvariantCulture;
+ }
+ }
+
+ CultureInfo temp = GetCultureByName(strDefault, true);
+
+ temp._isReadOnly = true;
+
+ return temp;
+ }
+ }
+}
diff --git a/src/mscorlib/corefx/System/Globalization/CultureInfo.cs b/src/mscorlib/corefx/System/Globalization/CultureInfo.cs
new file mode 100644
index 0000000000..f2b3742ab4
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/CultureInfo.cs
@@ -0,0 +1,1144 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+////////////////////////////////////////////////////////////////////////////
+//
+//
+//
+// Purpose: This class represents the software preferences of a particular
+// culture or community. It includes information such as the
+// language, writing system, and a calendar used by the culture
+// as well as methods for common operations such as printing
+// dates and sorting strings.
+//
+//
+//
+// !!!! NOTE WHEN CHANGING THIS CLASS !!!!
+//
+// If adding or removing members to this class, please update CultureInfoBaseObject
+// in ndp/clr/src/vm/object.h. Note, the "actual" layout of the class may be
+// different than the order in which members are declared. For instance, all
+// reference types will come first in the class before value types (like ints, bools, etc)
+// regardless of the order in which they are declared. The best way to see the
+// actual order of the class is to do a !dumpobj on an instance of the managed
+// object inside of the debugger.
+//
+////////////////////////////////////////////////////////////////////////////
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Diagnostics.Contracts;
+using System.Runtime;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.Serialization;
+using System.Security;
+using System.Threading;
+
+namespace System.Globalization
+{
+
+#if INSIDE_CLR
+ using StringCultureInfoDictionary = Dictionary<string, CultureInfo>;
+ using Lock = Object;
+#else
+ using StringCultureInfoDictionary = LowLevelDictionary<string, CultureInfo>;
+#endif
+
+ [Serializable]
+ public partial class CultureInfo : IFormatProvider, ICloneable
+ {
+ //--------------------------------------------------------------------//
+ // Internal Information //
+ //--------------------------------------------------------------------//
+
+ //--------------------------------------------------------------------//
+ // Data members to be serialized:
+ //--------------------------------------------------------------------//
+
+ // We use an RFC4646 type string to construct CultureInfo.
+ // This string is stored in m_name and is authoritative.
+ // We use the m_cultureData to get the data for our object
+
+ private bool m_isReadOnly;
+ private CompareInfo compareInfo;
+ private TextInfo textInfo;
+ internal NumberFormatInfo numInfo;
+ internal DateTimeFormatInfo dateTimeInfo;
+ private Calendar calendar;
+ //
+ // The CultureData instance that we are going to read data from.
+ // For supported culture, this will be the CultureData instance that read data from mscorlib assembly.
+ // For customized culture, this will be the CultureData instance that read data from user customized culture binary file.
+ //
+ [NonSerialized]
+ internal CultureData m_cultureData;
+
+ [NonSerialized]
+ internal bool m_isInherited;
+
+ // Names are confusing. Here are 3 names we have:
+ //
+ // new CultureInfo() m_name m_nonSortName m_sortName
+ // en-US en-US en-US en-US
+ // de-de_phoneb de-DE_phoneb de-DE de-DE_phoneb
+ // fj-fj (custom) fj-FJ fj-FJ en-US (if specified sort is en-US)
+ // en en
+ //
+ // Note that in Silverlight we ask the OS for the text and sort behavior, so the
+ // textinfo and compareinfo names are the same as the name
+
+ // Note that the name used to be serialized for Everett; it is now serialized
+ // because alernate sorts can have alternate names.
+ // This has a de-DE, de-DE_phoneb or fj-FJ style name
+ internal string m_name;
+
+ // This will hold the non sorting name to be returned from CultureInfo.Name property.
+ // This has a de-DE style name even for de-DE_phoneb type cultures
+ [NonSerialized]
+ private string m_nonSortName;
+
+ // This will hold the sorting name to be returned from CultureInfo.SortName property.
+ // This might be completely unrelated to the culture name if a custom culture. Ie en-US for fj-FJ.
+ // Otherwise its the sort name, ie: de-DE or de-DE_phoneb
+ [NonSerialized]
+ private string m_sortName;
+
+
+ //--------------------------------------------------------------------//
+ //
+ // Static data members
+ //
+ //--------------------------------------------------------------------//
+
+ //Get the current user default culture. This one is almost always used, so we create it by default.
+ private static volatile CultureInfo s_userDefaultCulture;
+
+ //
+ // All of the following will be created on demand.
+ //
+
+ // WARNING: We allow diagnostic tools to directly inspect these three members (s_InvariantCultureInfo, s_DefaultThreadCurrentUICulture and s_DefaultThreadCurrentCulture)
+ // See https://github.com/dotnet/corert/blob/master/Documentation/design-docs/diagnostics/diagnostics-tools-contract.md for more details.
+ // Please do not change the type, the name, or the semantic usage of this member without understanding the implication for tools.
+ // Get in touch with the diagnostics team if you have questions.
+
+ //The Invariant culture;
+ private static volatile CultureInfo s_InvariantCultureInfo;
+
+ //These are defaults that we use if a thread has not opted into having an explicit culture
+ private static volatile CultureInfo s_DefaultThreadCurrentUICulture;
+ private static volatile CultureInfo s_DefaultThreadCurrentCulture;
+
+ [ThreadStatic]
+ private static volatile CultureInfo s_currentThreadCulture;
+ [ThreadStatic]
+ private static volatile CultureInfo s_currentThreadUICulture;
+
+ private static readonly Lock m_lock = new Lock();
+ private static volatile StringCultureInfoDictionary s_NameCachedCultures;
+
+ //The parent culture.
+ [NonSerialized]
+ private CultureInfo m_parent;
+
+ static AsyncLocal<CultureInfo> s_asyncLocalCurrentCulture;
+ static AsyncLocal<CultureInfo> s_asyncLocalCurrentUICulture;
+
+ static void AsyncLocalSetCurrentCulture(AsyncLocalValueChangedArgs<CultureInfo> args)
+ {
+ s_currentThreadCulture = args.CurrentValue;
+ }
+
+ static void AsyncLocalSetCurrentUICulture(AsyncLocalValueChangedArgs<CultureInfo> args)
+ {
+ s_currentThreadUICulture = args.CurrentValue;
+ }
+
+ //
+ // The CultureData instance that reads the data provided by our CultureData class.
+ //
+ // Using a field initializer rather than a static constructor so that the whole class can be lazy
+ // init.
+ private static readonly bool init = Init();
+ private static bool Init()
+ {
+ if (s_InvariantCultureInfo == null)
+ {
+ CultureInfo temp = new CultureInfo("", false);
+ temp.m_isReadOnly = true;
+ s_InvariantCultureInfo = temp;
+ }
+
+ s_userDefaultCulture = GetUserDefaultCulture();
+ return true;
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // CultureInfo Constructors
+ //
+ ////////////////////////////////////////////////////////////////////////
+
+
+ public CultureInfo(String name)
+ : this(name, true)
+ {
+ }
+
+
+ internal CultureInfo(String name, bool useUserOverride)
+ {
+ if (name == null)
+ {
+ throw new ArgumentNullException("name",
+ SR.ArgumentNull_String);
+ }
+
+ InitializeFromName(name, useUserOverride);
+ }
+
+ private void InitializeFromName(string name, bool useUserOverride)
+ {
+ // Get our data providing record
+ this.m_cultureData = CultureData.GetCultureData(name, useUserOverride);
+
+ if (this.m_cultureData == null)
+ {
+ throw new CultureNotFoundException("name", name, SR.Argument_CultureNotSupported);
+ }
+
+ this.m_name = this.m_cultureData.CultureName;
+ this.m_isInherited = (this.GetType() != typeof(System.Globalization.CultureInfo));
+ }
+
+ // We do this to try to return the system UI language and the default user languages
+ // This method will fallback if this fails (like Invariant)
+ //
+ // TODO: It would appear that this is only ever called with userOveride = true
+ // and this method only has one caller. Can we fold it into the caller?
+ private static CultureInfo GetCultureByName(String name, bool userOverride)
+ {
+ CultureInfo ci = null;
+ // Try to get our culture
+ try
+ {
+ ci = userOverride ? new CultureInfo(name) : CultureInfo.GetCultureInfo(name);
+ }
+ catch (ArgumentException)
+ {
+ }
+
+ if (ci == null)
+ {
+ ci = InvariantCulture;
+ }
+
+ return ci;
+ }
+
+ // //
+ // // Return a specific culture. A tad irrelevent now since we always return valid data
+ // // for neutral locales.
+ // //
+ // // Note that there's interesting behavior that tries to find a smaller name, ala RFC4647,
+ // // if we can't find a bigger name. That doesn't help with things like "zh" though, so
+ // // the approach is of questionable value
+ // //
+
+ internal static bool VerifyCultureName(String cultureName, bool throwException)
+ {
+ // This function is used by ResourceManager.GetResourceFileName().
+ // ResourceManager searches for resource using CultureInfo.Name,
+ // so we should check against CultureInfo.Name.
+
+ for (int i = 0; i < cultureName.Length; i++)
+ {
+ char c = cultureName[i];
+ // TODO: Names can only be RFC4646 names (ie: a-zA-Z0-9) while this allows any unicode letter/digit
+ if (Char.IsLetterOrDigit(c) || c == '-' || c == '_')
+ {
+ continue;
+ }
+ if (throwException)
+ {
+ throw new ArgumentException(SR.Format(SR.Argument_InvalidResourceCultureName, cultureName));
+ }
+ return false;
+ }
+ return true;
+ }
+
+ internal static bool VerifyCultureName(CultureInfo culture, bool throwException)
+ {
+ //If we have an instance of one of our CultureInfos, the user can't have changed the
+ //name and we know that all names are valid in files.
+ if (!culture.m_isInherited)
+ {
+ return true;
+ }
+
+ return VerifyCultureName(culture.Name, throwException);
+ }
+
+ // We need to store the override from the culture data record.
+ private bool m_useUserOverride;
+
+ [OnSerializing]
+ private void OnSerializing(StreamingContext ctx)
+ {
+ m_name = m_cultureData.CultureName;
+ m_useUserOverride = m_cultureData.UseUserOverride;
+ }
+
+ [OnDeserialized]
+ private void OnDeserialized(StreamingContext ctx)
+ {
+ Contract.Assert(m_name != null, "[CultureInfo.OnDeserialized] m_name != null");
+ InitializeFromName(m_name, m_useUserOverride);
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // CurrentCulture
+ //
+ // This instance provides methods based on the current user settings.
+ // These settings are volatile and may change over the lifetime of the
+ // thread.
+ //
+ ////////////////////////////////////////////////////////////////////////
+
+ //
+ // We use the following order to return CurrentCulture and CurrentUICulture
+ // o Use WinRT to return the current user profile language
+ // o use current thread culture if the user already set one using CurrentCulture/CurrentUICulture
+ // o use thread culture if the user already set one using DefaultThreadCurrentCulture
+ // or DefaultThreadCurrentUICulture
+ // o Use NLS default user culture
+ // o Use NLS default system culture
+ // o Use Invariant culture
+ //
+ public static CultureInfo CurrentCulture
+ {
+ get
+ {
+ CultureInfo ci = GetUserDefaultCultureCacheOverride();
+ if (ci != null)
+ {
+ return ci;
+ }
+
+ if (s_currentThreadCulture != null)
+ {
+ return s_currentThreadCulture;
+ }
+
+ ci = s_DefaultThreadCurrentCulture;
+ if (ci != null)
+ {
+ return ci;
+ }
+
+ // if s_userDefaultCulture == null means CultureInfo statics didn't get initialized yet. this can happen if there early static
+ // method get executed which eventually hit the cultureInfo code while CultureInfo statics didn’t get chance to initialize
+ if (s_userDefaultCulture == null)
+ {
+ Init();
+ }
+
+ Contract.Assert(s_userDefaultCulture != null);
+ return s_userDefaultCulture;
+ }
+
+ set
+ {
+ if (value == null)
+ {
+ throw new ArgumentNullException("value");
+ }
+
+ if (s_asyncLocalCurrentCulture == null)
+ {
+ Interlocked.CompareExchange(ref s_asyncLocalCurrentCulture, new AsyncLocal<CultureInfo>(AsyncLocalSetCurrentCulture), null);
+ }
+ // this one will set s_currentThreadCulture too
+ s_asyncLocalCurrentCulture.Value = value;
+ }
+ }
+
+ public static CultureInfo CurrentUICulture
+ {
+ get
+ {
+ CultureInfo ci = GetUserDefaultCultureCacheOverride();
+ if (ci != null)
+ {
+ return ci;
+ }
+
+ if (s_currentThreadUICulture != null)
+ {
+ return s_currentThreadUICulture;
+ }
+
+ ci = s_DefaultThreadCurrentUICulture;
+ if (ci != null)
+ {
+ return ci;
+ }
+
+ // if s_userDefaultCulture == null means CultureInfo statics didn't get initialized yet. this can happen if there early static
+ // method get executed which eventually hit the cultureInfo code while CultureInfo statics didn’t get chance to initialize
+ if (s_userDefaultCulture == null)
+ {
+ Init();
+ }
+
+ Contract.Assert(s_userDefaultCulture != null);
+ return s_userDefaultCulture;
+ }
+
+ set
+ {
+ if (value == null)
+ {
+ throw new ArgumentNullException("value");
+ }
+
+ CultureInfo.VerifyCultureName(value, true);
+
+ if (s_asyncLocalCurrentUICulture == null)
+ {
+ Interlocked.CompareExchange(ref s_asyncLocalCurrentUICulture, new AsyncLocal<CultureInfo>(AsyncLocalSetCurrentUICulture), null);
+ }
+
+ // this one will set s_currentThreadUICulture too
+ s_asyncLocalCurrentUICulture.Value = value;
+ }
+ }
+
+ public static CultureInfo DefaultThreadCurrentCulture
+ {
+ get { return s_DefaultThreadCurrentCulture; }
+ set
+ {
+ // If you add pre-conditions to this method, check to see if you also need to
+ // add them to Thread.CurrentCulture.set.
+
+ s_DefaultThreadCurrentCulture = value;
+ }
+ }
+
+ public static CultureInfo DefaultThreadCurrentUICulture
+ {
+ get { return s_DefaultThreadCurrentUICulture; }
+ set
+ {
+ //If they're trying to use a Culture with a name that we can't use in resource lookup,
+ //don't even let them set it on the thread.
+
+ // If you add more pre-conditions to this method, check to see if you also need to
+ // add them to Thread.CurrentUICulture.set.
+
+ if (value != null)
+ {
+ CultureInfo.VerifyCultureName(value, true);
+ }
+
+ s_DefaultThreadCurrentUICulture = value;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // InvariantCulture
+ //
+ // This instance provides methods, for example for casing and sorting,
+ // that are independent of the system and current user settings. It
+ // should be used only by processes such as some system services that
+ // require such invariant results (eg. file systems). In general,
+ // the results are not linguistically correct and do not match any
+ // culture info.
+ //
+ ////////////////////////////////////////////////////////////////////////
+
+
+ public static CultureInfo InvariantCulture
+ {
+ get
+ {
+ return (s_InvariantCultureInfo);
+ }
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Parent
+ //
+ // Return the parent CultureInfo for the current instance.
+ //
+ ////////////////////////////////////////////////////////////////////////
+
+ public virtual CultureInfo Parent
+ {
+ get
+ {
+ if (null == m_parent)
+ {
+ try
+ {
+ string parentName = this.m_cultureData.SPARENT;
+
+ if (String.IsNullOrEmpty(parentName))
+ {
+ m_parent = InvariantCulture;
+ }
+ else
+ {
+ m_parent = new CultureInfo(parentName, this.m_cultureData.UseUserOverride);
+ }
+ }
+ catch (ArgumentException)
+ {
+ // For whatever reason our IPARENT or SPARENT wasn't correct, so use invariant
+ // We can't allow ourselves to fail. In case of custom cultures the parent of the
+ // current custom culture isn't installed.
+ m_parent = InvariantCulture;
+ }
+ }
+ return m_parent;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Name
+ //
+ // Returns the full name of the CultureInfo. The name is in format like
+ // "en-US" This version does NOT include sort information in the name.
+ //
+ ////////////////////////////////////////////////////////////////////////
+ public virtual String Name
+ {
+ get
+ {
+ // We return non sorting name here.
+ if (this.m_nonSortName == null)
+ {
+ this.m_nonSortName = this.m_cultureData.SNAME;
+ if (this.m_nonSortName == null)
+ {
+ this.m_nonSortName = String.Empty;
+ }
+ }
+ return this.m_nonSortName;
+ }
+ }
+
+ // This one has the sort information (ie: de-DE_phoneb)
+ internal String SortName
+ {
+ get
+ {
+ if (this.m_sortName == null)
+ {
+ this.m_sortName = this.m_cultureData.SCOMPAREINFO;
+ }
+
+ return this.m_sortName;
+ }
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // DisplayName
+ //
+ // Returns the full name of the CultureInfo in the localized language.
+ // For example, if the localized language of the runtime is Spanish and the CultureInfo is
+ // US English, "Ingles (Estados Unidos)" will be returned.
+ //
+ ////////////////////////////////////////////////////////////////////////
+ public virtual String DisplayName
+ {
+ get
+ {
+ Contract.Ensures(Contract.Result<String>() != null);
+ Contract.Assert(m_name != null, "[CultureInfo.DisplayName] Always expect m_name to be set");
+
+ return m_cultureData.SLOCALIZEDDISPLAYNAME;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // GetNativeName
+ //
+ // Returns the full name of the CultureInfo in the native language.
+ // For example, if the CultureInfo is US English, "English
+ // (United States)" will be returned.
+ //
+ ////////////////////////////////////////////////////////////////////////
+ public virtual String NativeName
+ {
+ get
+ {
+ Contract.Ensures(Contract.Result<String>() != null);
+ return (this.m_cultureData.SNATIVEDISPLAYNAME);
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // GetEnglishName
+ //
+ // Returns the full name of the CultureInfo in English.
+ // For example, if the CultureInfo is US English, "English
+ // (United States)" will be returned.
+ //
+ ////////////////////////////////////////////////////////////////////////
+ public virtual String EnglishName
+ {
+ get
+ {
+ Contract.Ensures(Contract.Result<String>() != null);
+ return (this.m_cultureData.SENGDISPLAYNAME);
+ }
+ }
+
+ // ie: en
+ public virtual String TwoLetterISOLanguageName
+ {
+ get
+ {
+ Contract.Ensures(Contract.Result<String>() != null);
+ return (this.m_cultureData.SISO639LANGNAME);
+ }
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // CompareInfo Read-Only Property
+ //
+ // Gets the CompareInfo for this culture.
+ //
+ ////////////////////////////////////////////////////////////////////////
+ public virtual CompareInfo CompareInfo
+ {
+ get
+ {
+ if (this.compareInfo == null)
+ {
+ // Since CompareInfo's don't have any overrideable properties, get the CompareInfo from
+ // the Non-Overridden CultureInfo so that we only create one CompareInfo per culture
+ CompareInfo temp = UseUserOverride
+ ? GetCultureInfo(this.m_name).CompareInfo
+ : new CompareInfo(this);
+ if (OkayToCacheClassWithCompatibilityBehavior)
+ {
+ this.compareInfo = temp;
+ }
+ else
+ {
+ return temp;
+ }
+ }
+ return (compareInfo);
+ }
+ }
+
+ private static bool OkayToCacheClassWithCompatibilityBehavior
+ {
+ get
+ {
+ return true;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // TextInfo
+ //
+ // Gets the TextInfo for this culture.
+ //
+ ////////////////////////////////////////////////////////////////////////
+ public virtual TextInfo TextInfo
+ {
+ get
+ {
+ if (textInfo == null)
+ {
+ // Make a new textInfo
+ TextInfo tempTextInfo = new TextInfo(this.m_cultureData);
+ tempTextInfo.SetReadOnlyState(m_isReadOnly);
+
+ if (OkayToCacheClassWithCompatibilityBehavior)
+ {
+ textInfo = tempTextInfo;
+ }
+ else
+ {
+ return tempTextInfo;
+ }
+ }
+ return (textInfo);
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Equals
+ //
+ // Implements Object.Equals(). Returns a boolean indicating whether
+ // or not object refers to the same CultureInfo as the current instance.
+ //
+ ////////////////////////////////////////////////////////////////////////
+
+
+ public override bool Equals(Object value)
+ {
+ if (Object.ReferenceEquals(this, value))
+ return true;
+
+ CultureInfo that = value as CultureInfo;
+
+ if (that != null)
+ {
+ // using CompareInfo to verify the data passed through the constructor
+ // CultureInfo(String cultureName, String textAndCompareCultureName)
+
+ return (this.Name.Equals(that.Name) && this.CompareInfo.Equals(that.CompareInfo));
+ }
+
+ return (false);
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // GetHashCode
+ //
+ // Implements Object.GetHashCode(). Returns the hash code for the
+ // CultureInfo. The hash code is guaranteed to be the same for CultureInfo A
+ // and B where A.Equals(B) is true.
+ //
+ ////////////////////////////////////////////////////////////////////////
+
+ public override int GetHashCode()
+ {
+ return (this.Name.GetHashCode() + this.CompareInfo.GetHashCode());
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // ToString
+ //
+ // Implements Object.ToString(). Returns the name of the CultureInfo,
+ // eg. "de-DE_phoneb", "en-US", or "fj-FJ".
+ //
+ ////////////////////////////////////////////////////////////////////////
+
+
+ public override String ToString()
+ {
+ return m_name;
+ }
+
+
+ public virtual Object GetFormat(Type formatType)
+ {
+ if (formatType == typeof(NumberFormatInfo))
+ return (NumberFormat);
+ if (formatType == typeof(DateTimeFormatInfo))
+ return (DateTimeFormat);
+ return (null);
+ }
+
+ public virtual bool IsNeutralCulture
+ {
+ get
+ {
+ return this.m_cultureData.IsNeutralCulture;
+ }
+ }
+
+ public virtual NumberFormatInfo NumberFormat
+ {
+ get
+ {
+ if (numInfo == null)
+ {
+ NumberFormatInfo temp = new NumberFormatInfo(this.m_cultureData);
+ temp.isReadOnly = m_isReadOnly;
+ numInfo = temp;
+ }
+ return (numInfo);
+ }
+ set
+ {
+ if (value == null)
+ {
+ throw new ArgumentNullException("value", SR.ArgumentNull_Obj);
+ }
+ VerifyWritable();
+ numInfo = value;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // GetDateTimeFormatInfo
+ //
+ // Create a DateTimeFormatInfo, and fill in the properties according to
+ // the CultureID.
+ //
+ ////////////////////////////////////////////////////////////////////////
+ public virtual DateTimeFormatInfo DateTimeFormat
+ {
+ get
+ {
+ if (dateTimeInfo == null)
+ {
+ // Change the calendar of DTFI to the specified calendar of this CultureInfo.
+ DateTimeFormatInfo temp = new DateTimeFormatInfo(this.m_cultureData, this.Calendar);
+ temp._isReadOnly = m_isReadOnly;
+ System.Threading.Interlocked.MemoryBarrier();
+ dateTimeInfo = temp;
+ }
+ return (dateTimeInfo);
+ }
+
+ set
+ {
+ if (value == null)
+ {
+ throw new ArgumentNullException("value", SR.ArgumentNull_Obj);
+ }
+ VerifyWritable();
+ dateTimeInfo = value;
+ }
+ }
+
+ /*=================================GetCalendarInstance==========================
+ **Action: Map a Win32 CALID to an instance of supported calendar.
+ **Returns: An instance of calendar.
+ **Arguments: calType The Win32 CALID
+ **Exceptions:
+ ** Shouldn't throw exception since the calType value is from our data table or from Win32 registry.
+ ** If we are in trouble (like getting a weird value from Win32 registry), just return the GregorianCalendar.
+ ============================================================================*/
+ internal static Calendar GetCalendarInstance(CalendarId calType)
+ {
+ if (calType == CalendarId.GREGORIAN)
+ {
+ return (new GregorianCalendar());
+ }
+ return GetCalendarInstanceRare(calType);
+ }
+
+ //This function exists as a shortcut to prevent us from loading all of the non-gregorian
+ //calendars unless they're required.
+ internal static Calendar GetCalendarInstanceRare(CalendarId calType)
+ {
+ Contract.Assert(calType != CalendarId.GREGORIAN, "calType!=CalendarId.GREGORIAN");
+
+ switch (calType)
+ {
+ case CalendarId.GREGORIAN_US: // Gregorian (U.S.) calendar
+ case CalendarId.GREGORIAN_ME_FRENCH: // Gregorian Middle East French calendar
+ case CalendarId.GREGORIAN_ARABIC: // Gregorian Arabic calendar
+ case CalendarId.GREGORIAN_XLIT_ENGLISH: // Gregorian Transliterated English calendar
+ case CalendarId.GREGORIAN_XLIT_FRENCH: // Gregorian Transliterated French calendar
+ return (new GregorianCalendar((GregorianCalendarTypes)calType));
+ case CalendarId.TAIWAN: // Taiwan Era calendar
+ return (new TaiwanCalendar());
+ case CalendarId.JAPAN: // Japanese Emperor Era calendar
+ return (new JapaneseCalendar());
+ case CalendarId.KOREA: // Korean Tangun Era calendar
+ return (new KoreanCalendar());
+ case CalendarId.THAI: // Thai calendar
+ return (new ThaiBuddhistCalendar());
+ case CalendarId.HIJRI: // Hijri (Arabic Lunar) calendar
+ return (new HijriCalendar());
+ case CalendarId.HEBREW: // Hebrew (Lunar) calendar
+ return (new HebrewCalendar());
+ case CalendarId.UMALQURA:
+ return (new UmAlQuraCalendar());
+ case CalendarId.PERSIAN:
+ return (new PersianCalendar());
+ }
+ return (new GregorianCalendar());
+ }
+
+ /*=================================Calendar==========================
+ **Action: Return/set the default calendar used by this culture.
+ ** This value can be overridden by regional option if this is a current culture.
+ **Returns:
+ **Arguments:
+ **Exceptions:
+ ** ArgumentNull_Obj if the set value is null.
+ ============================================================================*/
+ public virtual Calendar Calendar
+ {
+ get
+ {
+ if (calendar == null)
+ {
+ Contract.Assert(this.m_cultureData.CalendarIds.Length > 0, "this.m_cultureData.CalendarIds.Length > 0");
+ // Get the default calendar for this culture. Note that the value can be
+ // from registry if this is a user default culture.
+ Calendar newObj = this.m_cultureData.DefaultCalendar;
+
+ System.Threading.Interlocked.MemoryBarrier();
+ newObj.SetReadOnlyState(m_isReadOnly);
+ calendar = newObj;
+ }
+ return (calendar);
+ }
+ }
+
+ /*=================================OptionCalendars==========================
+ **Action: Return an array of the optional calendar for this culture.
+ **Returns: an array of Calendar.
+ **Arguments:
+ **Exceptions:
+ ============================================================================*/
+
+
+ public virtual Calendar[] OptionalCalendars
+ {
+ get
+ {
+ Contract.Ensures(Contract.Result<Calendar[]>() != null);
+
+ //
+ // This property always returns a new copy of the calendar array.
+ //
+ CalendarId[] calID = this.m_cultureData.CalendarIds;
+ Calendar[] cals = new Calendar[calID.Length];
+ for (int i = 0; i < cals.Length; i++)
+ {
+ cals[i] = GetCalendarInstance(calID[i]);
+ }
+ return (cals);
+ }
+ }
+
+
+ private bool UseUserOverride
+ {
+ get
+ {
+ return (this.m_cultureData.UseUserOverride);
+ }
+ }
+
+ public virtual Object Clone()
+ {
+ CultureInfo ci = (CultureInfo)MemberwiseClone();
+ ci.m_isReadOnly = false;
+
+ //If this is exactly our type, we can make certain optimizations so that we don't allocate NumberFormatInfo or DTFI unless
+ //they've already been allocated. If this is a derived type, we'll take a more generic codepath.
+ if (!m_isInherited)
+ {
+ if (this.dateTimeInfo != null)
+ {
+ ci.dateTimeInfo = (DateTimeFormatInfo)this.dateTimeInfo.Clone();
+ }
+ if (this.numInfo != null)
+ {
+ ci.numInfo = (NumberFormatInfo)this.numInfo.Clone();
+ }
+ }
+ else
+ {
+ ci.DateTimeFormat = (DateTimeFormatInfo)this.DateTimeFormat.Clone();
+ ci.NumberFormat = (NumberFormatInfo)this.NumberFormat.Clone();
+ }
+
+ if (textInfo != null)
+ {
+ ci.textInfo = (TextInfo)textInfo.Clone();
+ }
+
+ if (calendar != null)
+ {
+ ci.calendar = (Calendar)calendar.Clone();
+ }
+
+ return (ci);
+ }
+
+ public static CultureInfo ReadOnly(CultureInfo ci)
+ {
+ if (ci == null)
+ {
+ throw new ArgumentNullException("ci");
+ }
+ Contract.Ensures(Contract.Result<CultureInfo>() != null);
+ Contract.EndContractBlock();
+
+ if (ci.IsReadOnly)
+ {
+ return (ci);
+ }
+ CultureInfo newInfo = (CultureInfo)(ci.MemberwiseClone());
+
+ if (!ci.IsNeutralCulture)
+ {
+ //If this is exactly our type, we can make certain optimizations so that we don't allocate NumberFormatInfo or DTFI unless
+ //they've already been allocated. If this is a derived type, we'll take a more generic codepath.
+ if (!ci.m_isInherited)
+ {
+ if (ci.dateTimeInfo != null)
+ {
+ newInfo.dateTimeInfo = DateTimeFormatInfo.ReadOnly(ci.dateTimeInfo);
+ }
+ if (ci.numInfo != null)
+ {
+ newInfo.numInfo = NumberFormatInfo.ReadOnly(ci.numInfo);
+ }
+ }
+ else
+ {
+ newInfo.DateTimeFormat = DateTimeFormatInfo.ReadOnly(ci.DateTimeFormat);
+ newInfo.NumberFormat = NumberFormatInfo.ReadOnly(ci.NumberFormat);
+ }
+ }
+
+ if (ci.textInfo != null)
+ {
+ newInfo.textInfo = TextInfo.ReadOnly(ci.textInfo);
+ }
+
+ if (ci.calendar != null)
+ {
+ newInfo.calendar = Calendar.ReadOnly(ci.calendar);
+ }
+
+ // Don't set the read-only flag too early.
+ // We should set the read-only flag here. Otherwise, info.DateTimeFormat will not be able to set.
+ newInfo.m_isReadOnly = true;
+
+ return (newInfo);
+ }
+
+
+ public bool IsReadOnly
+ {
+ get
+ {
+ return (m_isReadOnly);
+ }
+ }
+
+ private void VerifyWritable()
+ {
+ if (m_isReadOnly)
+ {
+ throw new InvalidOperationException(SR.InvalidOperation_ReadOnly);
+ }
+ }
+
+ // For resource lookup, we consider a culture the invariant culture by name equality.
+ // We perform this check frequently during resource lookup, so adding a property for
+ // improved readability.
+ internal bool HasInvariantCultureName
+ {
+ get { return Name == CultureInfo.InvariantCulture.Name; }
+ }
+
+ // Helper function both both overloads of GetCachedReadOnlyCulture.
+ internal static CultureInfo GetCultureInfoHelper(string name)
+ {
+ // There is a race condition in this code with the side effect that the second thread's value
+ // clobbers the first in the dictionary. This is an acceptable race since the CultureInfo objects
+ // are content equal (but not reference equal). Since we make no guarantees there, this race is
+ // acceptable.
+
+ // retval is our return value.
+ CultureInfo retval;
+
+ if (name == null)
+ {
+ return null;
+ }
+
+ // Temporary hashtable for the names.
+ StringCultureInfoDictionary tempNameHT = s_NameCachedCultures;
+
+ name = CultureData.AnsiToLower(name);
+
+ // We expect the same result for both hashtables, but will test individually for added safety.
+ if (tempNameHT == null)
+ {
+ tempNameHT = new StringCultureInfoDictionary();
+ }
+ else
+ {
+ bool ret;
+ lock (m_lock)
+ {
+ ret = tempNameHT.TryGetValue(name, out retval);
+ }
+
+ if (ret && retval != null)
+ {
+ return retval;
+ }
+ }
+ try
+ {
+ retval = new CultureInfo(name, false);
+ }
+ catch (ArgumentException)
+ {
+ return null;
+ }
+
+ // Set it to read-only
+ retval.m_isReadOnly = true;
+
+ // Remember our name (as constructed). Do NOT use alternate sort name versions because
+ // we have internal state representing the sort. (So someone would get the wrong cached version)
+ string newName = CultureData.AnsiToLower(retval.m_name);
+
+ // We add this new culture info object to both tables.
+ lock (m_lock)
+ {
+ tempNameHT[newName] = retval;
+ }
+
+ s_NameCachedCultures = tempNameHT;
+
+ // Finally, return our new CultureInfo object.
+ return retval;
+ }
+
+ // Gets a cached copy of the specified culture from an internal hashtable (or creates it
+ // if not found). (Named version)
+ internal static CultureInfo GetCultureInfo(string name)
+ {
+ // Make sure we have a valid, non-zero length string as name
+ if (name == null)
+ {
+ throw new ArgumentNullException("name");
+ }
+
+ CultureInfo retval = GetCultureInfoHelper(name);
+ if (retval == null)
+ {
+ throw new CultureNotFoundException(
+ "name", name, SR.Argument_CultureNotSupported);
+ }
+ return retval;
+ }
+ }
+}
+
diff --git a/src/mscorlib/corefx/System/Globalization/CultureNotFoundException.cs b/src/mscorlib/corefx/System/Globalization/CultureNotFoundException.cs
new file mode 100644
index 0000000000..740063e4d3
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/CultureNotFoundException.cs
@@ -0,0 +1,104 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Threading;
+using System.Runtime.Serialization;
+
+namespace System.Globalization
+{
+ [Serializable]
+ [System.Runtime.InteropServices.ComVisible(true)]
+ public partial class CultureNotFoundException : ArgumentException, ISerializable
+ {
+ private string _invalidCultureName; // unrecognized culture name
+
+ public CultureNotFoundException()
+ : base(DefaultMessage)
+ {
+ }
+
+ public CultureNotFoundException(String message)
+ : base(message)
+ {
+ }
+
+ public CultureNotFoundException(String paramName, String message)
+ : base(message, paramName)
+ {
+ }
+
+ public CultureNotFoundException(String message, Exception innerException)
+ : base(message, innerException)
+ {
+ }
+
+ public CultureNotFoundException(String paramName, string invalidCultureName, String message)
+ : base(message, paramName)
+ {
+ _invalidCultureName = invalidCultureName;
+ }
+
+ public CultureNotFoundException(String message, string invalidCultureName, Exception innerException)
+ : base(message, innerException)
+ {
+ _invalidCultureName = invalidCultureName;
+ }
+
+ protected CultureNotFoundException(SerializationInfo info, StreamingContext context) : base(info, context)
+ {
+ _invalidCultureName = (string)info.GetValue("InvalidCultureName", typeof(string));
+ }
+
+ [System.Security.SecurityCritical] // auto-generated_required
+ public override void GetObjectData(SerializationInfo info, StreamingContext context)
+ {
+ if (info == null)
+ {
+ throw new ArgumentNullException("info");
+ }
+
+ base.GetObjectData(info, context);
+ info.AddValue("InvalidCultureName", _invalidCultureName, typeof(string));
+ }
+
+ public virtual string InvalidCultureName
+ {
+ get { return _invalidCultureName; }
+ }
+
+ private static String DefaultMessage
+ {
+ get
+ {
+ return SR.Argument_CultureNotSupported;
+ }
+ }
+
+ private String FormatedInvalidCultureId
+ {
+ get
+ {
+ return InvalidCultureName;
+ }
+ }
+
+ public override String Message
+ {
+ get
+ {
+ String s = base.Message;
+ if (
+ _invalidCultureName != null)
+ {
+ String valueMessage = SR.Format(SR.Argument_CultureInvalidIdentifier, FormatedInvalidCultureId);
+ if (s == null)
+ return valueMessage;
+ return s + Environment.NewLine + valueMessage;
+ }
+ return s;
+ }
+ }
+ }
+}
diff --git a/src/mscorlib/corefx/System/Globalization/DateTimeFormatInfo.cs b/src/mscorlib/corefx/System/Globalization/DateTimeFormatInfo.cs
new file mode 100644
index 0000000000..da746ada88
--- /dev/null
+++ b/src/mscorlib/corefx/System/Globalization/DateTimeFormatInfo.cs
@@ -0,0 +1,2958 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Diagnostics.Contracts;
+using System.Runtime.InteropServices;
+using System.Runtime.Serialization;
+using System.Security;
+using System.Text;
+using System.Threading;
+
+namespace System.Globalization
+{
+ //
+ // Flags used to indicate different styles of month names.
+ // This is an internal flag used by internalGetMonthName().
+ // Use flag here in case that we need to provide a combination of these styles
+ // (such as month name of a leap year in genitive form. Not likely for now,
+ // but would like to keep the option open).
+ //
+
+ [Flags]
+ internal enum MonthNameStyles
+ {
+ Regular = 0x00000000,
+ Genitive = 0x00000001,
+ LeapYear = 0x00000002,
+ }
+
+ //
+ // Flags used to indicate special rule used in parsing/formatting
+ // for a specific DateTimeFormatInfo instance.
+ // This is an internal flag.
+ //
+ // This flag is different from MonthNameStyles because this flag
+ // can be expanded to accomodate parsing behaviors like CJK month names
+ // or alternative month names, etc.
+
+ [Flags]
+ internal enum DateTimeFormatFlags
+ {
+ None = 0x00000000,
+ UseGenitiveMonth = 0x00000001,
+ UseLeapYearMonth = 0x00000002,
+ UseSpacesInMonthNames = 0x00000004, // Has spaces or non-breaking space in the month names.
+ UseHebrewRule = 0x00000008, // Format/Parse using the Hebrew calendar rule.
+ UseSpacesInDayNames = 0x00000010, // Has spaces or non-breaking space in the day names.
+ UseDigitPrefixInTokens = 0x00000020, // Has token starting with numbers.
+
+ NotInitialized = -1,
+ }
+
+
+ [Serializable]
+ [System.Runtime.InteropServices.ComVisible(true)]
+ public sealed partial class DateTimeFormatInfo : IFormatProvider, ICloneable
+ {
+ // cache for the invariant culture.
+ // invariantInfo is constant irrespective of your current culture.
+ private static volatile DateTimeFormatInfo s_invariantInfo;
+
+ // an index which points to a record in Culture Data Table.
+ [NonSerialized]
+ private CultureData _cultureData;
+
+ // The culture name used to create this DTFI.
+
+ [OptionalField(VersionAdded = 2)]
+ private String _name = null;
+
+ // The language name of the culture used to create this DTFI.
+ [NonSerialized]
+ private String _langName = null;
+
+ // CompareInfo usually used by the parser.
+ [NonSerialized]
+ private CompareInfo _compareInfo = null;
+
+ // Culture matches current DTFI. mainly used for string comparisons during parsing.
+ [NonSerialized]
+ private CultureInfo _cultureInfo = null;
+
+ //
+ // Caches for various properties.
+ //
+
+ private String amDesignator = null;
+ private String pmDesignator = null;
+
+ private String dateSeparator = null; // derived from short date (whidbey expects, arrowhead doesn't)
+
+ private String generalShortTimePattern = null; // short date + short time (whidbey expects, arrowhead doesn't)
+
+ private String generalLongTimePattern = null; // short date + long time (whidbey expects, arrowhead doesn't)
+
+ private String timeSeparator = null; // derived from long time (whidbey expects, arrowhead doesn't)
+ private String monthDayPattern = null;
+ // added in .NET Framework Release {2.0SP1/3.0SP1/3.5RTM}
+ private String dateTimeOffsetPattern = null;
+
+ //
+ // The following are constant values.
+ //
+ private const String rfc1123Pattern = "ddd, dd MMM yyyy HH':'mm':'ss 'GMT'";
+
+ // The sortable pattern is based on ISO 8601.
+ private const String sortableDateTimePattern = "yyyy'-'MM'-'dd'T'HH':'mm':'ss";
+ private const String universalSortableDateTimePattern = "yyyy'-'MM'-'dd HH':'mm':'ss'Z'";
+
+ //
+ // The following are affected by calendar settings.
+ //
+ private Calendar calendar = null;
+
+ private int firstDayOfWeek = -1;
+ private int calendarWeekRule = -1;
+
+
+ private String fullDateTimePattern = null; // long date + long time (whidbey expects, arrowhead doesn't)
+
+ private String[] abbreviatedDayNames = null;
+
+
+ private String[] m_superShortDayNames = null;
+
+ private String[] dayNames = null;
+ private String[] abbreviatedMonthNames = null;
+ private String[] monthNames = null;
+ // Cache the genitive month names that we retrieve from the data table.
+
+ private String[] genitiveMonthNames = null;
+
+ // Cache the abbreviated genitive month names that we retrieve from the data table.
+
+ private String[] m_genitiveAbbreviatedMonthNames = null;
+
+ // Cache the month names of a leap year that we retrieve from the data table.
+
+ private String[] leapYearMonthNames = null;
+
+ // For our "patterns" arrays we have 2 variables, a string and a string[]
+ //
+ // The string[] contains the list of patterns, EXCEPT the default may not be included.
+ // The string contains the default pattern.
+ // When we initially construct our string[], we set the string to string[0]
+
+ // The "default" Date/time patterns
+ private String longDatePattern = null;
+ private String shortDatePattern = null;
+ private String yearMonthPattern = null;
+ private String longTimePattern = null;
+ private String shortTimePattern = null;
+
+ [OptionalField(VersionAdded = 3)]
+ private String[] allYearMonthPatterns = null;
+
+ private String[] allShortDatePatterns = null;
+ private String[] allLongDatePatterns = null;
+ private String[] allShortTimePatterns = null;
+ private String[] allLongTimePatterns = null;
+
+ // Cache the era names for this DateTimeFormatInfo instance.
+ private String[] m_eraNames = null;
+ private String[] m_abbrevEraNames = null;
+ private String[] m_abbrevEnglishEraNames = null;
+
+ private CalendarId[] optionalCalendars = null;
+
+ private const int DEFAULT_ALL_DATETIMES_SIZE = 132;
+
+ // CultureInfo updates this
+ internal bool _isReadOnly = false;
+
+ // This flag gives hints about if formatting/parsing should perform special code path for things like
+ // genitive form or leap year month names.
+
+ private DateTimeFormatFlags formatFlags = DateTimeFormatFlags.NotInitialized;
+
+ private String CultureName
+ {
+ get
+ {
+ if (_name == null)
+ {
+ _name = _cultureData.CultureName;
+ }
+ return (_name);
+ }
+ }
+
+ private CultureInfo Culture
+ {
+ get
+ {
+ if (_cultureInfo == null)
+ {
+ _cultureInfo = CultureInfo.GetCultureInfo(this.CultureName);
+ }
+ return _cultureInfo;
+ }
+ }
+
+ // TODO: This ignores other cultures that might want to do something similar
+ private String LanguageName
+ {
+ get
+ {
+ if (_langName == null)
+ {
+ _langName = _cultureData.SISO639LANGNAME;
+ }
+ return (_langName);
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Create an array of string which contains the abbreviated day names.
+ //
+ ////////////////////////////////////////////////////////////////////////////
+
+ private String[] internalGetAbbreviatedDayOfWeekNames()
+ {
+ if (this.abbreviatedDayNames == null)
+ {
+ // Get the abbreviated day names for our current calendar
+ this.abbreviatedDayNames = _cultureData.AbbreviatedDayNames(Calendar.ID);
+ Contract.Assert(this.abbreviatedDayNames.Length == 7, "[DateTimeFormatInfo.GetAbbreviatedDayOfWeekNames] Expected 7 day names in a week");
+ }
+ return (this.abbreviatedDayNames);
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Action: Returns the string array of the one-letter day of week names.
+ // Returns:
+ // an array of one-letter day of week names
+ // Arguments:
+ // None
+ // Exceptions:
+ // None
+ //
+ ////////////////////////////////////////////////////////////////////////
+
+ private String[] internalGetSuperShortDayNames()
+ {
+ if (this.m_superShortDayNames == null)
+ {
+ // Get the super short day names for our current calendar
+ this.m_superShortDayNames = _cultureData.SuperShortDayNames(Calendar.ID);
+ Contract.Assert(this.m_superShortDayNames.Length == 7, "[DateTimeFormatInfo.internalGetSuperShortDayNames] Expected 7 day names in a week");
+ }
+ return (this.m_superShortDayNames);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Create an array of string which contains the day names.
+ //
+ ////////////////////////////////////////////////////////////////////////////
+
+ private String[] internalGetDayOfWeekNames()
+ {
+ if (this.dayNames == null)
+ {
+ // Get the day names for our current calendar
+ this.dayNames = _cultureData.DayNames(Calendar.ID);
+ Contract.Assert(this.dayNames.Length == 7, "[DateTimeFormatInfo.GetDayOfWeekNames] Expected 7 day names in a week");
+ }
+ return (this.dayNames);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Create an array of string which contains the abbreviated month names.
+ //
+ ////////////////////////////////////////////////////////////////////////////
+
+ private String[] internalGetAbbreviatedMonthNames()
+ {
+ if (this.abbreviatedMonthNames == null)
+ {
+ // Get the month names for our current calendar
+ this.abbreviatedMonthNames = _cultureData.AbbreviatedMonthNames(Calendar.ID);
+ Contract.Assert(this.abbreviatedMonthNames.Length == 12 || this.abbreviatedMonthNames.Length == 13,
+ "[DateTimeFormatInfo.GetAbbreviatedMonthNames] Expected 12 or 13 month names in a year");
+ }
+ return (this.abbreviatedMonthNames);
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Create an array of string which contains the month names.
+ //
+ ////////////////////////////////////////////////////////////////////////////
+
+ private String[] internalGetMonthNames()
+ {
+ if (this.monthNames == null)
+ {
+ // Get the month names for our current calendar
+ this.monthNames = _cultureData.MonthNames(Calendar.ID);
+ Contract.Assert(this.monthNames.Length == 12 || this.monthNames.Length == 13,
+ "[DateTimeFormatInfo.GetMonthNames] Expected 12 or 13 month names in a year");
+ }
+
+ return (this.monthNames);
+ }
+
+
+ //
+ // Invariant DateTimeFormatInfo doesn't have user-overriden values
+ // Default calendar is gregorian
+ public DateTimeFormatInfo()
+ : this(CultureInfo.InvariantCulture.m_cultureData,
+ GregorianCalendar.GetDefaultInstance())
+ {
+ }
+
+ internal DateTimeFormatInfo(CultureData cultureData, Calendar cal)
+ {
+ Contract.Requires(cultureData != null);
+ Contract.Requires(cal != null);
+
+ // Remember our culture
+ _cultureData = cultureData;
+
+ this.Calendar = cal;
+ }
+
+ private void InitializeOverridableProperties(CultureData cultureData, CalendarId calendarId)
+ {
+ Contract.Requires(cultureData != null);
+ Contract.Assert(calendarId != CalendarId.UNINITIALIZED_VALUE, "[DateTimeFormatInfo.Populate] Expected initalized calendarId");
+
+ if (this.firstDayOfWeek == -1) { this.firstDayOfWeek = cultureData.IFIRSTDAYOFWEEK; }
+ if (this.calendarWeekRule == -1) { this.calendarWeekRule = cultureData.IFIRSTWEEKOFYEAR; }
+
+ if (this.amDesignator == null) { this.amDesignator = cultureData.SAM1159; }
+ if (this.pmDesignator == null) { this.pmDesignator = cultureData.SPM2359; }
+ if (this.timeSeparator == null) { this.timeSeparator = cultureData.TimeSeparator; }
+ if (this.dateSeparator == null) { this.dateSeparator = cultureData.DateSeparator(calendarId); }
+
+ this.allLongTimePatterns = _cultureData.LongTimes;
+ Contract.Assert(this.allLongTimePatterns.Length > 0, "[DateTimeFormatInfo.Populate] Expected some long time patterns");
+
+ this.allShortTimePatterns = _cultureData.ShortTimes;
+ Contract.Assert(this.allShortTimePatterns.Length > 0, "[DateTimeFormatInfo.Populate] Expected some short time patterns");
+
+ this.allLongDatePatterns = cultureData.LongDates(calendarId);
+ Contract.Assert(this.allLongDatePatterns.Length > 0, "[DateTimeFormatInfo.Populate] Expected some long date patterns");
+
+ this.allShortDatePatterns = cultureData.ShortDates(calendarId);
+ Contract.Assert(this.allShortDatePatterns.Length > 0, "[DateTimeFormatInfo.Populate] Expected some short date patterns");
+
+ this.allYearMonthPatterns = cultureData.YearMonths(calendarId);
+ Contract.Assert(this.allYearMonthPatterns.Length > 0, "[DateTimeFormatInfo.Populate] Expected some year month patterns");
+ }
+
+ [OptionalField(VersionAdded = 1)]
+ private bool _useUserOverride;
+
+ // This was synthesized by Whidbey so we knew what words might appear in the middle of a date string
+ // Now we always synthesize so its not helpful
+
+ internal String[] m_dateWords = null;
+
+ [OnSerializing]
+ private void OnSerializing(StreamingContext ctx)
+ {
+ _name = this.CultureName; // make sure the _name is initialized.
+ _useUserOverride = _cultureData.UseUserOverride;
+
+ // Important to initialize these fields otherwise we may run into exception when deserializing on Whidbey
+ // because Whidbey try to initialize some of these fields using calendar data which could be null values
+ // and then we get exceptions. So we call the accessors to force the caches to get loaded.
+ Object o;
+ o = this.LongTimePattern;
+ o = this.LongDatePattern;
+ o = this.ShortTimePattern;
+ o = this.ShortDatePattern;
+ o = this.YearMonthPattern;
+ o = this.AllLongTimePatterns;
+ o = this.AllLongDatePatterns;
+ o = this.AllShortTimePatterns;
+ o = this.AllShortDatePatterns;
+ o = this.AllYearMonthPatterns;
+ }
+
+ [OnDeserialized]
+ private void OnDeserialized(StreamingContext ctx)
+ {
+ if (_name != null)
+ {
+ _cultureData = CultureData.GetCultureData(_name, _useUserOverride);
+ if (_cultureData == null)
+ {
+ throw new CultureNotFoundException("_name", _name, SR.Argument_CultureNotSupported);
+ }
+ }
+
+ if (calendar == null)
+ {
+ calendar = (Calendar)GregorianCalendar.GetDefaultInstance().Clone();
+ calendar.SetReadOnlyState(_isReadOnly);
+ }
+
+ InitializeOverridableProperties(_cultureData, calendar.ID);
+
+ //
+ // turn off read only state till we finish initializing all fields and then store read only state after we are done.
+ //
+ bool isReadOnly = _isReadOnly;
+ _isReadOnly = false;
+
+ // If we deserialized defaults ala Whidbey, make sure they're still defaults
+ // Whidbey's arrays could get a bit mixed up.
+ if (longDatePattern != null) this.LongDatePattern = longDatePattern;
+ if (shortDatePattern != null) this.ShortDatePattern = shortDatePattern;
+ if (yearMonthPattern != null) this.YearMonthPattern = yearMonthPattern;
+ if (longTimePattern != null) this.LongTimePattern = longTimePattern;
+ if (shortTimePattern != null) this.ShortTimePattern = shortTimePattern;
+
+ _isReadOnly = isReadOnly;
+ }
+
+ // Returns a default DateTimeFormatInfo that will be universally
+ // supported and constant irrespective of the current culture.
+ // Used by FromString methods.
+ //
+
+ public static DateTimeFormatInfo InvariantInfo
+ {
+ get
+ {
+ Contract.Ensures(Contract.Result<DateTimeFormatInfo>() != null);
+ if (s_invariantInfo == null)
+ {
+ DateTimeFormatInfo info = new DateTimeFormatInfo();
+ info.Calendar.SetReadOnlyState(true);
+ info._isReadOnly = true;
+ s_invariantInfo = info;
+ }
+ return (s_invariantInfo);
+ }
+ }
+
+ // Returns the current culture's DateTimeFormatInfo. Used by Parse methods.
+ //
+
+ public static DateTimeFormatInfo CurrentInfo
+ {
+ get
+ {
+ Contract.Ensures(Contract.Result<DateTimeFormatInfo>() != null);
+ System.Globalization.CultureInfo culture = System.Globalization.CultureInfo.CurrentCulture;
+ if (!culture.m_isInherited)
+ {
+ DateTimeFormatInfo info = culture.dateTimeInfo;
+ if (info != null)
+ {
+ return info;
+ }
+ }
+ return (DateTimeFormatInfo)culture.GetFormat(typeof(DateTimeFormatInfo));
+ }
+ }
+
+
+ public static DateTimeFormatInfo GetInstance(IFormatProvider provider)
+ {
+ // Fast case for a regular CultureInfo
+ DateTimeFormatInfo info;
+ CultureInfo cultureProvider = provider as CultureInfo;
+ if (cultureProvider != null && !cultureProvider.m_isInherited)
+ {
+ return cultureProvider.DateTimeFormat;
+ }
+ // Fast case for a DTFI;
+ info = provider as DateTimeFormatInfo;
+ if (info != null)
+ {
+ return info;
+ }
+ // Wasn't cultureInfo or DTFI, do it the slower way
+ if (provider != null)
+ {
+ info = provider.GetFormat(typeof(DateTimeFormatInfo)) as DateTimeFormatInfo;
+ if (info != null)
+ {
+ return info;
+ }
+ }
+ // Couldn't get anything, just use currentInfo as fallback
+ return CurrentInfo;
+ }
+
+
+ public Object GetFormat(Type formatType)
+ {
+ return (formatType == typeof(DateTimeFormatInfo) ? this : null);
+ }
+
+
+ public Object Clone()
+ {
+ DateTimeFormatInfo n = (DateTimeFormatInfo)MemberwiseClone();
+ // We can use the data member calendar in the setter, instead of the property Calendar,
+ // since the cloned copy should have the same state as the original copy.
+ n.calendar = (Calendar)this.Calendar.Clone();
+ n._isReadOnly = false;
+ return n;
+ }
+
+
+ public String AMDesignator
+ {
+ // auto-generated
+ get
+ {
+ if (this.amDesignator == null)
+ {
+ this.amDesignator = _cultureData.SAM1159;
+ }
+ Contract.Assert(this.amDesignator != null, "DateTimeFormatInfo.AMDesignator, amDesignator != null");
+ return (this.amDesignator);
+ }
+
+ set
+ {
+ if (IsReadOnly)
+ throw new InvalidOperationException(SR.InvalidOperation_ReadOnly);
+ if (value == null)
+ {
+ throw new ArgumentNullException("value",
+ SR.ArgumentNull_String);
+ }
+ Contract.EndContractBlock();
+ ClearTokenHashTable();
+ amDesignator = value;
+ }
+ }
+
+
+ public Calendar Calendar
+ {
+ get
+ {
+ Contract.Ensures(Contract.Result<Calendar>() != null);
+
+ Contract.Assert(this.calendar != null, "DateTimeFormatInfo.Calendar: calendar != null");
+ return (this.calendar);
+ }
+
+ set
+ {
+ if (IsReadOnly)
+ throw new InvalidOperationException(SR.InvalidOperation_ReadOnly);
+ if (value == null)
+ {
+ throw new ArgumentNullException("value", SR.ArgumentNull_Obj);
+ }
+ Contract.EndContractBlock();
+ if (value == calendar)
+ {
+ return;
+ }
+
+ for (int i = 0; i < this.OptionalCalendars.Length; i++)
+ {
+ if (this.OptionalCalendars[i] == value.ID)
+ {
+ // We can use this one, so do so.
+
+ // Clean related properties if we already had a calendar set
+ if (calendar != null)
+ {
+ // clean related properties which are affected by the calendar setting,
+ // so that they will be refreshed when they are accessed next time.
+ //
+
+ // These properites are in the order as appearing in calendar.xml.
+ m_eraNames = null;
+ m_abbrevEraNames = null;
+ m_abbrevEnglishEraNames = null;
+
+ monthDayPattern = null;
+
+ dayNames = null;
+ abbreviatedDayNames = null;
+ m_superShortDayNames = null;
+ monthNames = null;
+ abbreviatedMonthNames = null;
+ genitiveMonthNames = null;
+ m_genitiveAbbreviatedMonthNames = null;
+ leapYearMonthNames = null;
+ formatFlags = DateTimeFormatFlags.NotInitialized;
+
+ allShortDatePatterns = null;
+ allLongDatePatterns = null;
+ allYearMonthPatterns = null;
+ dateTimeOffsetPattern = null;
+
+ // The defaults need reset as well:
+ longDatePattern = null;
+ shortDatePattern = null;
+ yearMonthPattern = null;
+
+ // These properies are not in the OS data, but they are dependent on the values like shortDatePattern.
+ fullDateTimePattern = null; // Long date + long time
+ generalShortTimePattern = null; // short date + short time
+ generalLongTimePattern = null; // short date + long time
+
+ // Derived item that changes
+ dateSeparator = null;
+
+ // We don't need to do these because they are not changed by changing calendar
+ // amDesignator
+ // pmDesignator
+ // timeSeparator
+ // longTimePattern
+ // firstDayOfWeek
+ // calendarWeekRule
+
+ // remember to reload tokens
+ ClearTokenHashTable();
+ }
+
+ // Remember the new calendar
+ calendar = value;
+ InitializeOverridableProperties(_cultureData, calendar.ID);
+
+ // We succeeded, return
+ return;
+ }
+ }
+
+ // The assigned calendar is not a valid calendar for this culture, throw
+ throw new ArgumentOutOfRangeException("value", SR.Argument_InvalidCalendar);
+ }
+ }
+
+ private CalendarId[] OptionalCalendars
+ {
+ get
+ {
+ if (this.optionalCalendars == null)
+ {
+ this.optionalCalendars = _cultureData.CalendarIds;
+ }
+ return (this.optionalCalendars);
+ }
+ }
+
+ /*=================================GetEra==========================
+ **Action: Get the era value by parsing the name of the era.
+ **Returns: The era value for the specified era name.
+ ** -1 if the name of the era is not valid or not supported.
+ **Arguments: eraName the name of the era.
+ **Exceptions: None.
+ ============================================================================*/
+
+
+ public int GetEra(String eraName)
+ {
+ if (eraName == null)
+ {
+ throw new ArgumentNullException("eraName",
+ SR.ArgumentNull_String);
+ }
+ Contract.EndContractBlock();
+
+ // The Era Name and Abbreviated Era Name
+ // for Taiwan Calendar on non-Taiwan SKU returns empty string (which
+ // would be matched below) but we don't want the empty string to give
+ // us an Era number
+ // confer 85900 DTFI.GetEra("") should fail on all cultures
+ if (eraName.Length == 0)
+ {
+ return (-1);
+ }
+
+ // The following is based on the assumption that the era value is starting from 1, and has a
+ // serial values.
+ // If that ever changes, the code has to be changed.
+
+ // The calls to String.Compare should use the current culture for the string comparisons, but the
+ // invariant culture when comparing against the english names.
+ for (int i = 0; i < EraNames.Length; i++)
+ {
+ // Compare the era name in a case-insensitive way for the appropriate culture.
+ if (m_eraNames[i].Length > 0)
+ {
+ if (this.Culture.CompareInfo.Compare(eraName, m_eraNames[i], CompareOptions.IgnoreCase) == 0)
+ {
+ return (i + 1);
+ }
+ }
+ }
+ for (int i = 0; i < AbbreviatedEraNames.Length; i++)
+ {
+ // Compare the abbreviated era name in a case-insensitive way for the appropriate culture.
+ if (this.Culture.CompareInfo.Compare(eraName, m_abbrevEraNames[i], CompareOptions.IgnoreCase) == 0)
+ {
+ return (i + 1);
+ }
+ }
+ for (int i = 0; i < AbbreviatedEnglishEraNames.Length; i++)
+ {
+ // this comparison should use the InvariantCulture. The English name could have linguistically
+ // interesting characters.
+ if (CultureInfo.InvariantCulture.CompareInfo.Compare(eraName, m_abbrevEnglishEraNames[i], CompareOptions.IgnoreCase) == 0)
+ {
+ return (i + 1);
+ }
+ }
+ return (-1);
+ }
+
+
+ internal String[] EraNames
+ {
+ get
+ {
+ if (this.m_eraNames == null)
+ {
+ this.m_eraNames = _cultureData.EraNames(Calendar.ID); ;
+ }
+ return (this.m_eraNames);
+ }
+ }
+
+ /*=================================GetEraName==========================
+ **Action: Get the name of the era for the specified era value.
+ **Returns: The name of the specified era.
+ **Arguments:
+ ** era the era value.
+ **Exceptions:
+ ** ArguementException if the era valie is invalid.
+ ============================================================================*/
+
+ // Era names are 1 indexed
+ public String GetEraName(int era)
+ {
+ if (era == Calendar.CurrentEra)
+ {
+ era = Calendar.CurrentEraValue;
+ }
+
+ // The following is based on the assumption that the era value is starting from 1, and has a
+ // serial values.
+ // If that ever changes, the code has to be changed.
+ if ((--era) < EraNames.Length && (era >= 0))
+ {
+ return (m_eraNames[era]);
+ }
+ throw new ArgumentOutOfRangeException("era", SR.ArgumentOutOfRange_InvalidEraValue);
+ }
+
+ internal String[] AbbreviatedEraNames
+ {
+ get
+ {
+ if (this.m_abbrevEraNames == null)
+ {
+ this.m_abbrevEraNames = _cultureData.AbbrevEraNames(Calendar.ID);
+ }
+ return (this.m_abbrevEraNames);
+ }
+ }
+
+ // Era names are 1 indexed
+ public String GetAbbreviatedEraName(int era)
+ {
+ if (AbbreviatedEraNames.Length == 0)
+ {
+ // If abbreviation era name is not used in this culture,
+ // return the full era name.
+ return (GetEraName(era));
+ }
+ if (era == Calendar.CurrentEra)
+ {
+ era = Calendar.CurrentEraValue;
+ }
+ if ((--era) < m_abbrevEraNames.Length && (era >= 0))
+ {
+ return (m_abbrevEraNames[era]);
+ }
+ throw new ArgumentOutOfRangeException("era", SR.ArgumentOutOfRange_InvalidEraValue);
+ }
+
+ internal String[] AbbreviatedEnglishEraNames
+ {
+ get
+ {
+ if (this.m_abbrevEnglishEraNames == null)
+ {
+ Contract.Assert(Calendar.ID > 0, "[DateTimeFormatInfo.AbbreviatedEnglishEraNames] Expected Calendar.ID > 0");
+ this.m_abbrevEnglishEraNames = _cultureData.AbbreviatedEnglishEraNames(Calendar.ID);
+ }
+ return (this.m_abbrevEnglishEraNames);
+ }
+ }
+
+
+ // Note that cultureData derives this from the short date format (unless someone's set this previously)
+ // Note that this property is quite undesirable.
+ internal String DateSeparator
+ {
+ get
+ {
+ if (this.dateSeparator == null)
+ {
+ this.dateSeparator = _cultureData.DateSeparator(Calendar.ID);
+ }
+ Contract.Assert(this.dateSeparator != null, "DateTimeFormatInfo.DateSeparator, dateSeparator != null");
+ return (this.dateSeparator);
+ }
+ set
+ {
+ throw null;
+ }
+ }
+
+
+ public DayOfWeek FirstDayOfWeek
+ {
+ get
+ {
+ if (this.firstDayOfWeek == -1)
+ {
+ this.firstDayOfWeek = _cultureData.IFIRSTDAYOFWEEK;
+ }
+ Contract.Assert(this.firstDayOfWeek != -1, "DateTimeFormatInfo.FirstDayOfWeek, firstDayOfWeek != -1");
+
+ return ((DayOfWeek)this.firstDayOfWeek);
+ }
+
+ set
+ {
+ if (IsReadOnly)
+ throw new InvalidOperationException(SR.InvalidOperation_ReadOnly);
+ if (value >= DayOfWeek.Sunday && value <= DayOfWeek.Saturday)
+ {
+ firstDayOfWeek = (int)value;
+ }
+ else
+ {
+ throw new ArgumentOutOfRangeException(
+ "value", SR.Format(SR.ArgumentOutOfRange_Range,
+ DayOfWeek.Sunday, DayOfWeek.Saturday));
+ }
+ }
+ }
+
+ public CalendarWeekRule CalendarWeekRule
+ {
+ get
+ {
+ if (this.calendarWeekRule == -1)
+ {
+ this.calendarWeekRule = _cultureData.IFIRSTWEEKOFYEAR;
+ }
+ Contract.Assert(this.calendarWeekRule != -1, "DateTimeFormatInfo.CalendarWeekRule, calendarWeekRule != -1");
+ return ((CalendarWeekRule)this.calendarWeekRule);
+ }
+
+ set
+ {
+ if (IsReadOnly)
+ throw new InvalidOperationException(SR.InvalidOperation_ReadOnly);
+ if (value >= CalendarWeekRule.FirstDay && value <= CalendarWeekRule.FirstFourDayWeek)
+ {
+ calendarWeekRule = (int)value;
+ }
+ else
+ {
+ throw new ArgumentOutOfRangeException(
+ "value", SR.Format(SR.ArgumentOutOfRange_Range,
+ CalendarWeekRule.FirstDay, CalendarWeekRule.FirstFourDayWeek));
+ }
+ }
+ }
+
+ public String FullDateTimePattern
+ {
+ get
+ {
+ if (fullDateTimePattern == null)
+ {
+ fullDateTimePattern = LongDatePattern + " " + LongTimePattern;
+ }
+ return (fullDateTimePattern);
+ }
+
+ set
+ {
+ if (IsReadOnly)
+ throw new InvalidOperationException(SR.InvalidOperation_ReadOnly);
+ if (value == null)
+ {
+ throw new ArgumentNullException("value",
+ SR.ArgumentNull_String);
+ }
+ Contract.EndContractBlock();
+ fullDateTimePattern = value;
+ }
+ }
+
+
+ // For our "patterns" arrays we have 2 variables, a string and a string[]
+ //
+ // The string[] contains the list of patterns, EXCEPT the default may not be included.
+ // The string contains the default pattern.
+ // When we initially construct our string[], we set the string to string[0]
+ public String LongDatePattern
+ {
+ get
+ {
+ // Initialize our long date pattern from the 1st array value if not set
+ if (this.longDatePattern == null)
+ {
+ // Initialize our data
+ this.longDatePattern = this.UnclonedLongDatePatterns[0];
+ }
+
+ return this.longDatePattern;
+ }
+
+ set
+ {
+ if (IsReadOnly)
+ throw new InvalidOperationException(SR.InvalidOperation_ReadOnly);
+ if (value == null)
+ {
+ throw new ArgumentNullException("value",
+ SR.ArgumentNull_String);
+ }
+ Contract.EndContractBlock();
+
+ // Remember the new string
+ this.longDatePattern = value;
+
+ // Clear the token hash table
+ ClearTokenHashTable();
+
+ // Clean up cached values that will be affected by this property.
+ this.fullDateTimePattern = null;
+ }
+ }
+
+ // For our "patterns" arrays we have 2 variables, a string and a string[]
+ //
+ // The string[] contains the list of patterns, EXCEPT the default may not be included.
+ // The string contains the default pattern.
+ // When we initially construct our string[], we set the string to string[0]
+ public String LongTimePattern
+ {
+ get
+ {
+ // Initialize our long time pattern from the 1st array value if not set
+ if (this.longTimePattern == null)
+ {
+ // Initialize our data
+ this.longTimePattern = this.UnclonedLongTimePatterns[0];
+ }
+
+ return this.longTimePattern;
+ }
+
+ set
+ {
+ if (IsReadOnly)
+ throw new InvalidOperationException(SR.InvalidOperation_ReadOnly);
+ if (value == null)
+ {
+ throw new ArgumentNullException("value",
+ SR.ArgumentNull_String);
+ }
+ Contract.EndContractBlock();
+
+ // Remember the new string
+ this.longTimePattern = value;
+
+ // Clear the token hash table
+ ClearTokenHashTable();
+
+ // Clean up cached values that will be affected by this property.
+ this.fullDateTimePattern = null; // Full date = long date + long Time
+ this.generalLongTimePattern = null; // General long date = short date + long Time
+ this.dateTimeOffsetPattern = null;
+ }
+ }
+
+
+ // Note: just to be confusing there's only 1 month day pattern, not a whole list
+ public String MonthDayPattern
+ {
+ get
+ {
+ if (this.monthDayPattern == null)
+ {
+ Contract.Assert(Calendar.ID > 0, "[DateTimeFormatInfo.MonthDayPattern] Expected calID > 0");
+ this.monthDayPattern = _cultureData.MonthDay(Calendar.ID);
+ }
+ Contract.Assert(this.monthDayPattern != null, "DateTimeFormatInfo.MonthDayPattern, monthDayPattern != null");
+ return (this.monthDayPattern);
+ }
+
+ set
+ {
+ if (IsReadOnly)
+ throw new InvalidOperationException(SR.InvalidOperation_ReadOnly);
+ if (value == null)
+ {
+ throw new ArgumentNullException("value",
+ SR.ArgumentNull_String);
+ }
+ Contract.EndContractBlock();
+
+ this.monthDayPattern = value;
+ }
+ }
+
+
+ public String PMDesignator
+ {
+ // auto-generated
+ get
+ {
+ if (this.pmDesignator == null)
+ {
+ this.pmDesignator = _cultureData.SPM2359;
+ }
+ Contract.Assert(this.pmDesignator != null, "DateTimeFormatInfo.PMDesignator, pmDesignator != null");
+ return (this.pmDesignator);
+ }
+
+ set
+ {
+ if (IsReadOnly)
+ throw new InvalidOperationException(SR.InvalidOperation_ReadOnly);
+ if (value == null)
+ {
+ throw new ArgumentNullException("value",
+ SR.ArgumentNull_String);
+ }
+ Contract.EndContractBlock();
+ ClearTokenHashTable();
+
+ pmDesignator = value;
+ }
+ }
+
+
+ public String RFC1123Pattern
+ {
+ get
+ {
+ return (rfc1123Pattern);
+ }
+ }
+
+ // For our "patterns" arrays we have 2 variables, a string and a string[]
+ //
+ // The string[] contains the list of patterns, EXCEPT the default may not be included.
+ // The string contains the default pattern.
+ // When we initially construct our string[], we set the string to string[0]
+ public String ShortDatePattern
+ {
+ get
+ {
+ // Initialize our short date pattern from the 1st array value if not set
+ if (this.shortDatePattern == null)
+ {
+ // Initialize our data
+ this.shortDatePattern = this.UnclonedShortDatePatterns[0];
+ }
+
+ return this.shortDatePattern;
+ }
+
+ set
+ {
+ if (IsReadOnly)
+ throw new InvalidOperationException(SR.InvalidOperation_ReadOnly);
+ if (value == null)
+ throw new ArgumentNullException("value",
+ SR.ArgumentNull_String);
+ Contract.EndContractBlock();
+
+ // Remember the new string
+ this.shortDatePattern = value;
+
+ // Clear the token hash table, note that even short dates could require this
+ ClearTokenHashTable();
+
+ // Clean up cached values that will be affected by this property.
+ generalLongTimePattern = null; // General long time = short date + long time
+ generalShortTimePattern = null; // General short time = short date + short Time
+ dateTimeOffsetPattern = null;
+ }
+ }
+
+
+ // For our "patterns" arrays we have 2 variables, a string and a string[]
+ //
+ // The string[] contains the list of patterns, EXCEPT the default may not be included.
+ // The string contains the default pattern.
+ // When we initially construct our string[], we set the string to string[0]
+ public String ShortTimePattern
+ {
+ get
+ {
+ // Initialize our short time pattern from the 1st array value if not set
+ if (this.shortTimePattern == null)
+ {
+ // Initialize our data
+ this.shortTimePattern = this.UnclonedShortTimePatterns[0];
+ }
+ return this.shortTimePattern;
+ }
+
+ set
+ {
+ if (IsReadOnly)
+ throw new InvalidOperationException(SR.InvalidOperation_ReadOnly);
+ if (value == null)
+ {
+ throw new ArgumentNullException("value",
+ SR.ArgumentNull_String);
+ }
+ Contract.EndContractBlock();
+
+ // Remember the new string
+ this.shortTimePattern = value;
+
+ // Clear the token hash table, note that even short times could require this
+ ClearTokenHashTable();
+
+ // Clean up cached values that will be affected by this property.
+ generalShortTimePattern = null; // General short date = short date + short time.
+ }
+ }
+
+
+ public String SortableDateTimePattern
+ {
+ get
+ {
+ return (sortableDateTimePattern);
+ }
+ }
+
+ /*=================================GeneralShortTimePattern=====================
+ **Property: Return the pattern for 'g' general format: shortDate + short time
+ **Note: This is used by DateTimeFormat.cs to get the pattern for 'g'
+ ** We put this internal property here so that we can avoid doing the
+ ** concatation every time somebody asks for the general format.
+ ==============================================================================*/
+
+ internal String GeneralShortTimePattern
+ {
+ get
+ {
+ if (generalShortTimePattern == null)
+ {
+ generalShortTimePattern = ShortDatePattern + " " + ShortTimePattern;
+ }
+ return (generalShortTimePattern);
+ }
+ }
+
+ /*=================================GeneralLongTimePattern=====================
+ **Property: Return the pattern for 'g' general format: shortDate + Long time
+ **Note: This is used by DateTimeFormat.cs to get the pattern for 'g'
+ ** We put this internal property here so that we can avoid doing the
+ ** concatation every time somebody asks for the general format.
+ ==============================================================================*/
+
+ internal String GeneralLongTimePattern
+ {
+ get
+ {
+ if (generalLongTimePattern == null)
+ {
+ generalLongTimePattern = ShortDatePattern + " " + LongTimePattern;
+ }
+ return (generalLongTimePattern);
+ }
+ }
+
+ /*=================================DateTimeOffsetPattern==========================
+ **Property: Return the default pattern DateTimeOffset : shortDate + long time + time zone offset
+ **Note: This is used by DateTimeFormat.cs to get the pattern for short Date + long time + time zone offset
+ ** We put this internal property here so that we can avoid doing the
+ ** concatation every time somebody uses this form
+ ==============================================================================*/
+
+ /*=================================DateTimeOffsetPattern==========================
+ **Property: Return the default pattern DateTimeOffset : shortDate + long time + time zone offset
+ **Note: This is used by DateTimeFormat.cs to get the pattern for short Date + long time + time zone offset
+ ** We put this internal property here so that we can avoid doing the
+ ** concatation every time somebody uses this form
+ ==============================================================================*/
+
+ internal String DateTimeOffsetPattern
+ {
+ get
+ {
+ if (dateTimeOffsetPattern == null)
+ {
+ string dateTimePattern = ShortDatePattern + " " + LongTimePattern;
+
+ /* LongTimePattern might contain a "z" as part of the format string in which case we don't want to append a time zone offset */
+
+ bool foundZ = false;
+ bool inQuote = false;
+ char quote = '\'';
+ for (int i = 0; !foundZ && i < LongTimePattern.Length; i++)
+ {
+ switch (LongTimePattern[i])
+ {
+ case 'z':
+ /* if we aren't in a quote, we've found a z */
+ foundZ = !inQuote;
+ /* we'll fall out of the loop now because the test includes !foundZ */
+ break;
+ case '\'':
+ case '\"':
+ if (inQuote && (quote == LongTimePattern[i]))
+ {
+ /* we were in a quote and found a matching exit quote, so we are outside a quote now */
+ inQuote = false;
+ }
+ else if (!inQuote)
+ {
+ quote = LongTimePattern[i];
+ inQuote = true;
+ }
+ else
+ {
+ /* we were in a quote and saw the other type of quote character, so we are still in a quote */
+ }
+ break;
+ case '%':
+ case '\\':
+ i++; /* skip next character that is escaped by this backslash */
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (!foundZ)
+ {
+ dateTimePattern = dateTimePattern + " zzz";
+ }
+
+ dateTimeOffsetPattern = dateTimePattern;
+ }
+ return (dateTimeOffsetPattern);
+ }
+ }
+
+ // Note that cultureData derives this from the long time format (unless someone's set this previously)
+ // Note that this property is quite undesirable.
+ internal String TimeSeparator
+ {
+ get
+ {
+ if (timeSeparator == null)
+ {
+ timeSeparator = _cultureData.TimeSeparator;
+ }
+ Contract.Assert(this.timeSeparator != null, "DateTimeFormatInfo.TimeSeparator, timeSeparator != null");
+ return (timeSeparator);
+ }
+
+ set
+ {
+ throw null;
+ }
+ }
+
+
+ public String UniversalSortableDateTimePattern
+ {
+ get
+ {
+ return (universalSortableDateTimePattern);
+ }
+ }
+
+ // For our "patterns" arrays we have 2 variables, a string and a string[]
+ //
+ // The string[] contains the list of patterns, EXCEPT the default may not be included.
+ // The string contains the default pattern.
+ // When we initially construct our string[], we set the string to string[0]
+ public String YearMonthPattern
+ {
+ get
+ {
+ // Initialize our year/month pattern from the 1st array value if not set
+ if (this.yearMonthPattern == null)
+ {
+ // Initialize our data
+ this.yearMonthPattern = this.UnclonedYearMonthPatterns[0];
+ }
+ return this.yearMonthPattern;
+ }
+
+ set
+ {
+ if (IsReadOnly)
+ throw new InvalidOperationException(SR.InvalidOperation_ReadOnly);
+ if (value == null)
+ {
+ throw new ArgumentNullException("value",
+ SR.ArgumentNull_String);
+ }
+ Contract.EndContractBlock();
+
+ // Remember the new string
+ this.yearMonthPattern = value;
+
+ // Clear the token hash table, note that even short times could require this
+ ClearTokenHashTable();
+ }
+ }
+
+ //
+ // Check if a string array contains a null value, and throw ArgumentNullException with parameter name "value"
+ //
+ private static void CheckNullValue(String[] values, int length)
+ {
+ Contract.Requires(values != null, "value != null");
+ Contract.Requires(values.Length >= length);
+ for (int i = 0; i < length; i++)
+ {
+ if (values[i] == null)
+ {
+ throw new ArgumentNullException("value",
+ SR.ArgumentNull_ArrayValue);
+ }
+ }
+ }
+
+
+ public String[] AbbreviatedDayNames
+ {
+ get
+ {
+ return ((String[])internalGetAbbreviatedDayOfWeekNames().Clone());
+ }
+
+ set
+ {
+ if (IsReadOnly)
+ throw new InvalidOperationException(SR.InvalidOperation_ReadOnly);
+ if (value == null)
+ {
+ throw new ArgumentNullException("value",
+ SR.ArgumentNull_Array);
+ }
+ if (value.Length != 7)
+ {
+ throw new ArgumentException(SR.Format(SR.Argument_InvalidArrayLength, 7), "value");
+ }
+ Contract.EndContractBlock();
+ CheckNullValue(value, value.Length);
+ ClearTokenHashTable();
+
+ abbreviatedDayNames = value;
+ }
+ }
+
+ // Returns the string array of the one-letter day of week names.
+ [System.Runtime.InteropServices.ComVisible(false)]
+ public String[] ShortestDayNames
+ {
+ get
+ {
+ return ((String[])internalGetSuperShortDayNames().Clone());
+ }
+
+ set
+ {
+ if (IsReadOnly)
+ throw new InvalidOperationException(SR.InvalidOperation_ReadOnly);
+ if (value == null)
+ {
+ throw new ArgumentNullException("value",
+ SR.ArgumentNull_Array);
+ }
+ if (value.Length != 7)
+ {
+ throw new ArgumentException(SR.Format(SR.Argument_InvalidArrayLength, 7), "value");
+ }
+ Contract.EndContractBlock();
+ CheckNullValue(value, value.Length);
+ this.m_superShortDayNames = value;
+ }
+ }
+
+
+ public String[] DayNames
+ {
+ get
+ {
+ return ((String[])internalGetDayOfWeekNames().Clone());
+ }
+
+ set
+ {
+ if (IsReadOnly)
+ throw new InvalidOperationException(SR.InvalidOperation_ReadOnly);
+ if (value == null)
+ {
+ throw new ArgumentNullException("value",
+ SR.ArgumentNull_Array);
+ }
+ if (value.Length != 7)
+ {
+ throw new ArgumentException(SR.Format(SR.Argument_InvalidArrayLength, 7), "value");
+ }
+ Contract.EndContractBlock();
+ CheckNullValue(value, value.Length);
+ ClearTokenHashTable();
+
+ dayNames = value;
+ }
+ }
+
+
+ public String[] AbbreviatedMonthNames
+ {
+ get
+ {
+ return ((String[])internalGetAbbreviatedMonthNames().Clone());
+ }
+
+ set
+ {
+ if (IsReadOnly)
+ throw new InvalidOperationException(SR.InvalidOperation_ReadOnly);
+ if (value == null)
+ {
+ throw new ArgumentNullException("value",
+ SR.ArgumentNull_Array);
+ }
+ if (value.Length != 13)
+ {
+ throw new ArgumentException(SR.Format(SR.Argument_InvalidArrayLength, 13), "value");
+ }
+ Contract.EndContractBlock();
+ CheckNullValue(value, value.Length - 1);
+ ClearTokenHashTable();
+ abbreviatedMonthNames = value;
+ }
+ }
+
+
+ public String[] MonthNames
+ {
+ get
+ {
+ return ((String[])internalGetMonthNames().Clone());
+ }
+
+ set
+ {
+ if (IsReadOnly)
+ throw new InvalidOperationException(SR.InvalidOperation_ReadOnly);
+ if (value == null)
+ {
+ throw new ArgumentNullException("value",
+ SR.ArgumentNull_Array);
+ }
+ if (value.Length != 13)
+ {
+ throw new ArgumentException(SR.Format(SR.Argument_InvalidArrayLength, 13), "value");
+ }
+ Contract.EndContractBlock();
+ CheckNullValue(value, value.Length - 1);
+ monthNames = value;
+ ClearTokenHashTable();
+ }
+ }
+
+ // Whitespaces that we allow in the month names.
+ // U+00a0 is non-breaking space.
+ private static readonly char[] s_monthSpaces = { ' ', '\u00a0' };
+
+ internal bool HasSpacesInMonthNames
+ {
+ get
+ {
+ return (FormatFlags & DateTimeFormatFlags.UseSpacesInMonthNames) != 0;
+ }
+ }
+
+ internal bool HasSpacesInDayNames
+ {
+ get
+ {
+ return (FormatFlags & DateTimeFormatFlags.UseSpacesInDayNames) != 0;
+ }
+ }
+
+
+ //
+ // internalGetMonthName
+ //
+ // Actions: Return the month name using the specified MonthNameStyles in either abbreviated form
+ // or full form.
+ // Arguments:
+ // month
+ // style To indicate a form like regular/genitive/month name in a leap year.
+ // abbreviated When true, return abbreviated form. Otherwise, return a full form.
+ // Exceptions:
+ // ArgumentOutOfRangeException When month name is invalid.
+ //
+ internal String internalGetMonthName(int month, MonthNameStyles style, bool abbreviated)
+ {
+ //
+ // Right now, style is mutual exclusive, but I make the style to be flag so that
+ // maybe we can combine flag if there is such a need.
+ //
+ String[] monthNamesArray = null;
+ switch (style)
+ {
+ case MonthNameStyles.Genitive:
+ monthNamesArray = internalGetGenitiveMonthNames(abbreviated);
+ break;
+ case MonthNameStyles.LeapYear:
+ monthNamesArray = internalGetLeapYearMonthNames(/*abbreviated*/);
+ break;
+ default:
+ monthNamesArray = (abbreviated ? internalGetAbbreviatedMonthNames() : internalGetMonthNames());
+ break;
+ }
+ // The month range is from 1 ~ this.m_monthNames.Length
+ // (actually is 13 right now for all cases)
+ if ((month < 1) || (month > monthNamesArray.Length))
+ {
+ throw new ArgumentOutOfRangeException(
+ "month", SR.Format(SR.ArgumentOutOfRange_Range,
+ 1, monthNamesArray.Length));
+ }
+ return (monthNamesArray[month - 1]);
+ }
+
+ //
+ // internalGetGenitiveMonthNames
+ //
+ // Action: Retrieve the array which contains the month names in genitive form.
+ // If this culture does not use the gentive form, the normal month name is returned.
+ // Arguments:
+ // abbreviated When true, return abbreviated form. Otherwise, return a full form.
+ //
+ private String[] internalGetGenitiveMonthNames(bool abbreviated)
+ {
+ if (abbreviated)
+ {
+ if (this.m_genitiveAbbreviatedMonthNames == null)
+ {
+ this.m_genitiveAbbreviatedMonthNames = _cultureData.AbbreviatedGenitiveMonthNames(this.Calendar.ID);
+ Contract.Assert(this.m_genitiveAbbreviatedMonthNames.Length == 13,
+ "[DateTimeFormatInfo.GetGenitiveMonthNames] Expected 13 abbreviated genitive month names in a year");
+ }
+ return (this.m_genitiveAbbreviatedMonthNames);
+ }
+
+ if (this.genitiveMonthNames == null)
+ {
+ this.genitiveMonthNames = _cultureData.GenitiveMonthNames(this.Calendar.ID);
+ Contract.Assert(this.genitiveMonthNames.Length == 13,
+ "[DateTimeFormatInfo.GetGenitiveMonthNames] Expected 13 genitive month names in a year");
+ }
+ return (this.genitiveMonthNames);
+ }
+
+ //
+ // internalGetLeapYearMonthNames
+ //
+ // Actions: Retrieve the month names used in a leap year.
+ // If this culture does not have different month names in a leap year, the normal month name is returned.
+ // Agruments: None. (can use abbreviated later if needed)
+ //
+ internal String[] internalGetLeapYearMonthNames(/*bool abbreviated*/)
+ {
+ if (this.leapYearMonthNames == null)
+ {
+ Contract.Assert(Calendar.ID > 0, "[DateTimeFormatInfo.internalGetLeapYearMonthNames] Expected Calendar.ID > 0");
+ this.leapYearMonthNames = _cultureData.LeapYearMonthNames(Calendar.ID);
+ Contract.Assert(this.leapYearMonthNames.Length == 13,
+ "[DateTimeFormatInfo.internalGetLeapYearMonthNames] Expepcted 13 leap year month names");
+ }
+ return (leapYearMonthNames);
+ }
+
+
+ public String GetAbbreviatedDayName(DayOfWeek dayofweek)
+ {
+ if ((int)dayofweek < 0 || (int)dayofweek > 6)
+ {
+ throw new ArgumentOutOfRangeException(
+ "dayofweek", SR.Format(SR.ArgumentOutOfRange_Range,
+ DayOfWeek.Sunday, DayOfWeek.Saturday));
+ }
+ Contract.EndContractBlock();
+ //
+ // Don't call the public property AbbreviatedDayNames here since a clone is needed in that
+ // property, so it will be slower. Instead, use GetAbbreviatedDayOfWeekNames() directly.
+ //
+ return (internalGetAbbreviatedDayOfWeekNames()[(int)dayofweek]);
+ }
+
+ // Get all possible combination of inputs
+ private static String[] GetCombinedPatterns(String[] patterns1, String[] patterns2, String connectString)
+ {
+ Contract.Requires(patterns1 != null);
+ Contract.Requires(patterns2 != null);
+
+ // Get array size
+ String[] result = new String[patterns1.Length * patterns2.Length];
+
+ // Counter of actual results
+ int k = 0;
+ for (int i = 0; i < patterns1.Length; i++)
+ {
+ for (int j = 0; j < patterns2.Length; j++)
+ {
+ // Can't combine if null or empty
+ result[k++] = patterns1[i] + connectString + patterns2[j];
+ }
+ }
+
+ // Return the combinations
+ return (result);
+ }
+
+
+ // auto-generated
+ internal String[] GetAllDateTimePatterns(char format)
+ {
+ Contract.Ensures(Contract.Result<String[]>() != null);
+ String[] result = null;
+
+ switch (format)
+ {
+ case 'd':
+ result = this.AllShortDatePatterns;
+ break;
+ case 'D':
+ result = this.AllLongDatePatterns;
+ break;
+ case 'f':
+ result = GetCombinedPatterns(AllLongDatePatterns, AllShortTimePatterns, " ");
+ break;
+ case 'F':
+ case 'U':
+ result = GetCombinedPatterns(AllLongDatePatterns, AllLongTimePatterns, " ");
+ break;
+ case 'g':
+ result = GetCombinedPatterns(AllShortDatePatterns, AllShortTimePatterns, " ");
+ break;
+ case 'G':
+ result = GetCombinedPatterns(AllShortDatePatterns, AllLongTimePatterns, " ");
+ break;
+ case 'm':
+ case 'M':
+ result = new String[] { MonthDayPattern };
+ break;
+ case 'o':
+ case 'O':
+ result = new String[] { RoundtripFormat };
+ break;
+ case 'r':
+ case 'R':
+ result = new String[] { rfc1123Pattern };
+ break;
+ case 's':
+ result = new String[] { sortableDateTimePattern };
+ break;
+ case 't':
+ result = this.AllShortTimePatterns;
+ break;
+ case 'T':
+ result = this.AllLongTimePatterns;
+ break;
+ case 'u':
+ result = new String[] { UniversalSortableDateTimePattern };
+ break;
+ case 'y':
+ case 'Y':
+ result = this.AllYearMonthPatterns;
+ break;
+ default:
+ throw new ArgumentException(SR.Format_BadFormatSpecifier, "format");
+ }
+ return (result);
+ }
+
+
+ public String GetDayName(DayOfWeek dayofweek)
+ {
+ if ((int)dayofweek < 0 || (int)dayofweek > 6)
+ {
+ throw new ArgumentOutOfRangeException(
+ "dayofweek", SR.Format(SR.ArgumentOutOfRange_Range,
+ DayOfWeek.Sunday, DayOfWeek.Saturday));
+ }
+ Contract.EndContractBlock();
+
+ // Use the internal one so that we don't clone the array unnecessarily
+ return (internalGetDayOfWeekNames()[(int)dayofweek]);
+ }
+
+
+
+ public String GetAbbreviatedMonthName(int month)
+ {
+ if (month < 1 || month > 13)
+ {
+ throw new ArgumentOutOfRangeException(
+ "month", SR.Format(SR.ArgumentOutOfRange_Range,
+ 1, 13));
+ }
+ Contract.EndContractBlock();
+ // Use the internal one so we don't clone the array unnecessarily
+ return (internalGetAbbreviatedMonthNames()[month - 1]);
+ }
+
+
+ public String GetMonthName(int month)
+ {
+ if (month < 1 || month > 13)
+ {
+ throw new ArgumentOutOfRangeException(
+ "month", SR.Format(SR.ArgumentOutOfRange_Range,
+ 1, 13));
+ }
+ Contract.EndContractBlock();
+ // Use the internal one so we don't clone the array unnecessarily
+ return (internalGetMonthNames()[month - 1]);
+ }
+
+ // For our "patterns" arrays we have 2 variables, a string and a string[]
+ //
+ // The string[] contains the list of patterns, EXCEPT the default may not be included.
+ // The string contains the default pattern.
+ // When we initially construct our string[], we set the string to string[0]
+ //
+ // The resulting [] can get returned to the calling app, so clone it.
+ private static string[] GetMergedPatterns(string[] patterns, string defaultPattern)
+ {
+ Contract.Assert(patterns != null && patterns.Length > 0,
+ "[DateTimeFormatInfo.GetMergedPatterns]Expected array of at least one pattern");
+ Contract.Assert(defaultPattern != null,
+ "[DateTimeFormatInfo.GetMergedPatterns]Expected non null default string");
+
+ // If the default happens to be the first in the list just return (a cloned) copy
+ if (defaultPattern == patterns[0])
+ {
+ return (string[])patterns.Clone();
+ }
+
+ // We either need a bigger list, or the pattern from the list.
+ int i;
+ for (i = 0; i < patterns.Length; i++)
+ {
+ // Stop if we found it
+ if (defaultPattern == patterns[i])
+ break;
+ }
+
+ // Either way we're going to need a new array
+ string[] newPatterns;
+
+ // Did we find it
+ if (i < patterns.Length)
+ {
+ // Found it, output will be same size
+ newPatterns = (string[])patterns.Clone();
+
+ // Have to move [0] item to [i] so we can re-write default at [0]
+ // (remember defaultPattern == [i] so this is OK)
+ newPatterns[i] = newPatterns[0];
+ }
+ else
+ {
+ // Not found, make room for it
+ newPatterns = new String[patterns.Length + 1];
+
+ // Copy existing array
+ Array.Copy(patterns, 0, newPatterns, 1, patterns.Length);
+ }
+
+ // Remember the default
+ newPatterns[0] = defaultPattern;
+
+ // Return the reconstructed list
+ return newPatterns;
+ }
+
+ // Needed by DateTimeFormatInfo and DateTimeFormat
+ internal const String RoundtripFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss.fffffffK";
+ internal const String RoundtripDateTimeUnfixed = "yyyy'-'MM'-'ddTHH':'mm':'ss zzz";
+
+ // Default string isn't necessarily in our string array, so get the
+ // merged patterns of both
+ private String[] AllYearMonthPatterns
+ {
+ get
+ {
+ return GetMergedPatterns(this.UnclonedYearMonthPatterns, this.YearMonthPattern);
+ }
+ }
+
+ private String[] AllShortDatePatterns
+ {
+ get
+ {
+ return GetMergedPatterns(this.UnclonedShortDatePatterns, this.ShortDatePattern);
+ }
+ }
+
+ private String[] AllShortTimePatterns
+ {
+ get
+ {
+ return GetMergedPatterns(this.UnclonedShortTimePatterns, this.ShortTimePattern);
+ }
+ }
+
+ private String[] AllLongDatePatterns
+ {
+ get
+ {
+ return GetMergedPatterns(this.UnclonedLongDatePatterns, this.LongDatePattern);
+ }
+ }
+
+ private String[] AllLongTimePatterns
+ {
+ get
+ {
+ return GetMergedPatterns(this.UnclonedLongTimePatterns, this.LongTimePattern);
+ }
+ }
+
+ // NOTE: Clone this string array if you want to return it to user. Otherwise, you are returning a writable cache copy.
+ // This won't include default, call AllYearMonthPatterns
+ private String[] UnclonedYearMonthPatterns
+ {
+ get
+ {
+ if (this.allYearMonthPatterns == null)
+ {
+ Contract.Assert(Calendar.ID > 0, "[DateTimeFormatInfo.UnclonedYearMonthPatterns] Expected Calendar.ID > 0");
+ this.allYearMonthPatterns = _cultureData.YearMonths(this.Calendar.ID);
+ Contract.Assert(this.allYearMonthPatterns.Length > 0,
+ "[DateTimeFormatInfo.UnclonedYearMonthPatterns] Expected some year month patterns");
+ }
+
+ return this.allYearMonthPatterns;
+ }
+ }
+
+
+ // NOTE: Clone this string array if you want to return it to user. Otherwise, you are returning a writable cache copy.
+ // This won't include default, call AllShortDatePatterns
+ private String[] UnclonedShortDatePatterns
+ {
+ get
+ {
+ if (allShortDatePatterns == null)
+ {
+ Contract.Assert(Calendar.ID > 0, "[DateTimeFormatInfo.UnclonedShortDatePatterns] Expected Calendar.ID > 0");
+ this.allShortDatePatterns = _cultureData.ShortDates(this.Calendar.ID);
+ Contract.Assert(this.allShortDatePatterns.Length > 0,
+ "[DateTimeFormatInfo.UnclonedShortDatePatterns] Expected some short date patterns");
+ }
+
+ return this.allShortDatePatterns;
+ }
+ }
+
+ // NOTE: Clone this string array if you want to return it to user. Otherwise, you are returning a writable cache copy.
+ // This won't include default, call AllLongDatePatterns
+ private String[] UnclonedLongDatePatterns
+ {
+ get
+ {
+ if (allLongDatePatterns == null)
+ {
+ Contract.Assert(Calendar.ID > 0, "[DateTimeFormatInfo.UnclonedLongDatePatterns] Expected Calendar.ID > 0");
+ this.allLongDatePatterns = _cultureData.LongDates(this.Calendar.ID);
+ Contract.Assert(this.allLongDatePatterns.Length > 0,
+ "[DateTimeFormatInfo.UnclonedLongDatePatterns] Expected some long date patterns");
+ }
+
+ return this.allLongDatePatterns;
+ }
+ }
+
+ // NOTE: Clone this string array if you want to return it to user. Otherwise, you are returning a writable cache copy.
+ // This won't include default, call AllShortTimePatterns
+ private String[] UnclonedShortTimePatterns
+ {
+ get
+ {
+ if (this.allShortTimePatterns == null)
+ {
+ this.allShortTimePatterns = _cultureData.ShortTimes;
+ Contract.Assert(this.allShortTimePatterns.Length > 0,
+ "[DateTimeFormatInfo.UnclonedShortTimePatterns] Expected some short time patterns");
+ }
+
+ return this.allShortTimePatterns;
+ }
+ }
+
+ // NOTE: Clone this string array if you want to return it to user. Otherwise, you are returning a writable cache copy.
+ // This won't include default, call AllLongTimePatterns
+ private String[] UnclonedLongTimePatterns
+ {
+ get
+ {
+ if (this.allLongTimePatterns == null)
+ {
+ this.allLongTimePatterns = _cultureData.LongTimes;
+ Contract.Assert(this.allLongTimePatterns.Length > 0,
+ "[DateTimeFormatInfo.UnclonedLongTimePatterns] Expected some long time patterns");
+ }
+
+ return this.allLongTimePatterns;
+ }
+ }
+
+ public static DateTimeFormatInfo ReadOnly(DateTimeFormatInfo dtfi)
+ {
+ if (dtfi == null)
+ {
+ throw new ArgumentNullException("dtfi",
+ SR.ArgumentNull_Obj);
+ }
+ Contract.EndContractBlock();
+ if (dtfi.IsReadOnly)
+ {
+ return (dtfi);
+ }
+ DateTimeFormatInfo newInfo = (DateTimeFormatInfo)(dtfi.MemberwiseClone());
+ // We can use the data member calendar in the setter, instead of the property Calendar,
+ // since the cloned copy should have the same state as the original copy.
+ newInfo.calendar = Calendar.ReadOnly(dtfi.Calendar);
+ newInfo._isReadOnly = true;
+ return (newInfo);
+ }
+
+ public bool IsReadOnly
+ {
+ get
+ {
+ return (_isReadOnly);
+ }
+ }
+
+ [System.Runtime.InteropServices.ComVisible(false)]
+ public String[] AbbreviatedMonthGenitiveNames
+ {
+ get
+ {
+ return ((String[])internalGetGenitiveMonthNames(true).Clone());
+ }
+
+ set
+ {
+ if (IsReadOnly)
+ throw new InvalidOperationException(SR.InvalidOperation_ReadOnly);
+ if (value == null)
+ {
+ throw new ArgumentNullException("value",
+ SR.ArgumentNull_Array);
+ }
+ if (value.Length != 13)
+ {
+ throw new ArgumentException(SR.Format(SR.Argument_InvalidArrayLength, 13), "value");
+ }
+ Contract.EndContractBlock();
+ CheckNullValue(value, value.Length - 1);
+ ClearTokenHashTable();
+ this.m_genitiveAbbreviatedMonthNames = value;
+ }
+ }
+
+ [System.Runtime.InteropServices.ComVisible(false)]
+ public String[] MonthGenitiveNames
+ {
+ get
+ {
+ return ((String[])internalGetGenitiveMonthNames(false).Clone());
+ }
+
+ set
+ {
+ if (IsReadOnly)
+ throw new InvalidOperationException(SR.InvalidOperation_ReadOnly);
+ if (value == null)
+ {
+ throw new ArgumentNullException("value",
+ SR.ArgumentNull_Array);
+ }
+ if (value.Length != 13)
+ {
+ throw new ArgumentException(SR.Format(SR.Argument_InvalidArrayLength, 13), "value");
+ }
+ Contract.EndContractBlock();
+ CheckNullValue(value, value.Length - 1);
+ genitiveMonthNames = value;
+ ClearTokenHashTable();
+ }
+ }
+
+ //
+ // Positive TimeSpan Pattern
+ //
+
+ private string _fullTimeSpanPositivePattern;
+ internal String FullTimeSpanPositivePattern
+ {
+ get
+ {
+ if (_fullTimeSpanPositivePattern == null)
+ {
+ CultureData cultureDataWithoutUserOverrides;
+ if (_cultureData.UseUserOverride)
+ cultureDataWithoutUserOverrides = CultureData.GetCultureData(_cultureData.CultureName, false);
+ else
+ cultureDataWithoutUserOverrides = _cultureData;
+ String decimalSeparator = new NumberFormatInfo(cultureDataWithoutUserOverrides).NumberDecimalSeparator;
+
+ _fullTimeSpanPositivePattern = "d':'h':'mm':'ss'" + decimalSeparator + "'FFFFFFF";
+ }
+ return _fullTimeSpanPositivePattern;
+ }
+ }
+
+ //
+ // Negative TimeSpan Pattern
+ //
+
+ private string _fullTimeSpanNegativePattern;
+ internal String FullTimeSpanNegativePattern
+ {
+ get
+ {
+ if (_fullTimeSpanNegativePattern == null)
+ _fullTimeSpanNegativePattern = "'-'" + FullTimeSpanPositivePattern;
+ return _fullTimeSpanNegativePattern;
+ }
+ }
+
+ //
+ // Get suitable CompareInfo from current DTFI object.
+ //
+ internal CompareInfo CompareInfo
+ {
+ get
+ {
+ if (_compareInfo == null)
+ {
+ // We use the regular GetCompareInfo here to make sure the created CompareInfo object is stored in the
+ // CompareInfo cache. otherwise we would just create CompareInfo using _cultureData.
+ _compareInfo = CompareInfo.GetCompareInfo(_cultureData.SCOMPAREINFO);
+ }
+
+ return _compareInfo;
+ }
+ }
+
+
+ internal const DateTimeStyles InvalidDateTimeStyles = ~(DateTimeStyles.AllowLeadingWhite | DateTimeStyles.AllowTrailingWhite
+ | DateTimeStyles.AllowInnerWhite | DateTimeStyles.NoCurrentDateDefault
+ | DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeLocal
+ | DateTimeStyles.AssumeUniversal | DateTimeStyles.RoundtripKind);
+
+ internal static void ValidateStyles(DateTimeStyles style, String parameterName)
+ {
+ if ((style & InvalidDateTimeStyles) != 0)
+ {
+ throw new ArgumentException(SR.Argument_InvalidDateTimeStyles, parameterName);
+ }
+ if (((style & (DateTimeStyles.AssumeLocal)) != 0) && ((style & (DateTimeStyles.AssumeUniversal)) != 0))
+ {
+ throw new ArgumentException(SR.Argument_ConflictingDateTimeStyles, parameterName);
+ }
+ Contract.EndContractBlock();
+ if (((style & DateTimeStyles.RoundtripKind) != 0)
+ && ((style & (DateTimeStyles.AssumeLocal | DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal)) != 0))
+ {
+ throw new ArgumentException(SR.Argument_ConflictingDateTimeRoundtripStyles, parameterName);
+ }
+ }
+
+ //
+ // Actions: Return the internal flag used in formatting and parsing.
+ // The flag can be used to indicate things like if genitive forms is used in this DTFi, or if leap year gets different month names.
+ //
+ internal DateTimeFormatFlags FormatFlags
+ {
+ get
+ {
+ if (formatFlags == DateTimeFormatFlags.NotInitialized)
+ {
+ // Build the format flags from the data in this DTFI
+ formatFlags = DateTimeFormatFlags.None;
+ formatFlags |= (DateTimeFormatFlags)DateTimeFormatInfoScanner.GetFormatFlagGenitiveMonth(
+ MonthNames, internalGetGenitiveMonthNames(false), AbbreviatedMonthNames, internalGetGenitiveMonthNames(true));
+ formatFlags |= (DateTimeFormatFlags)DateTimeFormatInfoScanner.GetFormatFlagUseSpaceInMonthNames(
+ MonthNames, internalGetGenitiveMonthNames(false), AbbreviatedMonthNames, internalGetGenitiveMonthNames(true));
+ formatFlags |= (DateTimeFormatFlags)DateTimeFormatInfoScanner.GetFormatFlagUseSpaceInDayNames(DayNames, AbbreviatedDayNames);
+ formatFlags |= (DateTimeFormatFlags)DateTimeFormatInfoScanner.GetFormatFlagUseHebrewCalendar((int)Calendar.ID);
+ }
+ return (formatFlags);
+ }
+ }
+
+ internal Boolean HasForceTwoDigitYears
+ {
+ get
+ {
+ switch (calendar.ID)
+ {
+ // Handle Japanese and Taiwan cases.
+ // If is y/yy, do not get (year % 100). "y" will print
+ // year without leading zero. "yy" will print year with two-digit in leading zero.
+ // If pattern is yyy/yyyy/..., print year value with two-digit in leading zero.
+ // So year 5 is "05", and year 125 is "125".
+ // The reason for not doing (year % 100) is for Taiwan calendar.
+ // If year 125, then output 125 and not 25.
+ // Note: OS uses "yyyy" for Taiwan calendar by default.
+ case (CalendarId.JAPAN):
+ case (CalendarId.TAIWAN):
+ return true;
+ }
+ return false;
+ }
+ }
+
+ // Returns whether the YearMonthAdjustment function has any fix-up work to do for this culture/calendar.
+ internal Boolean HasYearMonthAdjustment
+ {
+ get
+ {
+ return ((FormatFlags & DateTimeFormatFlags.UseHebrewRule) != 0);
+ }
+ }
+
+ // This is a callback that the parser can make back into the DTFI to let it fiddle with special
+ // cases associated with that culture or calendar. Currently this only has special cases for
+ // the Hebrew calendar, but this could be extended to other cultures.
+ //
+ // The return value is whether the year and month are actually valid for this calendar.
+ internal Boolean YearMonthAdjustment(ref int year, ref int month, Boolean parsedMonthName)
+ {
+ if ((FormatFlags & DateTimeFormatFlags.UseHebrewRule) != 0)
+ {
+ // Special rules to fix up the Hebrew year/month
+
+ // When formatting, we only format up to the hundred digit of the Hebrew year, although Hebrew year is now over 5000.
+ // E.g. if the year is 5763, we only format as 763.
+ if (year < 1000)
+ {
+ year += 5000;
+ }
+
+ // Because we need to calculate leap year, we should fall out now for an invalid year.
+ if (year < Calendar.GetYear(Calendar.MinSupportedDateTime) || year > Calendar.GetYear(Calendar.MaxSupportedDateTime))
+ {
+ return false;
+ }
+
+ // To handle leap months, the set of month names in the symbol table does not always correspond to the numbers.
+ // For non-leap years, month 7 (Adar Bet) is not present, so we need to make using this month invalid and
+ // shuffle the other months down.
+ if (parsedMonthName)
+ {
+ if (!Calendar.IsLeapYear(year))
+ {
+ if (month >= 8)
+ {
+ month--;
+ }
+ else if (month == 7)
+ {
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+ }
+
+ //
+ // DateTimeFormatInfo tokenizer. This is used by DateTime.Parse() to break input string into tokens.
+ //
+
+ private TokenHashValue[] _dtfiTokenHash;
+
+ private const int TOKEN_HASH_SIZE = 199;
+ private const int SECOND_PRIME = 197;
+ private const String dateSeparatorOrTimeZoneOffset = "-";
+ private const String invariantDateSeparator = "/";
+ private const String invariantTimeSeparator = ":";
+
+ //
+ // Common Ignorable Symbols
+ //
+ internal const String IgnorablePeriod = ".";
+ internal const String IgnorableComma = ",";
+
+ //
+ // Year/Month/Day suffixes
+ //
+ internal const String CJKYearSuff = "\u5e74";
+ internal const String CJKMonthSuff = "\u6708";
+ internal const String CJKDaySuff = "\u65e5";
+
+ internal const String KoreanYearSuff = "\ub144";
+ internal const String KoreanMonthSuff = "\uc6d4";
+ internal const String KoreanDaySuff = "\uc77c";
+
+ internal const String KoreanHourSuff = "\uc2dc";
+ internal const String KoreanMinuteSuff = "\ubd84";
+ internal const String KoreanSecondSuff = "\ucd08";
+
+ internal const String CJKHourSuff = "\u6642";
+ internal const String ChineseHourSuff = "\u65f6";
+
+ internal const String CJKMinuteSuff = "\u5206";
+ internal const String CJKSecondSuff = "\u79d2";
+
+ internal const String LocalTimeMark = "T";
+
+ internal const String GMTName = "GMT";
+ internal const String ZuluName = "Z";
+
+ internal const String KoreanLangName = "ko";
+ internal const String JapaneseLangName = "ja";
+ internal const String EnglishLangName = "en";
+
+ private static volatile DateTimeFormatInfo s_jajpDTFI;
+ private static volatile DateTimeFormatInfo s_zhtwDTFI;
+
+ //
+ // Create a Japanese DTFI which uses JapaneseCalendar. This is used to parse
+ // date string with Japanese era name correctly even when the supplied DTFI
+ // does not use Japanese calendar.
+ // The created instance is stored in global s_jajpDTFI.
+ //
+ internal static DateTimeFormatInfo GetJapaneseCalendarDTFI()
+ {
+ DateTimeFormatInfo temp = s_jajpDTFI;
+ if (temp == null)
+ {
+ temp = new CultureInfo("ja-JP", false).DateTimeFormat;
+ temp.Calendar = JapaneseCalendar.GetDefaultInstance();
+ s_jajpDTFI = temp;
+ }
+ return (temp);
+ }
+
+ // Create a Taiwan DTFI which uses TaiwanCalendar. This is used to parse
+ // date string with era name correctly even when the supplied DTFI
+ // does not use Taiwan calendar.
+ // The created instance is stored in global s_zhtwDTFI.
+ internal static DateTimeFormatInfo GetTaiwanCalendarDTFI()
+ {
+ DateTimeFormatInfo temp = s_zhtwDTFI;
+ if (temp == null)
+ {
+ temp = new CultureInfo("zh-TW", false).DateTimeFormat;
+ temp.Calendar = TaiwanCalendar.GetDefaultInstance();
+ s_zhtwDTFI = temp;
+ }
+ return (temp);
+ }
+
+
+ // DTFI properties should call this when the setter are called.
+ private void ClearTokenHashTable()
+ {
+ _dtfiTokenHash = null;
+ formatFlags = DateTimeFormatFlags.NotInitialized;
+ }
+
+ internal TokenHashValue[] CreateTokenHashTable()
+ {
+ TokenHashValue[] temp = _dtfiTokenHash;
+ if (temp == null)
+ {
+ temp = new TokenHashValue[TOKEN_HASH_SIZE];
+
+ bool koreanLanguage = LanguageName.Equals(KoreanLangName);
+
+ string sep = this.TimeSeparator.Trim();
+ if (IgnorableComma != sep) InsertHash(temp, IgnorableComma, TokenType.IgnorableSymbol, 0);
+ if (IgnorablePeriod != sep) InsertHash(temp, IgnorablePeriod, TokenType.IgnorableSymbol, 0);
+
+ if (KoreanHourSuff != sep && CJKHourSuff != sep && ChineseHourSuff != sep)
+ {
+ //
+ // On the Macintosh, the default TimeSeparator is identical to the KoreanHourSuff, CJKHourSuff, or ChineseHourSuff for some cultures like
+ // ja-JP and ko-KR. In these cases having the same symbol inserted into the hash table with multiple TokenTypes causes undesirable
+ // DateTime.Parse behavior. For instance, the DateTimeFormatInfo.Tokenize() method might return SEP_DateOrOffset for KoreanHourSuff
+ // instead of SEP_HourSuff.
+ //
+ InsertHash(temp, this.TimeSeparator, TokenType.SEP_Time, 0);
+ }
+
+ InsertHash(temp, this.AMDesignator, TokenType.SEP_Am | TokenType.Am, 0);
+ InsertHash(temp, this.PMDesignator, TokenType.SEP_Pm | TokenType.Pm, 1);
+
+ // TODO: This ignores similar custom cultures
+ if (LanguageName.Equals("sq"))
+ {
+ // Albanian allows time formats like "12:00.PD"
+ InsertHash(temp, IgnorablePeriod + this.AMDesignator, TokenType.SEP_Am | TokenType.Am, 0);
+ InsertHash(temp, IgnorablePeriod + this.PMDesignator, TokenType.SEP_Pm | TokenType.Pm, 1);
+ }
+
+ // CJK suffix
+ InsertHash(temp, CJKYearSuff, TokenType.SEP_YearSuff, 0);
+ InsertHash(temp, KoreanYearSuff, TokenType.SEP_YearSuff, 0);
+ InsertHash(temp, CJKMonthSuff, TokenType.SEP_MonthSuff, 0);
+ InsertHash(temp, KoreanMonthSuff, TokenType.SEP_MonthSuff, 0);
+ InsertHash(temp, CJKDaySuff, TokenType.SEP_DaySuff, 0);
+ InsertHash(temp, KoreanDaySuff, TokenType.SEP_DaySuff, 0);
+
+ InsertHash(temp, CJKHourSuff, TokenType.SEP_HourSuff, 0);
+ InsertHash(temp, ChineseHourSuff, TokenType.SEP_HourSuff, 0);
+ InsertHash(temp, CJKMinuteSuff, TokenType.SEP_MinuteSuff, 0);
+ InsertHash(temp, CJKSecondSuff, TokenType.SEP_SecondSuff, 0);
+
+ // TODO: This ignores other custom cultures that might want to do something similar
+ if (koreanLanguage)
+ {
+ // Korean suffix
+ InsertHash(temp, KoreanHourSuff, TokenType.SEP_HourSuff, 0);
+ InsertHash(temp, KoreanMinuteSuff, TokenType.SEP_MinuteSuff, 0);
+ InsertHash(temp, KoreanSecondSuff, TokenType.SEP_SecondSuff, 0);
+ }
+
+ if (LanguageName.Equals("ky"))
+ {
+ // For some cultures, the date separator works more like a comma, being allowed before or after any date part
+ InsertHash(temp, dateSeparatorOrTimeZoneOffset, TokenType.IgnorableSymbol, 0);
+ }
+ else
+ {
+ InsertHash(temp, dateSeparatorOrTimeZoneOffset, TokenType.SEP_DateOrOffset, 0);
+ }
+
+ String[] dateWords = null;
+ DateTimeFormatInfoScanner scanner = null;
+
+ // We need to rescan the date words since we're always synthetic
+ scanner = new DateTimeFormatInfoScanner();
+ m_dateWords = dateWords = scanner.GetDateWordsOfDTFI(this);
+ // Ensure the formatflags is initialized.
+ DateTimeFormatFlags flag = FormatFlags;
+
+ // For some cultures, the date separator works more like a comma, being allowed before or after any date part.
+ // In these cultures, we do not use normal date separator since we disallow date separator after a date terminal state.
+ // This is determined in DateTimeFormatInfoScanner. Use this flag to determine if we should treat date separator as ignorable symbol.
+ bool useDateSepAsIgnorableSymbol = false;
+
+ String monthPostfix = null;
+ if (dateWords != null)
+ {
+ // There are DateWords. It could be a real date word (such as "de"), or a monthPostfix.
+ // The monthPostfix starts with '\xfffe' (MonthPostfixChar), followed by the real monthPostfix.
+ for (int i = 0; i < dateWords.Length; i++)
+ {
+ switch (dateWords[i][0])
+ {
+ // This is a month postfix
+ case DateTimeFormatInfoScanner.MonthPostfixChar:
+ // Get the real month postfix.
+ monthPostfix = dateWords[i].Substring(1);
+ // Add the month name + postfix into the token.
+ AddMonthNames(temp, monthPostfix);
+ break;
+ case DateTimeFormatInfoScanner.IgnorableSymbolChar:
+ String symbol = dateWords[i].Substring(1);
+ InsertHash(temp, symbol, TokenType.IgnorableSymbol, 0);
+ if (this.DateSeparator.Trim(null).Equals(symbol))
+ {
+ // The date separator is the same as the ignorable symbol.
+ useDateSepAsIgnorableSymbol = true;
+ }
+ break;
+ default:
+ InsertHash(temp, dateWords[i], TokenType.DateWordToken, 0);
+ // TODO: This ignores similar custom cultures
+ if (LanguageName.Equals("eu"))
+ {
+ // Basque has date words with leading dots
+ InsertHash(temp, IgnorablePeriod + dateWords[i], TokenType.DateWordToken, 0);
+ }
+ break;
+ }
+ }
+ }
+
+ if (!useDateSepAsIgnorableSymbol)
+ {
+ // Use the normal date separator.
+ InsertHash(temp, this.DateSeparator, TokenType.SEP_Date, 0);
+ }
+ // Add the regular month names.
+ AddMonthNames(temp, null);
+
+ // Add the abbreviated month names.
+ for (int i = 1; i <= 13; i++)
+ {
+ InsertHash(temp, GetAbbreviatedMonthName(i), TokenType.MonthToken, i);
+ }
+
+
+ if ((FormatFlags & DateTimeFormatFlags.UseGenitiveMonth) != 0)
+ {