diff options
author | Zoltan Varga <vargaz@gmail.com> | 2020-09-09 00:52:33 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-09-09 00:52:33 +0300 |
commit | 6e103e7191dcb17120032f2516cc7f8e9e04c32e (patch) | |
tree | a3ee2ea7450809dac229fc084683df3f335942ad /netcore/System.Private.CoreLib/shared/System/Globalization | |
parent | 427395f4c6a18466c26d0cf782bed106d05e77ae (diff) |
Remove netcore/ directory from the mono/mono repository. (#20361)
Diffstat (limited to 'netcore/System.Private.CoreLib/shared/System/Globalization')
75 files changed, 0 insertions, 43199 deletions
diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/BidiCategory.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/BidiCategory.cs deleted file mode 100644 index abe69508932..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/BidiCategory.cs +++ /dev/null @@ -1,33 +0,0 @@ -// 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 -{ - internal enum BidiCategory - { - LeftToRight = 0, - LeftToRightEmbedding = 1, - LeftToRightOverride = 2, - RightToLeft = 3, - RightToLeftArabic = 4, - RightToLeftEmbedding = 5, - RightToLeftOverride = 6, - PopDirectionalFormat = 7, - EuropeanNumber = 8, - EuropeanNumberSeparator = 9, - EuropeanNumberTerminator = 10, - ArabicNumber = 11, - CommonNumberSeparator = 12, - NonSpacingMark = 13, - BoundaryNeutral = 14, - ParagraphSeparator = 15, - SegmentSeparator = 16, - Whitespace = 17, - OtherNeutrals = 18, - LeftToRightIsolate = 19, - RightToLeftIsolate = 20, - FirstStrongIsolate = 21, - PopDirectionIsolate = 22, - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/Calendar.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/Calendar.cs deleted file mode 100644 index 7d86971a879..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/Calendar.cs +++ /dev/null @@ -1,732 +0,0 @@ -// 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; - -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. - - public abstract 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; - - private bool _isReadOnly = false; - - public virtual DateTime MinSupportedDateTime => DateTime.MinValue; - - public virtual DateTime MaxSupportedDateTime => DateTime.MaxValue; - - public virtual CalendarAlgorithmType AlgorithmType => CalendarAlgorithmType.Unknown; - - protected Calendar() - { - } - - internal virtual CalendarId ID => CalendarId.UNINITIALIZED_VALUE; - - // Return the Base calendar ID for calendars that didn't have defined data in calendarData - internal virtual CalendarId BaseCalendarID => ID; - - public bool IsReadOnly => _isReadOnly; - - public virtual object Clone() - { - object o = MemberwiseClone(); - ((Calendar)o).SetReadOnlyState(false); - return o; - } - - public static Calendar ReadOnly(Calendar calendar) - { - if (calendar == null) - { - throw new ArgumentNullException(nameof(calendar)); - } - 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; - } - - /// <summary> - /// This is used to convert CurrentEra(0) to an appropriate era value. - /// </summary> - internal virtual int CurrentEraValue - { - get - { - // The following code assumes that the current era value can not be -1. - if (_currentEraValue == -1) - { - Debug.Assert(BaseCalendarID != CalendarId.UNINITIALIZED_VALUE, "[Calendar.CurrentEraValue] Expected a real calendar ID"); - _currentEraValue = CalendarData.GetCalendarData(BaseCalendarID).iCurrentEra; - } - - return _currentEraValue; - } - } - - 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(SR.Format(SR.Argument_ResultCalendarRange, minValue, maxValue)); - } - } - - 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(nameof(value), value, SR.ArgumentOutOfRange_AddValue); - } - - long millis = (long)tempMillis; - long ticks = time.Ticks + millis * TicksPerMillisecond; - CheckAddResult(ticks, MinSupportedDateTime, MaxSupportedDateTime); - return new DateTime(ticks); - } - - /// <summary> - /// 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. - /// </summary> - public virtual DateTime AddMilliseconds(DateTime time, double milliseconds) - { - return Add(time, milliseconds, 1); - } - - /// <summary> - /// 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. - /// </summary> - public virtual DateTime AddDays(DateTime time, int days) - { - return Add(time, days, MillisPerDay); - } - - /// <summary> - /// 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. - /// </summary> - public virtual DateTime AddHours(DateTime time, int hours) - { - return Add(time, hours, MillisPerHour); - } - - /// <summary> - /// 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. - /// </summary> - public virtual DateTime AddMinutes(DateTime time, int minutes) - { - return Add(time, minutes, MillisPerMinute); - } - - /// <summary> - /// 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. - /// </summary> - public abstract DateTime AddMonths(DateTime time, int months); - - /// <summary> - /// 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. - /// </summary> - 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); - } - - /// <summary> - /// 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. - /// </summary> - public abstract DateTime AddYears(DateTime time, int years); - - /// <summary> - /// Returns the day-of-month part of the specified DateTime. The returned - /// value is an integer between 1 and 31. - /// </summary> - public abstract int GetDayOfMonth(DateTime time); - - /// <summary> - /// 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. - /// </summary> - public abstract DayOfWeek GetDayOfWeek(DateTime time); - - /// <summary> - /// Returns the day-of-year part of the specified DateTime. The returned value - /// is an integer between 1 and 366. - /// </summary> - public abstract int GetDayOfYear(DateTime time); - - /// <summary> - /// Returns the number of days in the month given by the year and - /// month arguments. - /// </summary> - public virtual int GetDaysInMonth(int year, int month) - { - return GetDaysInMonth(year, month, CurrentEra); - } - - /// <summary> - /// Returns the number of days in the month given by the year and - /// month arguments for the specified era. - /// </summary> - public abstract int GetDaysInMonth(int year, int month, int era); - - /// <summary> - /// Returns the number of days in the year given by the year argument - /// for the current era. - /// </summary> - public virtual int GetDaysInYear(int year) - { - return GetDaysInYear(year, CurrentEra); - } - - /// <summary> - /// Returns the number of days in the year given by the year argument - /// for the current era. - /// </summary> - public abstract int GetDaysInYear(int year, int era); - - /// <summary> - /// Returns the era for the specified DateTime value. - /// </summary> - public abstract int GetEra(DateTime time); - - /// <summary> - /// Get the list of era values. - /// </summary> - /// <returns>The int array of the era names supported in this calendar or null if era is not used.</returns> - 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); - } - - /// <summary> - /// Get the week of year using the FirstDay rule. - /// </summary> - /// <remarks> - /// 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 - /// </remarks> - 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; - Debug.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; - } - - protected virtual int DaysInYearBeforeMinSupportedYear => 365; - - /// <summary> - /// Returns the week of year for the specified DateTime. The returned value is an - /// integer between 1 and 53. - /// </summary> - public virtual int GetWeekOfYear(DateTime time, CalendarWeekRule rule, DayOfWeek firstDayOfWeek) - { - if (firstDayOfWeek < DayOfWeek.Sunday || firstDayOfWeek > DayOfWeek.Saturday) - { - throw new ArgumentOutOfRangeException( - nameof(firstDayOfWeek), - firstDayOfWeek, - SR.Format(SR.ArgumentOutOfRange_Range, DayOfWeek.Sunday, DayOfWeek.Saturday)); - } - - return rule switch - { - CalendarWeekRule.FirstDay => GetFirstDayWeekOfYear(time, (int)firstDayOfWeek), - CalendarWeekRule.FirstFullWeek => GetWeekOfYearFullDays(time, (int)firstDayOfWeek, 7), - CalendarWeekRule.FirstFourDayWeek => GetWeekOfYearFullDays(time, (int)firstDayOfWeek, 4), - _ => throw new ArgumentOutOfRangeException( - nameof(rule), - rule, - SR.Format(SR.ArgumentOutOfRange_Range, CalendarWeekRule.FirstDay, CalendarWeekRule.FirstFourDayWeek)), - }; - } - - /// <summary> - /// Returns the year part of the specified DateTime. The returned value is an - /// integer between 1 and 9999. - /// </summary> - public abstract int GetYear(DateTime time); - - /// <summary> - /// 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. - /// </summary> - public virtual bool IsLeapDay(int year, int month, int day) - { - return IsLeapDay(year, month, day, CurrentEra); - } - - /// <summary> - /// 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. - /// </summary> - public abstract bool IsLeapDay(int year, int month, int day, int era); - - /// <summary> - /// 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. - /// </summary> - public virtual bool IsLeapMonth(int year, int month) - { - return IsLeapMonth(year, month, CurrentEra); - } - - /// <summary> - /// 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. - /// </summary> - public abstract bool IsLeapMonth(int year, int month, int era); - - /// <summary> - /// Returns the leap month in a calendar year of the current era. - /// This method returns 0 if this calendar does not have leap month, - /// or this year is not a leap year. - /// </summary> - public virtual int GetLeapMonth(int year) - { - return GetLeapMonth(year, CurrentEra); - } - - /// <summary> - /// 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. - /// </summary> - 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; - } - - /// <summary> - /// 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. - /// </summary> - public virtual bool IsLeapYear(int year) - { - return IsLeapYear(year, CurrentEra); - } - - /// <summary> - /// 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. - /// </summary> - public abstract bool IsLeapYear(int year, int era); - - /// <summary> - /// Returns the date and time converted to a DateTime value. - /// Throws an exception if the n-tuple is invalid. - /// </summary> - 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); - } - - /// <summary> - /// Returns the date and time converted to a DateTime value. - /// Throws an exception if the n-tuple is invalid. - /// </summary> - public abstract DateTime ToDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int era); - - internal virtual bool 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); - } - - /// <summary> - /// 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(). - /// </summary> - public virtual int TwoDigitYearMax - { - get => _twoDigitYearMax; - set - { - VerifyWritable(); - _twoDigitYearMax = value; - } - } - - /// <summary> - /// 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. - /// </summary> - public virtual int ToFourDigitYear(int year) - { - if (year < 0) - { - throw new ArgumentOutOfRangeException(nameof(year), year, SR.ArgumentOutOfRange_NeedNonNegNum); - } - 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; - } - - /// <summary> - /// Return the tick count corresponding to the given hour, minute, second. - /// Will check the if the parameters are valid. - /// </summary> - 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) - { - throw new ArgumentOutOfRangeException(null, SR.ArgumentOutOfRange_BadHourMinuteSecond); - } - if (millisecond < 0 || millisecond >= MillisPerSecond) - { - throw new ArgumentOutOfRangeException( - nameof(millisecond), - millisecond, - SR.Format(SR.ArgumentOutOfRange_Range, 0, MillisPerSecond - 1)); - } - - return InternalGlobalizationHelper.TimeToTicks(hour, minute, second) + millisecond * TicksPerMillisecond; - } - - internal static int GetSystemTwoDigitYearSetting(CalendarId CalID, int defaultYearValue) - { - int twoDigitYearMax = CalendarData.GetTwoDigitYearMax(CalID); - return twoDigitYearMax >= 0 ? twoDigitYearMax : defaultYearValue; - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/CalendarAlgorithmType.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/CalendarAlgorithmType.cs deleted file mode 100644 index 4ddc307abfa..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/CalendarAlgorithmType.cs +++ /dev/null @@ -1,18 +0,0 @@ -// 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 enum CalendarAlgorithmType - { - Unknown = 0, // This is the default value to return in the Calendar base class. - SolarCalendar = 1, // Solar-base calendar, such as GregorianCalendar, jaoaneseCalendar, JulianCalendar, etc. - // Solar calendars are based on the solar year and seasons. - LunarCalendar = 2, // Lunar-based calendar, such as Hijri and UmAlQuraCalendar. - // Lunar calendars are based on the path of the moon. The seasons are not accurately represented. - LunisolarCalendar = 3 // Lunisolar-based calendar which use leap month rule, such as HebrewCalendar and Asian Lunisolar calendars. - // Lunisolar calendars are based on the cycle of the moon, but consider the seasons as a secondary consideration, - // so they align with the seasons as well as lunar events. - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/CalendarData.Unix.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/CalendarData.Unix.cs deleted file mode 100644 index d8ed0072f37..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/CalendarData.Unix.cs +++ /dev/null @@ -1,460 +0,0 @@ -// 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; -using System.Security; -using System.Text; -using Internal.Runtime.CompilerServices; - -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; - - // these can return null but are later replaced with String.Empty or other non-nullable value - result &= GetCalendarInfo(localeName, calendarId, CalendarDataType.NativeName, out this.sNativeName!); - result &= GetCalendarInfo(localeName, calendarId, CalendarDataType.MonthDay, out this.sMonthDay!); - - if (this.sMonthDay != null) - { - 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!); - - string? leapHebrewMonthName = null; - result &= EnumMonthNames(localeName, calendarId, CalendarDataType.MonthNames, out this.saMonthNames!, ref leapHebrewMonthName); - if (leapHebrewMonthName != null) - { - Debug.Assert(this.saMonthNames != null); - - // In Hebrew calendar, get the leap month name Adar II and override the non-leap month 7 - Debug.Assert(calendarId == CalendarId.HEBREW && saMonthNames.Length == 13); - saLeapYearMonthNames = (string[]) saMonthNames.Clone(); - saLeapYearMonthNames[6] = leapHebrewMonthName; - - // The returned data from ICU has 6th month name as 'Adar I' and 7th month name as 'Adar' - // We need to adjust that in the list used with non-leap year to have 6th month as 'Adar' and 7th month as 'Adar II' - // note that when formatting non-leap year dates, 7th month shouldn't get used at all. - saMonthNames[5] = saMonthNames[6]; - saMonthNames[6] = leapHebrewMonthName; - - } - result &= EnumMonthNames(localeName, calendarId, CalendarDataType.AbbrevMonthNames, out this.saAbbrevMonthNames!, ref leapHebrewMonthName); - result &= EnumMonthNames(localeName, calendarId, CalendarDataType.MonthGenitiveNames, out this.saMonthGenitiveNames!, ref leapHebrewMonthName); - result &= EnumMonthNames(localeName, calendarId, CalendarDataType.AbbrevMonthGenitiveNames, out this.saAbbrevMonthGenitiveNames!, ref leapHebrewMonthName); - - 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 - internal static int GetCalendars(string localeName, bool useUserOverride, CalendarId[] calendars) - { - Debug.Assert(!GlobalizationMode.Invariant); - - // NOTE: there are no 'user overrides' on Linux - int count = Interop.Globalization.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 - - private static unsafe bool GetCalendarInfo(string localeName, CalendarId calendarId, CalendarDataType dataType, out string? calendarString) - { - Debug.Assert(!GlobalizationMode.Invariant); - - return Interop.CallStringMethod( - (buffer, locale, id, type) => - { - fixed (char* bufferPtr = buffer) - { - return Interop.Globalization.GetCalendarInfo(locale, id, type, bufferPtr, buffer.Length); - } - }, - localeName, - calendarId, - dataType, - out calendarString); - } - - private static bool EnumDatePatterns(string localeName, CalendarId calendarId, CalendarDataType dataType, out string[]? datePatterns) - { - datePatterns = null; - - EnumCalendarsData callbackContext = default; - callbackContext.Results = new List<string>(); - callbackContext.DisallowDuplicates = true; - bool result = EnumCalendarInfo(localeName, calendarId, dataType, ref callbackContext); - if (result) - { - List<string> datePatternsList = callbackContext.Results; - - for (int i = 0; i < datePatternsList.Count; i++) - { - datePatternsList[i] = NormalizeDatePattern(datePatternsList[i]); - } - - if (dataType == CalendarDataType.ShortDates) - FixDefaultShortDatePattern(datePatternsList); - - datePatterns = datePatternsList.ToArray(); - } - - return result; - } - - // FixDefaultShortDatePattern will convert the default short date pattern from using 'yy' to using 'yyyy' - // And will ensure the original pattern still exist in the list. - // doing that will have the short date pattern format the year as 4-digit number and not just 2-digit number. - // Example: June 5, 2018 will be formatted to something like 6/5/2018 instead of 6/5/18 fro en-US culture. - private static void FixDefaultShortDatePattern(List<string> shortDatePatterns) - { - if (shortDatePatterns.Count == 0) - return; - - string s = shortDatePatterns[0]; - - // We are not expecting any pattern have length more than 100. - // We have to do this check to prevent stack overflow as we allocate the buffer on the stack. - if (s.Length > 100) - return; - - Span<char> modifiedPattern = stackalloc char[s.Length + 2]; - int index = 0; - - while (index < s.Length) - { - if (s[index] == '\'') - { - do - { - modifiedPattern[index] = s[index]; - index++; - } while (index < s.Length && s[index] != '\''); - - if (index >= s.Length) - return; - } - else if (s[index] == 'y') - { - modifiedPattern[index] = 'y'; - break; - } - - modifiedPattern[index] = s[index]; - index++; - } - - if (index >= s.Length - 1 || s[index + 1] != 'y') - { - // not a 'yy' pattern - return; - } - - if (index + 2 < s.Length && s[index + 2] == 'y') - { - // we have 'yyy' then nothing to do - return; - } - - // we are sure now we have 'yy' pattern - - Debug.Assert(index + 3 < modifiedPattern.Length); - - modifiedPattern[index + 1] = 'y'; // second y - modifiedPattern[index + 2] = 'y'; // third y - modifiedPattern[index + 3] = 'y'; // fourth y - - index += 2; - - // Now, copy the rest of the pattern to the destination buffer - while (index < s.Length) - { - modifiedPattern[index + 2] = s[index]; - index++; - } - - shortDatePatterns[0] = modifiedPattern.ToString(); - - for (int i = 1; i < shortDatePatterns.Count; i++) - { - if (shortDatePatterns[i] == shortDatePatterns[0]) - { - // Found match in the list to the new constructed pattern, then replace it with the original modified pattern - shortDatePatterns[i] = s; - return; - } - } - - // if we come here means the newly constructed pattern not found on the list, then add the original pattern - shortDatePatterns.Add(s); - } - - /// <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"; - Debug.Assert(!unsupportedDateFieldSymbols.Contains(input[index]), - $"Encountered an unexpected date field symbol '{input[index]}' from ICU which has no known corresponding .NET equivalent."); - - 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; - } - - private static bool EnumMonthNames(string localeName, CalendarId calendarId, CalendarDataType dataType, out string[]? monthNames, ref string? leapHebrewMonthName) - { - monthNames = null; - - EnumCalendarsData callbackContext = default; - callbackContext.Results = new List<string>(); - bool result = EnumCalendarInfo(localeName, calendarId, dataType, ref 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); - } - - if (callbackContext.Results.Count > 13) - { - Debug.Assert(calendarId == CalendarId.HEBREW && callbackContext.Results.Count == 14); - - if (calendarId == CalendarId.HEBREW) - { - leapHebrewMonthName = callbackContext.Results[13]; - } - callbackContext.Results.RemoveRange(13, callbackContext.Results.Count - 13); - } - - monthNames = callbackContext.Results.ToArray(); - } - - return result; - } - - 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; - } - - internal static bool EnumCalendarInfo(string localeName, CalendarId calendarId, CalendarDataType dataType, out string[]? calendarData) - { - calendarData = null; - - EnumCalendarsData callbackContext = default; - callbackContext.Results = new List<string>(); - bool result = EnumCalendarInfo(localeName, calendarId, dataType, ref callbackContext); - if (result) - { - calendarData = callbackContext.Results.ToArray(); - } - - return result; - } - - private static unsafe bool EnumCalendarInfo(string localeName, CalendarId calendarId, CalendarDataType dataType, ref EnumCalendarsData callbackContext) - { - return Interop.Globalization.EnumCalendarInfo(EnumCalendarInfoCallback, localeName, calendarId, dataType, (IntPtr)Unsafe.AsPointer(ref callbackContext)); - } - - private static unsafe void EnumCalendarInfoCallback(string calendarString, IntPtr context) - { - try - { - ref EnumCalendarsData callbackContext = ref Unsafe.As<byte, EnumCalendarsData>(ref *(byte*)context); - - 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); - } - catch (Exception e) - { - Debug.Fail(e.ToString()); - // we ignore the managed exceptions here because EnumCalendarInfoCallback will get called from the native code. - // If we don't ignore the exception here that can cause the runtime to fail fast. - } - } - - private struct EnumCalendarsData - { - public List<string> Results; - public bool DisallowDuplicates; - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/CalendarData.Windows.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/CalendarData.Windows.cs deleted file mode 100644 index 8031df90e0e..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/CalendarData.Windows.cs +++ /dev/null @@ -1,448 +0,0 @@ -// 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; -using System.Collections.Generic; -using Internal.Runtime.CompilerServices; - -namespace System.Globalization -{ - internal partial class CalendarData - { - private bool LoadCalendarDataFromSystem(string localeName, CalendarId calendarId) - { - Debug.Assert(!GlobalizationMode.Invariant); - - 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) => - GlobalizationMode.Invariant ? Invariant.iTwoDigitYearMax : - CallGetCalendarInfoEx(null, calendarId, CAL_ITWODIGITYEARMAX, out int twoDigitYearMax) ? twoDigitYearMax : - -1; - - // Call native side to figure out which calendars are allowed - internal static int GetCalendars(string localeName, bool useUserOverride, CalendarId[] calendars) - { - Debug.Assert(!GlobalizationMode.Invariant); - - EnumCalendarsData data = default; - data.userOverride = 0; - data.calendars = new List<int>(); - - // First call GetLocaleInfo if necessary - if (useUserOverride) - { - // They want user overrides, see if the user calendar matches the input calendar - int userCalendar = CultureData.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); - } - } - - unsafe - { - Interop.Kernel32.EnumCalendarInfoExEx(EnumCalendarsCallback, localeName, ENUM_ALL_CALENDARS, null, CAL_ICALINTVALUE, Unsafe.AsPointer(ref data)); - } - - // 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() - { - Debug.Assert(!GlobalizationMode.Invariant); - - // 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 string _); - } - - // 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) - { - // 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 string _)) - { - // 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 string _)) - { - // 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.Kernel32.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.Kernel32.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 struct EnumData - { - public string? userOverride; - public List<string>? strings; - } - - // EnumCalendarInfoExEx callback itself. - // [NativeCallable(CallingConvention = CallingConvention.StdCall)] - private static unsafe Interop.BOOL EnumCalendarInfoCallback(char* lpCalendarInfoString, uint calendar, IntPtr pReserved, void* lParam) - { - ref EnumData context = ref Unsafe.As<byte, EnumData>(ref *(byte*)lParam); - try - { - string calendarInfo = new string(lpCalendarInfoString); - - // If we had a user override, check to make sure this differs - if (context.userOverride != calendarInfo) - { - Debug.Assert(context.strings != null); - 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 = default; - context.userOverride = null; - context.strings = new List<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)CultureData.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 = CultureData.GetLocaleInfoEx(localeName, lcType); - - // if it succeeded remember the override for the later callers - if (res != null) - { - // 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); - } - } - } - - // Now call the enumeration API. Work is done by our callback function - Interop.Kernel32.EnumCalendarInfoExEx(EnumCalendarInfoCallback, localeName, (uint)calendar, null, calType, Unsafe.AsPointer(ref context)); - - // Now we have a list of data, fail if we didn't find anything. - Debug.Assert(context.strings != null); - 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 struct EnumCalendarsData - { - public int userOverride; // user override value (if found) - public List<int> calendars; // list of calendars found so far - } - - // [NativeCallable(CallingConvention = CallingConvention.StdCall)] - private static unsafe Interop.BOOL EnumCalendarsCallback(char* lpCalendarInfoString, uint calendar, IntPtr reserved, void* lParam) - { - ref EnumCalendarsData context = ref Unsafe.As<byte, EnumCalendarsData>(ref *(byte*)lParam); - 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() - { - Debug.Assert(!GlobalizationMode.Invariant); - - int result; - char* localeName = stackalloc char[Interop.Kernel32.LOCALE_NAME_MAX_LENGTH]; - result = CultureData.GetLocaleInfoEx(Interop.Kernel32.LOCALE_NAME_USER_DEFAULT, Interop.Kernel32.LOCALE_SNAME, localeName, Interop.Kernel32.LOCALE_NAME_MAX_LENGTH); - - return result <= 0 ? "" : new string(localeName, 0, result - 1); // exclude the null termination - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/CalendarData.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/CalendarData.cs deleted file mode 100644 index 997cfb406e4..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/CalendarData.cs +++ /dev/null @@ -1,380 +0,0 @@ -// 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; - -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 = null!; // Calendar Name for the locale - - // Formats - internal string[] saShortDates = null!; // Short Data format, default first - internal string[] saYearMonths = null!; // Year/Month Data format, default first - internal string[] saLongDates = null!; // Long Data format, default first - internal string sMonthDay = null!; // Month/Day format - - // Calendar Parts Names - internal string[] saEraNames = null!; // Names of Eras - internal string[] saAbbrevEraNames = null!; // Abbreviated Era Names - internal string[] saAbbrevEnglishEraNames = null!; // Abbreviated Era Names in English - internal string[] saDayNames = null!; // Day Names, null to use locale data, starts on Sunday - internal string[] saAbbrevDayNames = null!; // Abbrev Day Names, null to use locale data, starts on Sunday - internal string[] saSuperShortDayNames = null!; // Super short Day of week names - internal string[] saMonthNames = null!; // Month Names (13) - internal string[] saAbbrevMonthNames = null!; // Abbrev Month Names (13) - internal string[] saMonthGenitiveNames = null!; // Genitive Month Names (13) - internal string[] saAbbrevMonthGenitiveNames = null!; // Genitive Abbrev Month Names (13) - internal string[] saLeapYearMonthNames = null!; // 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 readonly CalendarData Invariant = CreateInvariant(); - - // Private constructor - private CalendarData() - { - } - - // Invariant factory - private static CalendarData CreateInvariant() - { - // 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; - - return invariant; - } - - // - // Get a bunch of data for a calendar - // - internal CalendarData(string localeName, CalendarId calendarId, bool bUseUserOverrides) - { - this.bUseUserOverrides = bUseUserOverrides; - - Debug.Assert(!GlobalizationMode.Invariant); - - if (!LoadCalendarDataFromSystem(localeName, calendarId)) - { - // LoadCalendarDataFromSystem sometimes can fail on Linux if the installed ICU package is missing some resources. - // The ICU package can miss some resources in some cases like if someone compile and build the ICU package manually or ICU has a regression. - - // Something failed, try invariant for missing parts - // This is really not good, but we don't want the callers to crash. - this.sNativeName ??= string.Empty; // Calendar Name for the locale. - - // Formats - this.saShortDates ??= Invariant.saShortDates; // Short Data format, default first - this.saYearMonths ??= Invariant.saYearMonths; // Year/Month Data format, default first - this.saLongDates ??= Invariant.saLongDates; // Long Data format, default first - this.sMonthDay ??= Invariant.sMonthDay; // Month/Day format - - // Calendar Parts Names - this.saEraNames ??= Invariant.saEraNames; // Names of Eras - this.saAbbrevEraNames ??= Invariant.saAbbrevEraNames; // Abbreviated Era Names - this.saAbbrevEnglishEraNames ??= Invariant.saAbbrevEnglishEraNames; // Abbreviated Era Names in English - this.saDayNames ??= Invariant.saDayNames; // Day Names, null to use locale data, starts on Sunday - this.saAbbrevDayNames ??= Invariant.saAbbrevDayNames; // Abbrev Day Names, null to use locale data, starts on Sunday - this.saSuperShortDayNames ??= Invariant.saSuperShortDayNames; // Super short Day of week names - this.saMonthNames ??= Invariant.saMonthNames; // Month Names (13) - 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)._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/netcore/System.Private.CoreLib/shared/System/Globalization/CalendarWeekRule.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/CalendarWeekRule.cs deleted file mode 100644 index 13567afba1a..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/CalendarWeekRule.cs +++ /dev/null @@ -1,15 +0,0 @@ -// 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 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/netcore/System.Private.CoreLib/shared/System/Globalization/CalendricalCalculationsHelper.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/CalendricalCalculationsHelper.cs deleted file mode 100644 index 99caf6ba1d1..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/CalendricalCalculationsHelper.cs +++ /dev/null @@ -1,412 +0,0 @@ -// 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; - -namespace System.Globalization -{ - internal static 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 s_startOf1810 = GetNumberOfDays(new DateTime(1810, 1, 1)); - private static readonly long s_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; - } - - public static 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 - s_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) - { - Debug.Assert(gregorianYear < 1620 || 2020 <= gregorianYear); - long january1stOfYear = GetNumberOfDays(new DateTime(gregorianYear, 1, 1)); - double daysSinceStartOf1810 = january1stOfYear - s_startOf1810; - double x = TwelveHours + daysSinceStartOf1810; - return ((Math.Pow(x, 2) / 41048480) - 15) / SecondsPerDay; - } - - private static double EphemerisCorrection1988to2019(int gregorianYear) - { - Debug.Assert(1988 <= gregorianYear && gregorianYear <= 2019); - return (double)(gregorianYear - 1933) / SecondsPerDay; - } - - private static double EphemerisCorrection1900to1987(int gregorianYear) - { - Debug.Assert(1900 <= gregorianYear && gregorianYear <= 1987); - double centuriesFrom1900 = CenturiesFrom1900(gregorianYear); - return PolynomialSum(s_coefficients1900to1987, centuriesFrom1900); - } - - private static double EphemerisCorrection1800to1899(int gregorianYear) - { - Debug.Assert(1800 <= gregorianYear && gregorianYear <= 1899); - double centuriesFrom1900 = CenturiesFrom1900(gregorianYear); - return PolynomialSum(s_coefficients1800to1899, centuriesFrom1900); - } - - private static double EphemerisCorrection1700to1799(int gregorianYear) - { - Debug.Assert(1700 <= gregorianYear && gregorianYear <= 1799); - double yearsSince1700 = gregorianYear - 1700; - return PolynomialSum(s_coefficients1700to1799, yearsSince1700) / SecondsPerDay; - } - - private static double EphemerisCorrection1620to1699(int gregorianYear) - { - Debug.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 - } - } - - Debug.Fail("Not expected to come here"); - return DefaultEphemerisCorrection(year); - } - - public static 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))); - const 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 - public static 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 - public static 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)); - } - - public static 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); - } - - public static 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 occurrence (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; - } - } - Debug.Assert(day != upperBoundNewYearDay); - - return day - 1; - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/CharUnicodeInfo.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/CharUnicodeInfo.cs deleted file mode 100644 index 59ccd9e30da..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/CharUnicodeInfo.cs +++ /dev/null @@ -1,321 +0,0 @@ -// 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.Buffers.Binary; -using System.Diagnostics; -using System.Text; -using Internal.Runtime.CompilerServices; - -namespace System.Globalization -{ - /// <summary> - /// This class implements a set of methods for retrieving character type - /// information. Character type information is independent of culture - /// and region. - /// </summary> - public static partial class CharUnicodeInfo - { - 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 HIGH_SURROGATE_RANGE = 0x3FF; - - 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; - - /// <summary> - /// 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. - /// </summary> - internal static int InternalConvertToUtf32(string s, int index) - { - Debug.Assert(s != null, "s != null"); - Debug.Assert(index >= 0 && index < s.Length, "index < s.Length"); - if (index < s.Length - 1) - { - int temp1 = (int)s[index] - HIGH_SURROGATE_START; - if ((uint)temp1 <= HIGH_SURROGATE_RANGE) - { - int temp2 = (int)s[index + 1] - LOW_SURROGATE_START; - if ((uint)temp2 <= HIGH_SURROGATE_RANGE) - { - // Convert the surrogate to UTF32 and get the result. - return (temp1 * 0x400) + temp2 + UNICODE_PLANE01_START; - } - } - } - return (int)s[index]; - } - - internal static int InternalConvertToUtf32(StringBuilder s, int index) - { - Debug.Assert(s != null, "s != null"); - Debug.Assert(index >= 0 && index < s.Length, "index < s.Length"); - - int c = (int)s[index]; - if (index < s.Length - 1) - { - int temp1 = c - HIGH_SURROGATE_START; - if ((uint)temp1 <= HIGH_SURROGATE_RANGE) - { - int temp2 = (int)s[index + 1] - LOW_SURROGATE_START; - if ((uint)temp2 <= HIGH_SURROGATE_RANGE) - { - // Convert the surrogate to UTF32 and get the result. - return (temp1 * 0x400) + temp2 + UNICODE_PLANE01_START; - } - } - } - return c; - } - - /// <summary> - /// Convert a character or a surrogate pair starting at index of string s - /// to UTF32 value. - /// 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. - /// </summary> - internal static int InternalConvertToUtf32(string s, int index, out int charLength) - { - Debug.Assert(s != null, "s != null"); - Debug.Assert(s.Length > 0, "s.Length > 0"); - Debug.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 ((uint)temp1 <= HIGH_SURROGATE_RANGE) - { - int temp2 = (int)s[index + 1] - LOW_SURROGATE_START; - if ((uint)temp2 <= HIGH_SURROGATE_RANGE) - { - // Convert the surrogate to UTF32 and get the result. - charLength++; - return (temp1 * 0x400) + temp2 + UNICODE_PLANE01_START; - } - } - } - return (int)s[index]; - } - - /// <summary> - /// 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 - /// </summary> - internal static double InternalGetNumericValue(int ch) - { - Debug.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. - int index = ch >> 8; - if ((uint)index < (uint)NumericLevel1Index.Length) - { - index = NumericLevel1Index[index]; - // Get the level 2 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 = NumericLevel2Index[(index << 4) + ((ch >> 4) & 0x000f)]; - index = NumericLevel3Index[(index << 4) + (ch & 0x000f)]; - ref byte value = ref Unsafe.AsRef(in NumericValues[index * 8]); - - if (BitConverter.IsLittleEndian) - { - return Unsafe.ReadUnaligned<double>(ref value); - } - - return BitConverter.Int64BitsToDouble(BinaryPrimitives.ReverseEndianness(Unsafe.ReadUnaligned<long>(ref value))); - } - return -1; - } - - internal static byte InternalGetDigitValues(int ch, int offset) - { - Debug.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. - int index = ch >> 8; - if ((uint)index < (uint)NumericLevel1Index.Length) - { - index = NumericLevel1Index[index]; - // Get the level 2 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 = NumericLevel2Index[(index << 4) + ((ch >> 4) & 0x000f)]; - index = NumericLevel3Index[(index << 4) + (ch & 0x000f)]; - return DigitValues[index * 2 + offset]; - } - return 0xff; - } - - /// <summary> - /// 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. - /// </summary> - public static double GetNumericValue(char ch) - { - return InternalGetNumericValue(ch); - } - - public static double GetNumericValue(string s, int index) - { - if (s == null) - { - throw new ArgumentNullException(nameof(s)); - } - if (index < 0 || index >= s.Length) - { - throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_Index); - } - - return InternalGetNumericValue(InternalConvertToUtf32(s, index)); - } - - public static int GetDecimalDigitValue(char ch) - { - return (sbyte)InternalGetDigitValues(ch, 0); - } - - public static int GetDecimalDigitValue(string s, int index) - { - if (s == null) - { - throw new ArgumentNullException(nameof(s)); - } - if (index < 0 || index >= s.Length) - { - throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_Index); - } - - return (sbyte)InternalGetDigitValues(InternalConvertToUtf32(s, index), 0); - } - - public static int GetDigitValue(char ch) - { - return (sbyte)InternalGetDigitValues(ch, 1); - } - - public static int GetDigitValue(string s, int index) - { - if (s == null) - { - throw new ArgumentNullException(nameof(s)); - } - if (index < 0 || index >= s.Length) - { - throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_Index); - } - - return (sbyte)InternalGetDigitValues(InternalConvertToUtf32(s, index), 1); - } - - public static UnicodeCategory GetUnicodeCategory(char ch) - { - return GetUnicodeCategory((int)ch); - } - - public static UnicodeCategory GetUnicodeCategory(string s, int index) - { - if (s == null) - { - throw new ArgumentNullException(nameof(s)); - } - if (((uint)index) >= ((uint)s.Length)) - { - throw new ArgumentOutOfRangeException(nameof(index)); - } - - return InternalGetUnicodeCategory(s, index); - } - - public static UnicodeCategory GetUnicodeCategory(int codePoint) - { - return (UnicodeCategory)InternalGetCategoryValue(codePoint, UNICODE_CATEGORY_OFFSET); - } - - /// <summary> - /// Returns the Unicode Category property for the character c. - /// Note that this API will return values for D800-DF00 surrogate halves. - /// </summary> - internal static byte InternalGetCategoryValue(int ch, int offset) - { - Debug.Assert(ch >= 0 && ch <= 0x10ffff, "ch is not in valid Unicode range."); - // Get the level 2 item from the highest 11 bits of ch. - int index = CategoryLevel1Index[ch >> 9]; - // Get the level 2 WORD offset from the next 5 bits 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 = Unsafe.ReadUnaligned<ushort>(ref Unsafe.AsRef(in CategoryLevel2Index[(index << 6) + ((ch >> 3) & 0b111110)])); - if (!BitConverter.IsLittleEndian) - { - index = BinaryPrimitives.ReverseEndianness((ushort)index); - } - - // Get the result from the 0 -3 bit of ch. - index = CategoryLevel3Index[(index << 4) + (ch & 0x000f)]; - return CategoriesValue[index * 2 + offset]; - } - - /// <summary> - /// Returns the Unicode Category property for the character c. - /// </summary> - internal static UnicodeCategory InternalGetUnicodeCategory(string value, int index) - { - Debug.Assert(value != null, "value can not be null"); - Debug.Assert(index < value.Length, "index < value.Length"); - - return GetUnicodeCategory(InternalConvertToUtf32(value, index)); - } - - internal static BidiCategory GetBidiCategory(string s, int index) - { - if (s == null) - { - throw new ArgumentNullException(nameof(s)); - } - if (((uint)index) >= ((uint)s.Length)) - { - throw new ArgumentOutOfRangeException(nameof(index)); - } - - return (BidiCategory)InternalGetCategoryValue(InternalConvertToUtf32(s, index), BIDI_CATEGORY_OFFSET); - } - - internal static BidiCategory GetBidiCategory(StringBuilder s, int index) - { - Debug.Assert(s != null, "s can not be null"); - Debug.Assert(index >= 0 && index < s.Length, "invalid index"); - - return (BidiCategory)InternalGetCategoryValue(InternalConvertToUtf32(s, index), BIDI_CATEGORY_OFFSET); - } - - /// <summary> - /// 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. - /// </summary> - internal static UnicodeCategory InternalGetUnicodeCategory(string str, int index, out int charLength) - { - Debug.Assert(str != null, "str can not be null"); - Debug.Assert(str.Length > 0, "str.Length > 0"); - Debug.Assert(index >= 0 && index < str.Length, "index >= 0 && index < str.Length"); - - return GetUnicodeCategory(InternalConvertToUtf32(str, index, out charLength)); - } - - internal static bool IsCombiningCategory(UnicodeCategory uc) - { - Debug.Assert(uc >= 0, "uc >= 0"); - return - uc == UnicodeCategory.NonSpacingMark || - uc == UnicodeCategory.SpacingCombiningMark || - uc == UnicodeCategory.EnclosingMark - ; - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/CharUnicodeInfoData.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/CharUnicodeInfoData.cs deleted file mode 100644 index 522c33004a4..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/CharUnicodeInfoData.cs +++ /dev/null @@ -1,1576 +0,0 @@ -// 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 static partial class CharUnicodeInfo - { - // THE FOLLOWING DATA IS AUTO GENERATED BY GenUnicodeProp program UNDER THE TOOLS FOLDER - // PLEASE DON'T MODIFY BY HAND - - - // 11:5:4 index table of the Unicode category data. - private static ReadOnlySpan<byte> CategoryLevel1Index => new byte[2176] - { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, - 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1b, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, - 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, - 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1c, - 0x1d, 0x1a, 0x1e, 0x1f, 0x20, 0x21, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, - 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x22, 0x23, 0x23, 0x23, 0x23, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x25, 0x26, 0x27, 0x28, - 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, - 0x1a, 0x39, 0x3a, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x1a, 0x1a, 0x3c, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x1a, 0x3d, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x1a, 0x3e, 0x3b, 0x3f, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, - 0x1a, 0x1a, 0x1a, 0x40, 0x1a, 0x41, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x42, 0x43, 0x3b, 0x3b, 0x3b, 0x3b, 0x44, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x3b, 0x3b, - 0x4b, 0x3b, 0x3b, 0x3b, 0x4c, 0x3b, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x3b, 0x3b, - 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, - 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, - 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, - 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, - 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, - 0x1a, 0x1a, 0x1a, 0x55, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x56, 0x57, 0x1a, 0x1a, 0x1a, - 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x58, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, - 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x59, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x1a, 0x5a, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x5b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x5c, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x5c - }; - - private static ReadOnlySpan<byte> CategoryLevel2Index => new byte[5952] - { - 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, - 0x08, 0x00, 0x09, 0x00, 0x0a, 0x00, 0x0b, 0x00, 0x0c, 0x00, 0x0d, 0x00, 0x0e, 0x00, 0x0f, 0x00, - 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x11, 0x00, 0x12, 0x00, 0x10, 0x00, 0x10, 0x00, 0x13, 0x00, - 0x14, 0x00, 0x15, 0x00, 0x16, 0x00, 0x17, 0x00, 0x18, 0x00, 0x19, 0x00, 0x10, 0x00, 0x1a, 0x00, - 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x1b, 0x00, 0x1c, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x0e, 0x00, - 0x0e, 0x00, 0x1d, 0x00, 0x0e, 0x00, 0x1e, 0x00, 0x1f, 0x00, 0x20, 0x00, 0x21, 0x00, 0x22, 0x00, - 0x23, 0x00, 0x23, 0x00, 0x23, 0x00, 0x23, 0x00, 0x23, 0x00, 0x23, 0x00, 0x23, 0x00, 0x24, 0x00, - 0x25, 0x00, 0x26, 0x00, 0x27, 0x00, 0x0e, 0x00, 0x28, 0x00, 0x29, 0x00, 0x10, 0x00, 0x2a, 0x00, - 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x10, 0x00, 0x10, 0x00, - 0x2b, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x2c, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, - 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x2d, 0x00, 0x0c, 0x00, 0x2e, 0x00, 0x0e, 0x00, 0x0e, 0x00, - 0x2f, 0x00, 0x30, 0x00, 0x23, 0x00, 0x31, 0x00, 0x32, 0x00, 0x33, 0x00, 0x34, 0x00, 0x35, 0x00, - 0x36, 0x00, 0x37, 0x00, 0x38, 0x00, 0x38, 0x00, 0x39, 0x00, 0x23, 0x00, 0x3a, 0x00, 0x3b, 0x00, - 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x3e, 0x00, - 0x3f, 0x00, 0x40, 0x00, 0x38, 0x00, 0x23, 0x00, 0x41, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, - 0x38, 0x00, 0x38, 0x00, 0x42, 0x00, 0x43, 0x00, 0x44, 0x00, 0x33, 0x00, 0x45, 0x00, 0x46, 0x00, - 0x33, 0x00, 0x47, 0x00, 0x48, 0x00, 0x49, 0x00, 0x33, 0x00, 0x4a, 0x00, 0x4b, 0x00, 0x4c, 0x00, - 0x4c, 0x00, 0x4c, 0x00, 0x38, 0x00, 0x4d, 0x00, 0x4c, 0x00, 0x4e, 0x00, 0x4f, 0x00, 0x23, 0x00, - 0x50, 0x00, 0x51, 0x00, 0x51, 0x00, 0x52, 0x00, 0x53, 0x00, 0x54, 0x00, 0x55, 0x00, 0x56, 0x00, - 0x57, 0x00, 0x58, 0x00, 0x59, 0x00, 0x5a, 0x00, 0x5b, 0x00, 0x5c, 0x00, 0x5d, 0x00, 0x5e, 0x00, - 0x5f, 0x00, 0x58, 0x00, 0x59, 0x00, 0x60, 0x00, 0x61, 0x00, 0x62, 0x00, 0x63, 0x00, 0x64, 0x00, - 0x65, 0x00, 0x66, 0x00, 0x59, 0x00, 0x67, 0x00, 0x68, 0x00, 0x69, 0x00, 0x5d, 0x00, 0x6a, 0x00, - 0x6b, 0x00, 0x58, 0x00, 0x59, 0x00, 0x6c, 0x00, 0x6d, 0x00, 0x6e, 0x00, 0x5d, 0x00, 0x6f, 0x00, - 0x70, 0x00, 0x71, 0x00, 0x72, 0x00, 0x73, 0x00, 0x74, 0x00, 0x75, 0x00, 0x63, 0x00, 0x76, 0x00, - 0x77, 0x00, 0x78, 0x00, 0x59, 0x00, 0x79, 0x00, 0x7a, 0x00, 0x7b, 0x00, 0x5d, 0x00, 0x7c, 0x00, - 0x7d, 0x00, 0x78, 0x00, 0x59, 0x00, 0x7e, 0x00, 0x7f, 0x00, 0x80, 0x00, 0x5d, 0x00, 0x81, 0x00, - 0x82, 0x00, 0x78, 0x00, 0x51, 0x00, 0x83, 0x00, 0x84, 0x00, 0x85, 0x00, 0x5d, 0x00, 0x86, 0x00, - 0x87, 0x00, 0x88, 0x00, 0x51, 0x00, 0x89, 0x00, 0x8a, 0x00, 0x8b, 0x00, 0x63, 0x00, 0x8c, 0x00, - 0x8d, 0x00, 0x51, 0x00, 0x51, 0x00, 0x8e, 0x00, 0x8f, 0x00, 0x90, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x91, 0x00, 0x92, 0x00, 0x93, 0x00, 0x94, 0x00, 0x95, 0x00, 0x96, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x97, 0x00, 0x98, 0x00, 0x99, 0x00, 0x9a, 0x00, 0x9b, 0x00, 0x51, 0x00, 0x9c, 0x00, 0x9d, 0x00, - 0x9e, 0x00, 0x9f, 0x00, 0x23, 0x00, 0xa0, 0x00, 0xa1, 0x00, 0xa2, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x51, 0x00, 0x51, 0x00, 0xa3, 0x00, 0xa4, 0x00, 0xa5, 0x00, 0xa6, 0x00, 0xa7, 0x00, 0xa8, 0x00, - 0xa9, 0x00, 0xaa, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0xab, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0xac, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0xad, 0x00, 0xae, 0x00, 0x51, 0x00, 0x51, 0x00, - 0xad, 0x00, 0x51, 0x00, 0x51, 0x00, 0xaf, 0x00, 0xb0, 0x00, 0xb1, 0x00, 0x51, 0x00, 0x51, 0x00, - 0x51, 0x00, 0xb0, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0xb2, 0x00, 0xb3, 0x00, 0xb4, 0x00, - 0x51, 0x00, 0xb5, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0xb6, 0x00, - 0xb7, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0xb8, 0x00, 0x51, 0x00, - 0xb9, 0x00, 0xba, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0xbb, 0x00, 0xbc, 0x00, - 0xbd, 0x00, 0xbe, 0x00, 0x51, 0x00, 0xbf, 0x00, 0x51, 0x00, 0xc0, 0x00, 0xbd, 0x00, 0xc1, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0xc2, 0x00, 0xc3, 0x00, 0xc4, 0x00, 0xc5, 0x00, 0xc6, 0x00, - 0xc7, 0x00, 0xc5, 0x00, 0x51, 0x00, 0x51, 0x00, 0xc8, 0x00, 0x51, 0x00, 0x51, 0x00, 0xc9, 0x00, - 0xca, 0x00, 0x51, 0x00, 0xcb, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0xcc, 0x00, - 0x51, 0x00, 0xcd, 0x00, 0xce, 0x00, 0xcf, 0x00, 0xd0, 0x00, 0x51, 0x00, 0xd1, 0x00, 0xd2, 0x00, - 0x51, 0x00, 0x51, 0x00, 0xd3, 0x00, 0x51, 0x00, 0xd4, 0x00, 0xd5, 0x00, 0xd6, 0x00, 0xd6, 0x00, - 0x51, 0x00, 0xd7, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0xd8, 0x00, 0xd9, 0x00, 0xda, 0x00, - 0xc5, 0x00, 0xc5, 0x00, 0xdb, 0x00, 0xdc, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0xdd, 0x00, 0x51, 0x00, 0x51, 0x00, 0xde, 0x00, 0xdf, 0x00, 0xa5, 0x00, 0xe0, 0x00, 0xe1, 0x00, - 0xe2, 0x00, 0x51, 0x00, 0xe3, 0x00, 0xe4, 0x00, 0x51, 0x00, 0x51, 0x00, 0xe5, 0x00, 0xe6, 0x00, - 0x51, 0x00, 0x51, 0x00, 0xe7, 0x00, 0xe8, 0x00, 0xe9, 0x00, 0xe4, 0x00, 0x51, 0x00, 0xea, 0x00, - 0xeb, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0xec, 0x00, 0xed, 0x00, 0xee, 0x00, 0xef, 0x00, 0xf0, 0x00, - 0x0e, 0x00, 0x0e, 0x00, 0xf1, 0x00, 0xf2, 0x00, 0xf2, 0x00, 0xf2, 0x00, 0xf3, 0x00, 0xf4, 0x00, - 0x0e, 0x00, 0xf5, 0x00, 0xf2, 0x00, 0xf2, 0x00, 0x23, 0x00, 0x23, 0x00, 0x23, 0x00, 0xf6, 0x00, - 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, - 0x10, 0x00, 0xf7, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, - 0xf8, 0x00, 0xf9, 0x00, 0xf8, 0x00, 0xf8, 0x00, 0xf9, 0x00, 0xfa, 0x00, 0xf8, 0x00, 0xfb, 0x00, - 0xfc, 0x00, 0xfc, 0x00, 0xfc, 0x00, 0xfd, 0x00, 0xfe, 0x00, 0xff, 0x00, 0x00, 0x01, 0x01, 0x01, - 0x02, 0x01, 0x03, 0x01, 0x04, 0x01, 0x05, 0x01, 0x06, 0x01, 0x07, 0x01, 0x08, 0x01, 0x09, 0x01, - 0x0a, 0x01, 0x0b, 0x01, 0x0c, 0x01, 0x0c, 0x01, 0x4c, 0x00, 0x0d, 0x01, 0x0e, 0x01, 0x0f, 0x01, - 0x10, 0x01, 0x11, 0x01, 0x12, 0x01, 0x13, 0x01, 0x14, 0x01, 0x15, 0x01, 0x16, 0x01, 0x16, 0x01, - 0x17, 0x01, 0x18, 0x01, 0x19, 0x01, 0xd6, 0x00, 0x1a, 0x01, 0x1b, 0x01, 0xd6, 0x00, 0x1c, 0x01, - 0x1d, 0x01, 0x1e, 0x01, 0x1d, 0x01, 0x1d, 0x01, 0x1d, 0x01, 0x1d, 0x01, 0x1d, 0x01, 0x1d, 0x01, - 0x1d, 0x01, 0x1d, 0x01, 0x1d, 0x01, 0x1d, 0x01, 0x1d, 0x01, 0x1d, 0x01, 0x1d, 0x01, 0x1d, 0x01, - 0x1f, 0x01, 0xd6, 0x00, 0x20, 0x01, 0x21, 0x01, 0x22, 0x01, 0x22, 0x01, 0x22, 0x01, 0x23, 0x01, - 0xd6, 0x00, 0x24, 0x01, 0x1d, 0x01, 0x25, 0x01, 0xd6, 0x00, 0x26, 0x01, 0x27, 0x01, 0xd6, 0x00, - 0xd6, 0x00, 0xd6, 0x00, 0x28, 0x01, 0x4c, 0x00, 0x29, 0x01, 0x4c, 0x00, 0x15, 0x01, 0x15, 0x01, - 0x2a, 0x01, 0x2b, 0x01, 0x22, 0x01, 0x22, 0x01, 0x22, 0x01, 0x22, 0x01, 0x2c, 0x01, 0x15, 0x01, - 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, - 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0x2d, 0x01, 0x2e, 0x01, 0xd6, 0x00, 0xd6, 0x00, 0x2f, 0x01, - 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0x30, 0x01, 0xd6, 0x00, - 0xd6, 0x00, 0xd6, 0x00, 0x31, 0x01, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, - 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0x32, 0x01, 0x33, 0x01, - 0x15, 0x01, 0x34, 0x01, 0xd6, 0x00, 0xd6, 0x00, 0x35, 0x01, 0x1d, 0x01, 0x36, 0x01, 0x1d, 0x01, - 0x22, 0x01, 0x22, 0x01, 0x22, 0x01, 0x22, 0x01, 0x22, 0x01, 0x22, 0x01, 0x22, 0x01, 0x22, 0x01, - 0x22, 0x01, 0x22, 0x01, 0x22, 0x01, 0x22, 0x01, 0x22, 0x01, 0x22, 0x01, 0x22, 0x01, 0x22, 0x01, - 0x1d, 0x01, 0x1d, 0x01, 0x1d, 0x01, 0x1d, 0x01, 0x1d, 0x01, 0x1d, 0x01, 0x1d, 0x01, 0x1d, 0x01, - 0x37, 0x01, 0x38, 0x01, 0x1d, 0x01, 0x1d, 0x01, 0x1d, 0x01, 0x39, 0x01, 0x1d, 0x01, 0x3a, 0x01, - 0x1d, 0x01, 0x1d, 0x01, 0x1d, 0x01, 0x1d, 0x01, 0x1d, 0x01, 0x1d, 0x01, 0x1d, 0x01, 0x1d, 0x01, - 0x1d, 0x01, 0x1d, 0x01, 0x1d, 0x01, 0x1d, 0x01, 0x1d, 0x01, 0x1d, 0x01, 0x1d, 0x01, 0x1d, 0x01, - 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0x1d, 0x01, 0x3b, 0x01, 0xd6, 0x00, 0xd6, 0x00, 0x3c, 0x01, - 0xd6, 0x00, 0x3d, 0x01, 0xd6, 0x00, 0xd6, 0x00, 0x3e, 0x01, 0xd6, 0x00, 0xd6, 0x00, 0x3f, 0x01, - 0x0c, 0x00, 0x0c, 0x00, 0x40, 0x01, 0x0e, 0x00, 0x0e, 0x00, 0x41, 0x01, 0x42, 0x01, 0x43, 0x01, - 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x44, 0x01, 0x45, 0x01, - 0x0e, 0x00, 0x0e, 0x00, 0x46, 0x01, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x47, 0x01, 0x48, 0x01, - 0x51, 0x00, 0x49, 0x01, 0x4a, 0x01, 0x4a, 0x01, 0x4a, 0x01, 0x4a, 0x01, 0x23, 0x00, 0x23, 0x00, - 0x4b, 0x01, 0x4c, 0x01, 0x4d, 0x01, 0x4e, 0x01, 0x4f, 0x01, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0xd6, 0x00, 0x50, 0x01, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0x51, 0x01, - 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, - 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0x52, 0x01, 0x4c, 0x00, 0x53, 0x01, - 0x54, 0x01, 0x55, 0x01, 0x56, 0x01, 0x57, 0x01, 0x8d, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, - 0x51, 0x00, 0x58, 0x01, 0xb7, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x59, 0x01, - 0x5a, 0x01, 0x51, 0x00, 0x51, 0x00, 0x8d, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, - 0xcd, 0x00, 0x5b, 0x01, 0x51, 0x00, 0x5c, 0x01, 0xd6, 0x00, 0xd6, 0x00, 0x51, 0x01, 0x51, 0x00, - 0x22, 0x01, 0x5d, 0x01, 0x5e, 0x01, 0x22, 0x01, 0x5f, 0x01, 0x60, 0x01, 0x22, 0x01, 0x61, 0x01, - 0x5e, 0x01, 0x22, 0x01, 0x22, 0x01, 0x62, 0x01, 0x63, 0x01, 0x22, 0x01, 0x22, 0x01, 0x64, 0x01, - 0x22, 0x01, 0x22, 0x01, 0x22, 0x01, 0x22, 0x01, 0x22, 0x01, 0x22, 0x01, 0x22, 0x01, 0x65, 0x01, - 0x22, 0x01, 0x22, 0x01, 0x22, 0x01, 0x22, 0x01, 0x22, 0x01, 0x66, 0x01, 0x22, 0x01, 0x67, 0x01, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0xcc, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x4c, 0x00, - 0x51, 0x00, 0x68, 0x01, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, - 0x9c, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0x28, 0x01, 0x51, 0x00, 0x51, 0x00, 0xea, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, - 0x69, 0x01, 0x51, 0x00, 0x6a, 0x01, 0x4c, 0x00, 0x10, 0x00, 0x10, 0x00, 0x6b, 0x01, 0x6c, 0x01, - 0x10, 0x00, 0x6d, 0x01, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x6e, 0x01, 0x6f, 0x01, - 0x22, 0x00, 0x70, 0x01, 0x71, 0x01, 0x72, 0x01, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x73, 0x01, - 0x74, 0x01, 0x75, 0x01, 0x76, 0x01, 0x77, 0x01, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x78, 0x01, - 0x79, 0x01, 0x51, 0x00, 0x7a, 0x01, 0x7b, 0x01, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x7c, 0x01, - 0x7d, 0x01, 0x51, 0x00, 0x51, 0x00, 0x7e, 0x01, 0x7f, 0x01, 0xc5, 0x00, 0x23, 0x00, 0x80, 0x01, - 0xe4, 0x00, 0x51, 0x00, 0x81, 0x01, 0x51, 0x00, 0x82, 0x01, 0x83, 0x01, 0x51, 0x00, 0x9c, 0x00, - 0x50, 0x00, 0x51, 0x00, 0x51, 0x00, 0x84, 0x01, 0x85, 0x01, 0x86, 0x01, 0x87, 0x01, 0x88, 0x01, - 0x51, 0x00, 0x51, 0x00, 0x89, 0x01, 0x8a, 0x01, 0x8b, 0x01, 0x8c, 0x01, 0x51, 0x00, 0x8d, 0x01, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x8e, 0x01, 0x8f, 0x01, 0x90, 0x01, 0x91, 0x01, 0x92, 0x01, - 0x93, 0x01, 0x94, 0x01, 0x4a, 0x01, 0x0e, 0x00, 0x0e, 0x00, 0x95, 0x01, 0x96, 0x01, 0x0e, 0x00, - 0x0e, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x51, 0x00, 0x51, 0x00, 0x97, 0x01, 0xc5, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x98, 0x01, 0x51, 0x00, 0x99, 0x01, 0x51, 0x00, 0x51, 0x00, 0xd3, 0x00, - 0x9a, 0x01, 0x9a, 0x01, 0x9a, 0x01, 0x9a, 0x01, 0x9a, 0x01, 0x9a, 0x01, 0x9a, 0x01, 0x9a, 0x01, - 0x9a, 0x01, 0x9a, 0x01, 0x9a, 0x01, 0x9a, 0x01, 0x9a, 0x01, 0x9a, 0x01, 0x9a, 0x01, 0x9a, 0x01, - 0x9a, 0x01, 0x9a, 0x01, 0x9a, 0x01, 0x9a, 0x01, 0x9a, 0x01, 0x9a, 0x01, 0x9a, 0x01, 0x9a, 0x01, - 0x9a, 0x01, 0x9a, 0x01, 0x9a, 0x01, 0x9a, 0x01, 0x9a, 0x01, 0x9a, 0x01, 0x9a, 0x01, 0x9a, 0x01, - 0x9b, 0x01, 0x9b, 0x01, 0x9b, 0x01, 0x9b, 0x01, 0x9b, 0x01, 0x9b, 0x01, 0x9b, 0x01, 0x9b, 0x01, - 0x9b, 0x01, 0x9b, 0x01, 0x9b, 0x01, 0x9b, 0x01, 0x9b, 0x01, 0x9b, 0x01, 0x9b, 0x01, 0x9b, 0x01, - 0x9b, 0x01, 0x9b, 0x01, 0x9b, 0x01, 0x9b, 0x01, 0x9b, 0x01, 0x9b, 0x01, 0x9b, 0x01, 0x9b, 0x01, - 0x9b, 0x01, 0x9b, 0x01, 0x9b, 0x01, 0x9b, 0x01, 0x9b, 0x01, 0x9b, 0x01, 0x9b, 0x01, 0x9b, 0x01, - 0x9b, 0x01, 0x9b, 0x01, 0x9b, 0x01, 0x9b, 0x01, 0x9b, 0x01, 0x9b, 0x01, 0x9b, 0x01, 0x9b, 0x01, - 0x9b, 0x01, 0x9b, 0x01, 0x9b, 0x01, 0x9b, 0x01, 0x9b, 0x01, 0x9b, 0x01, 0x9b, 0x01, 0x9b, 0x01, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0xd1, 0x00, 0x51, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0xd4, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x9c, 0x01, 0x9d, 0x01, 0x9e, 0x01, 0x9f, 0x01, 0xa0, 0x01, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, - 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0xa1, 0x01, 0xa2, 0x01, 0xa3, 0x01, 0x38, 0x00, 0x38, 0x00, - 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, - 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, - 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0xa4, 0x01, 0x4c, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, - 0x38, 0x00, 0xa5, 0x01, 0x38, 0x00, 0x38, 0x00, 0xa6, 0x01, 0x4c, 0x00, 0x4c, 0x00, 0xa7, 0x01, - 0x23, 0x00, 0xa8, 0x01, 0x23, 0x00, 0xa9, 0x01, 0xaa, 0x01, 0xab, 0x01, 0xac, 0x01, 0xad, 0x01, - 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0xae, 0x01, - 0xaf, 0x01, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, 0x06, 0x00, 0xb0, 0x01, 0xb1, 0x01, 0xb2, 0x01, - 0x51, 0x00, 0xb3, 0x01, 0x51, 0x00, 0xcd, 0x00, 0xb4, 0x01, 0xb5, 0x01, 0xb6, 0x01, 0xb7, 0x01, - 0xb8, 0x01, 0x51, 0x00, 0xb1, 0x00, 0xb9, 0x01, 0xd1, 0x00, 0xd1, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x5c, 0x01, - 0xba, 0x01, 0xbb, 0x01, 0xbb, 0x01, 0xbc, 0x01, 0xbd, 0x01, 0xbd, 0x01, 0xbd, 0x01, 0xbe, 0x01, - 0xbf, 0x01, 0x53, 0x01, 0xc0, 0x01, 0x4c, 0x00, 0x4c, 0x00, 0x22, 0x01, 0x22, 0x01, 0xc1, 0x01, - 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x51, 0x00, 0x9c, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x69, 0x00, 0xc2, 0x01, 0xc3, 0x01, - 0x51, 0x00, 0x51, 0x00, 0xc4, 0x01, 0x51, 0x00, 0xc5, 0x01, 0x51, 0x00, 0x51, 0x00, 0xc6, 0x01, - 0x51, 0x00, 0xc7, 0x01, 0x51, 0x00, 0x51, 0x00, 0xc8, 0x01, 0xc9, 0x01, 0x4c, 0x00, 0x4c, 0x00, - 0x0c, 0x00, 0x0c, 0x00, 0xca, 0x01, 0x0e, 0x00, 0x0e, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, - 0x51, 0x00, 0xd1, 0x00, 0xc5, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0xcb, 0x01, 0x0e, 0x00, 0xcc, 0x01, - 0x51, 0x00, 0x51, 0x00, 0xcd, 0x01, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0xce, 0x01, 0x4c, 0x00, - 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x49, 0x01, 0x51, 0x00, 0xcc, 0x00, 0xcd, 0x01, 0x4c, 0x00, - 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0xcf, 0x01, 0x33, 0x00, 0x33, 0x00, 0xd0, 0x01, 0x33, 0x00, 0xd1, 0x01, 0x33, 0x00, 0xd2, 0x01, - 0x33, 0x00, 0xd3, 0x01, 0xd4, 0x01, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x33, 0x00, 0xd5, 0x01, - 0x33, 0x00, 0xd6, 0x01, 0x33, 0x00, 0xd7, 0x01, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0xd8, 0x01, 0xd9, 0x01, 0xda, 0x01, 0xd9, 0x01, 0xd9, 0x01, - 0xdb, 0x01, 0xdc, 0x01, 0x33, 0x00, 0xdd, 0x01, 0xde, 0x01, 0xdf, 0x01, 0x33, 0x00, 0xe0, 0x01, - 0x33, 0x00, 0xe1, 0x01, 0x4c, 0x00, 0x4c, 0x00, 0xe2, 0x01, 0x33, 0x00, 0xe3, 0x01, 0xe4, 0x01, - 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0xe5, 0x01, 0x33, 0x00, 0xe6, 0x01, 0x33, 0x00, 0xe7, 0x01, - 0x33, 0x00, 0xe8, 0x01, 0xe9, 0x01, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0xea, 0x01, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0xeb, 0x01, 0xeb, 0x01, 0xeb, 0x01, 0xec, 0x01, 0xed, 0x01, 0xed, 0x01, 0xed, 0x01, 0xee, 0x01, - 0x38, 0x00, 0x38, 0x00, 0xef, 0x01, 0xf0, 0x01, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0xf1, 0x01, 0xf2, 0x01, - 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x33, 0x00, 0xe1, 0x01, 0xf3, 0x01, 0x38, 0x00, 0x42, 0x00, 0xf4, 0x01, 0x4c, 0x00, 0x4c, 0x00, - 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0xf5, 0x01, 0x51, 0x00, 0x51, 0x00, 0xf6, 0x01, 0xf7, 0x01, 0xf8, 0x01, 0xf9, 0x01, 0xfa, 0x01, - 0xe2, 0x00, 0x51, 0x00, 0x51, 0x00, 0xfb, 0x01, 0xfc, 0x01, 0x51, 0x00, 0xc9, 0x00, 0xc5, 0x00, - 0xfd, 0x01, 0x51, 0x00, 0xfe, 0x01, 0xff, 0x01, 0x00, 0x02, 0x51, 0x00, 0x51, 0x00, 0x01, 0x02, - 0xe2, 0x00, 0x51, 0x00, 0x51, 0x00, 0x02, 0x02, 0x03, 0x02, 0x04, 0x02, 0x05, 0x02, 0x06, 0x02, - 0x51, 0x00, 0x66, 0x00, 0x07, 0x02, 0x08, 0x02, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x09, 0x02, 0x0a, 0x02, 0x0b, 0x02, 0x51, 0x00, 0x51, 0x00, 0x0c, 0x02, 0x0d, 0x02, 0xc5, 0x00, - 0x0e, 0x02, 0x58, 0x00, 0x59, 0x00, 0x0f, 0x02, 0x10, 0x02, 0x11, 0x02, 0x12, 0x02, 0x13, 0x02, - 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x14, 0x02, 0x15, 0x02, 0x16, 0x02, 0x4c, 0x00, 0x4c, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x17, 0x02, 0x18, 0x02, 0xc5, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x19, 0x02, 0x1a, 0x02, 0x1b, 0x02, 0x1c, 0x02, 0x4c, 0x00, 0x4c, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x1d, 0x02, 0x1e, 0x02, 0xc5, 0x00, 0x1f, 0x02, 0x4c, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x20, 0x02, 0x21, 0x02, 0xc5, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x51, 0x00, 0xb2, 0x00, 0x22, 0x02, 0x23, 0x02, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x07, 0x02, 0x24, 0x02, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x4c, 0x00, 0x4c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x99, 0x00, 0x25, 0x02, - 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x26, 0x02, 0x51, 0x00, 0x51, 0x00, 0x27, 0x02, 0x28, 0x02, 0x29, 0x02, 0x51, 0x00, 0x51, 0x00, - 0x2a, 0x02, 0x2b, 0x02, 0x2c, 0x02, 0x4c, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0xc9, 0x00, - 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x59, 0x00, 0x51, 0x00, 0x19, 0x02, 0x2d, 0x02, 0x2e, 0x02, 0x99, 0x00, 0xb4, 0x00, 0x2f, 0x02, - 0x51, 0x00, 0x30, 0x02, 0x31, 0x02, 0x32, 0x02, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x33, 0x02, 0x51, 0x00, 0x51, 0x00, 0x34, 0x02, 0x35, 0x02, 0xc5, 0x00, 0x36, 0x02, 0x51, 0x00, - 0x37, 0x02, 0x38, 0x02, 0xc5, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x51, 0x00, 0x39, 0x02, - 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, - 0x51, 0x00, 0xd4, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x16, 0x01, 0x16, 0x01, 0x16, 0x01, 0x16, 0x01, 0x16, 0x01, 0x16, 0x01, 0x3a, 0x02, 0x3b, 0x02, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x98, 0x01, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x51, 0x00, 0x51, 0x00, 0xcd, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x49, 0x01, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0xc9, 0x00, 0x51, 0x00, 0xcd, 0x00, 0x86, 0x01, 0x4c, 0x00, - 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x51, 0x00, 0xd1, 0x00, 0x3c, 0x02, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x3d, 0x02, 0x3e, 0x02, 0x3f, 0x02, 0x40, 0x02, 0x41, 0x02, - 0x51, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0e, 0x00, 0x0e, 0x00, - 0xbb, 0x01, 0x42, 0x02, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0xd2, 0x00, 0x43, 0x02, 0x44, 0x02, 0x45, 0x02, - 0xfa, 0x01, 0x46, 0x02, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x47, 0x02, 0x4c, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x48, 0x02, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x49, 0x02, - 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, - 0x51, 0x00, 0xcd, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x51, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0xd3, 0x00, - 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x5c, 0x01, 0x9c, 0x00, - 0xc9, 0x00, 0x4a, 0x02, 0x4b, 0x02, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x22, 0x01, 0x22, 0x01, 0x22, 0x01, 0x22, 0x01, 0x22, 0x01, 0x22, 0x01, 0x22, 0x01, 0x22, 0x01, - 0x22, 0x01, 0x22, 0x01, 0x22, 0x01, 0x22, 0x01, 0x22, 0x01, 0x22, 0x01, 0x22, 0x01, 0x4c, 0x02, - 0x22, 0x01, 0x22, 0x01, 0x4d, 0x02, 0x22, 0x01, 0x22, 0x01, 0x22, 0x01, 0x4e, 0x02, 0x4f, 0x02, - 0x50, 0x02, 0x22, 0x01, 0x51, 0x02, 0x22, 0x01, 0x22, 0x01, 0x22, 0x01, 0x52, 0x02, 0x4c, 0x00, - 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0x53, 0x02, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0xbb, 0x01, 0x54, 0x02, - 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0x28, 0x01, 0xbb, 0x01, 0x55, 0x02, - 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x0c, 0x00, 0x56, 0x02, 0x0e, 0x00, 0x57, 0x02, 0x58, 0x02, 0x59, 0x02, 0xf8, 0x00, 0x0c, 0x00, - 0x5a, 0x02, 0x5b, 0x02, 0x5c, 0x02, 0x5d, 0x02, 0x5e, 0x02, 0x0c, 0x00, 0x56, 0x02, 0x0e, 0x00, - 0x5f, 0x02, 0x60, 0x02, 0x0e, 0x00, 0x61, 0x02, 0x62, 0x02, 0x63, 0x02, 0x64, 0x02, 0x0c, 0x00, - 0x65, 0x02, 0x0e, 0x00, 0x0c, 0x00, 0x56, 0x02, 0x0e, 0x00, 0x57, 0x02, 0x58, 0x02, 0x0e, 0x00, - 0xf8, 0x00, 0x0c, 0x00, 0x5a, 0x02, 0x64, 0x02, 0x0c, 0x00, 0x65, 0x02, 0x0e, 0x00, 0x0c, 0x00, - 0x56, 0x02, 0x0e, 0x00, 0x66, 0x02, 0x0c, 0x00, 0x67, 0x02, 0x68, 0x02, 0x69, 0x02, 0x6a, 0x02, - 0x0e, 0x00, 0x6b, 0x02, 0x0c, 0x00, 0x6c, 0x02, 0x6d, 0x02, 0x6e, 0x02, 0x6f, 0x02, 0x0e, 0x00, - 0x70, 0x02, 0x0c, 0x00, 0x71, 0x02, 0x0e, 0x00, 0x72, 0x02, 0x73, 0x02, 0x73, 0x02, 0x73, 0x02, - 0x22, 0x01, 0x22, 0x01, 0x22, 0x01, 0x22, 0x01, 0x22, 0x01, 0x22, 0x01, 0x22, 0x01, 0x22, 0x01, - 0x22, 0x01, 0x22, 0x01, 0x22, 0x01, 0x22, 0x01, 0x22, 0x01, 0x22, 0x01, 0x22, 0x01, 0x22, 0x01, - 0x22, 0x01, 0x22, 0x01, 0x22, 0x01, 0x22, 0x01, 0x22, 0x01, 0x22, 0x01, 0x22, 0x01, 0x22, 0x01, - 0x22, 0x01, 0x22, 0x01, 0x22, 0x01, 0x22, 0x01, 0x22, 0x01, 0x22, 0x01, 0x22, 0x01, 0x22, 0x01, - 0x23, 0x00, 0x23, 0x00, 0x23, 0x00, 0x74, 0x02, 0x23, 0x00, 0x23, 0x00, 0x75, 0x02, 0x76, 0x02, - 0x77, 0x02, 0x78, 0x02, 0x30, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x79, 0x02, 0x7a, 0x02, 0x7b, 0x02, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, - 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x7c, 0x02, 0x7d, 0x02, 0x4c, 0x00, 0x4c, 0x00, - 0xeb, 0x01, 0xeb, 0x01, 0x7e, 0x02, 0xed, 0x01, 0x7f, 0x02, 0x80, 0x02, 0x4c, 0x00, 0x4c, 0x00, - 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x81, 0x02, - 0x82, 0x02, 0x82, 0x02, 0x83, 0x02, 0x84, 0x02, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x85, 0x02, 0x38, 0x00, 0x86, 0x02, 0x87, 0x02, 0x88, 0x02, 0x89, 0x02, 0x8a, 0x02, 0x8b, 0x02, - 0x8c, 0x02, 0x8d, 0x02, 0x8e, 0x02, 0x8d, 0x02, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x8f, 0x02, - 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0xd6, 0x00, 0xd6, 0x00, 0x53, 0x01, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, - 0xd6, 0x00, 0x51, 0x01, 0x3f, 0x01, 0x90, 0x02, 0x90, 0x02, 0x90, 0x02, 0xd6, 0x00, 0x52, 0x01, - 0x91, 0x02, 0x22, 0x01, 0x67, 0x01, 0x22, 0x01, 0x22, 0x01, 0x22, 0x01, 0x92, 0x02, 0x22, 0x01, - 0x22, 0x01, 0x22, 0x01, 0x93, 0x02, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x94, 0x02, 0x22, 0x01, - 0x95, 0x02, 0x22, 0x01, 0x22, 0x01, 0x96, 0x02, 0x52, 0x02, 0x97, 0x02, 0x52, 0x01, 0x4c, 0x00, - 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, - 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0x98, 0x02, - 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, - 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, - 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, - 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, - 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, - 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0x99, 0x02, 0x9a, 0x02, 0xb5, 0x00, - 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0x51, 0x01, - 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0x9b, 0x02, 0x4c, 0x00, 0x4c, 0x00, - 0x53, 0x01, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0x9c, 0x02, 0xb5, 0x00, 0xd6, 0x00, 0xd6, 0x00, - 0x9c, 0x02, 0xd6, 0x00, 0x9d, 0x02, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x53, 0x01, 0xd6, 0x00, 0xd6, 0x00, 0x3f, 0x01, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, 0x9e, 0x02, - 0xd6, 0x00, 0xd6, 0x00, 0x9f, 0x02, 0xb5, 0x00, 0x9f, 0x02, 0xd6, 0x00, 0xd6, 0x00, 0xd6, 0x00, - 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x9d, 0x02, 0x4c, 0x00, - 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x49, 0x01, 0x4c, 0x00, 0x4c, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0xd2, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, - 0x51, 0x00, 0xd1, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x48, 0x02, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, - 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x51, 0x00, 0x69, 0x00, 0x4c, 0x00, - 0x51, 0x00, 0xd1, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0xa0, 0x02, 0x4c, 0x00, 0xa1, 0x02, 0xa1, 0x02, 0xa1, 0x02, 0xa1, 0x02, 0xa1, 0x02, 0xa1, 0x02, - 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, 0x4c, 0x00, - 0x23, 0x00, 0x23, 0x00, 0x23, 0x00, 0x23, 0x00, 0x23, 0x00, 0x23, 0x00, 0x23, 0x00, 0x23, 0x00, - 0x23, 0x00, 0x23, 0x00, 0x23, 0x00, 0x23, 0x00, 0x23, 0x00, 0x23, 0x00, 0x23, 0x00, 0x4c, 0x00, - 0x9b, 0x01, 0x9b, 0x01, 0x9b, 0x01, 0x9b, 0x01, 0x9b, 0x01, 0x9b, 0x01, 0x9b, 0x01, 0x9b, 0x01, - 0x9b, 0x01, 0x9b, 0x01, 0x9b, 0x01, 0x9b, 0x01, 0x9b, 0x01, 0x9b, 0x01, 0x9b, 0x01, 0x9b, 0x01, - 0x9b, 0x01, 0x9b, 0x01, 0x9b, 0x01, 0x9b, 0x01, 0x9b, 0x01, 0x9b, 0x01, 0x9b, 0x01, 0x9b, 0x01, - 0x9b, 0x01, 0x9b, 0x01, 0x9b, 0x01, 0x9b, 0x01, 0x9b, 0x01, 0x9b, 0x01, 0x9b, 0x01, 0xa2, 0x02 - }; - - private static ReadOnlySpan<byte> CategoryLevel3Index => new byte[10800] - { - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x03, 0x02, 0x04, 0x03, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x02, - 0x05, 0x06, 0x06, 0x07, 0x08, 0x07, 0x06, 0x06, 0x09, 0x0a, 0x06, 0x0b, 0x0c, 0x0d, 0x0c, 0x0c, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0c, 0x06, 0x0f, 0x0f, 0x0f, 0x06, - 0x06, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x09, 0x06, 0x0a, 0x11, 0x12, - 0x11, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x09, 0x0f, 0x0a, 0x0f, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x14, 0x06, 0x08, 0x08, 0x08, 0x08, 0x15, 0x06, 0x11, 0x15, 0x16, 0x17, 0x0f, 0x18, 0x15, 0x11, - 0x19, 0x1a, 0x1b, 0x1b, 0x11, 0x13, 0x06, 0x06, 0x11, 0x1b, 0x16, 0x1c, 0x1d, 0x1d, 0x1d, 0x06, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x0f, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x0f, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x10, 0x13, 0x10, 0x13, 0x10, 0x13, 0x10, 0x13, 0x10, 0x13, 0x10, 0x13, 0x10, 0x13, 0x10, 0x13, - 0x10, 0x13, 0x10, 0x13, 0x10, 0x13, 0x10, 0x13, 0x13, 0x10, 0x13, 0x10, 0x13, 0x10, 0x13, 0x10, - 0x13, 0x10, 0x13, 0x10, 0x13, 0x10, 0x13, 0x10, 0x13, 0x13, 0x10, 0x13, 0x10, 0x13, 0x10, 0x13, - 0x10, 0x13, 0x10, 0x13, 0x10, 0x13, 0x10, 0x13, 0x10, 0x10, 0x13, 0x10, 0x13, 0x10, 0x13, 0x13, - 0x13, 0x10, 0x10, 0x13, 0x10, 0x13, 0x10, 0x10, 0x13, 0x10, 0x10, 0x10, 0x13, 0x13, 0x10, 0x10, - 0x10, 0x10, 0x13, 0x10, 0x10, 0x13, 0x10, 0x10, 0x10, 0x13, 0x13, 0x13, 0x10, 0x10, 0x13, 0x10, - 0x10, 0x13, 0x10, 0x13, 0x10, 0x13, 0x10, 0x10, 0x13, 0x10, 0x13, 0x13, 0x10, 0x13, 0x10, 0x10, - 0x13, 0x10, 0x10, 0x10, 0x13, 0x10, 0x13, 0x10, 0x10, 0x13, 0x13, 0x16, 0x10, 0x13, 0x13, 0x13, - 0x16, 0x16, 0x16, 0x16, 0x10, 0x1e, 0x13, 0x10, 0x1e, 0x13, 0x10, 0x1e, 0x13, 0x10, 0x13, 0x10, - 0x13, 0x10, 0x13, 0x10, 0x13, 0x10, 0x13, 0x10, 0x13, 0x10, 0x13, 0x10, 0x13, 0x13, 0x10, 0x13, - 0x13, 0x10, 0x1e, 0x13, 0x10, 0x13, 0x10, 0x10, 0x10, 0x13, 0x10, 0x13, 0x10, 0x13, 0x10, 0x13, - 0x10, 0x13, 0x10, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x10, 0x10, 0x13, 0x10, 0x10, 0x13, - 0x13, 0x10, 0x13, 0x10, 0x10, 0x10, 0x10, 0x13, 0x10, 0x13, 0x10, 0x13, 0x10, 0x13, 0x10, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x16, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x20, 0x20, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, - 0x1f, 0x1f, 0x11, 0x11, 0x11, 0x11, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x1f, 0x1f, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x20, 0x11, 0x1f, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x10, 0x13, 0x10, 0x13, 0x20, 0x11, 0x10, 0x13, 0x00, 0x00, 0x1f, 0x13, 0x13, 0x13, 0x06, 0x10, - 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x10, 0x06, 0x10, 0x10, 0x10, 0x00, 0x10, 0x00, 0x10, 0x10, - 0x13, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x10, - 0x13, 0x13, 0x10, 0x10, 0x10, 0x13, 0x13, 0x13, 0x10, 0x13, 0x10, 0x13, 0x10, 0x13, 0x10, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x10, 0x13, 0x0f, 0x10, 0x13, 0x10, 0x10, 0x13, 0x13, 0x10, 0x10, 0x10, - 0x10, 0x13, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x23, 0x23, 0x10, 0x13, 0x10, 0x13, 0x10, 0x13, - 0x10, 0x10, 0x13, 0x10, 0x13, 0x10, 0x13, 0x10, 0x13, 0x10, 0x13, 0x10, 0x13, 0x10, 0x13, 0x13, - 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x1f, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x24, 0x25, 0x00, 0x00, 0x15, 0x15, 0x08, - 0x00, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x26, 0x21, - 0x27, 0x21, 0x21, 0x27, 0x21, 0x21, 0x27, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x28, - 0x28, 0x28, 0x28, 0x27, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x0f, 0x0f, 0x2a, 0x07, 0x07, 0x2b, 0x0c, 0x2c, 0x15, 0x15, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x2c, 0x2d, 0x00, 0x2c, 0x2c, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2f, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x07, 0x31, 0x31, 0x2c, 0x2e, 0x2e, - 0x21, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2c, 0x2e, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x29, 0x15, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x2f, 0x2f, 0x21, 0x21, 0x15, 0x21, 0x21, 0x21, 0x21, 0x2e, 0x2e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x2e, 0x2e, 0x2e, 0x32, 0x32, 0x2e, - 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x00, 0x2d, - 0x2e, 0x21, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x00, 0x00, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x34, 0x34, 0x15, 0x06, 0x06, 0x06, 0x34, 0x00, 0x00, 0x21, 0x35, 0x35, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x21, 0x21, 0x21, 0x21, 0x34, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x34, 0x21, 0x21, 0x21, 0x34, 0x21, 0x21, 0x21, 0x21, 0x21, 0x00, 0x00, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x00, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x21, 0x21, 0x21, 0x00, 0x00, 0x27, 0x00, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x00, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x29, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x36, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x21, 0x36, 0x21, 0x16, 0x36, 0x36, - 0x36, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x36, 0x36, 0x36, 0x36, 0x21, 0x36, 0x36, - 0x16, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x21, 0x21, 0x24, 0x24, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, - 0x24, 0x1f, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x21, 0x36, 0x36, 0x00, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x00, 0x00, 0x16, - 0x16, 0x00, 0x00, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x00, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x00, 0x16, 0x00, 0x00, 0x00, 0x16, 0x16, 0x16, 0x16, 0x00, 0x00, 0x21, 0x16, 0x36, 0x36, - 0x36, 0x21, 0x21, 0x21, 0x21, 0x00, 0x00, 0x36, 0x36, 0x00, 0x00, 0x36, 0x36, 0x21, 0x16, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0x16, 0x16, 0x00, 0x16, - 0x16, 0x16, 0x21, 0x21, 0x00, 0x00, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, - 0x16, 0x16, 0x08, 0x08, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x22, 0x08, 0x16, 0x24, 0x21, 0x00, - 0x00, 0x21, 0x21, 0x36, 0x00, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x00, 0x00, 0x00, 0x00, 0x16, - 0x16, 0x00, 0x16, 0x16, 0x00, 0x16, 0x16, 0x00, 0x16, 0x16, 0x00, 0x00, 0x21, 0x00, 0x36, 0x36, - 0x36, 0x21, 0x21, 0x00, 0x00, 0x00, 0x00, 0x21, 0x21, 0x00, 0x00, 0x21, 0x21, 0x21, 0x00, 0x00, - 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x16, 0x16, 0x16, 0x00, 0x16, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, - 0x21, 0x21, 0x16, 0x16, 0x16, 0x21, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x21, 0x21, 0x36, 0x00, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x00, 0x16, - 0x16, 0x16, 0x00, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x00, 0x16, 0x16, 0x00, 0x16, 0x16, 0x16, 0x16, 0x16, 0x00, 0x00, 0x21, 0x16, 0x36, 0x36, - 0x36, 0x21, 0x21, 0x21, 0x21, 0x21, 0x00, 0x21, 0x21, 0x36, 0x00, 0x36, 0x36, 0x21, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x24, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x00, 0x21, 0x36, 0x36, 0x00, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x00, 0x00, 0x16, - 0x16, 0x00, 0x16, 0x16, 0x00, 0x16, 0x16, 0x16, 0x16, 0x16, 0x00, 0x00, 0x21, 0x16, 0x36, 0x21, - 0x36, 0x21, 0x21, 0x21, 0x21, 0x00, 0x00, 0x36, 0x36, 0x00, 0x00, 0x36, 0x36, 0x21, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x36, 0x00, 0x00, 0x00, 0x00, 0x16, 0x16, 0x00, 0x16, - 0x22, 0x16, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x21, 0x16, 0x00, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x00, 0x00, 0x00, 0x16, 0x16, - 0x16, 0x00, 0x16, 0x16, 0x16, 0x16, 0x00, 0x00, 0x00, 0x16, 0x16, 0x00, 0x16, 0x00, 0x16, 0x16, - 0x00, 0x00, 0x00, 0x16, 0x16, 0x00, 0x00, 0x00, 0x16, 0x16, 0x16, 0x00, 0x00, 0x00, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, - 0x21, 0x36, 0x36, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x00, 0x36, 0x36, 0x36, 0x21, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x38, 0x38, 0x38, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x08, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x21, 0x36, 0x36, 0x36, 0x21, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x00, 0x16, 0x16, - 0x16, 0x00, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x00, 0x00, 0x00, 0x16, 0x21, 0x21, - 0x21, 0x36, 0x36, 0x36, 0x36, 0x00, 0x21, 0x21, 0x21, 0x00, 0x21, 0x21, 0x21, 0x21, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x21, 0x00, 0x16, 0x16, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x22, - 0x16, 0x21, 0x36, 0x36, 0x24, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x00, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x00, 0x16, 0x16, 0x16, 0x16, 0x16, 0x00, 0x00, 0x21, 0x16, 0x36, 0x39, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x00, 0x39, 0x36, 0x36, 0x00, 0x36, 0x36, 0x21, 0x21, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, - 0x00, 0x16, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x21, 0x21, 0x36, 0x36, 0x00, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x00, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x21, 0x21, 0x16, 0x36, 0x36, - 0x36, 0x21, 0x21, 0x21, 0x21, 0x00, 0x36, 0x36, 0x36, 0x00, 0x36, 0x36, 0x36, 0x21, 0x16, 0x22, - 0x00, 0x00, 0x00, 0x00, 0x16, 0x16, 0x16, 0x36, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x16, - 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x22, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x00, 0x00, 0x36, 0x36, 0x00, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x00, 0x00, 0x00, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x00, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x00, 0x16, 0x00, 0x00, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x36, - 0x36, 0x36, 0x21, 0x21, 0x21, 0x00, 0x21, 0x00, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x00, 0x00, 0x36, 0x36, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x21, 0x16, 0x16, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x00, 0x00, 0x00, 0x00, 0x08, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x1f, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x24, - 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x24, 0x24, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x16, 0x16, 0x00, 0x16, 0x00, 0x00, 0x16, 0x16, 0x00, 0x16, 0x00, 0x00, 0x16, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x16, 0x16, 0x16, 0x16, 0x00, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x00, 0x16, 0x16, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x00, 0x16, 0x16, 0x00, 0x16, 0x16, 0x16, - 0x16, 0x21, 0x16, 0x16, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x00, 0x21, 0x21, 0x16, 0x00, 0x00, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x00, 0x1f, 0x00, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x00, 0x00, - 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x00, 0x00, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x22, 0x22, 0x22, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x22, 0x24, 0x22, 0x22, 0x22, 0x21, 0x21, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, - 0x38, 0x38, 0x38, 0x38, 0x22, 0x21, 0x22, 0x21, 0x22, 0x21, 0x09, 0x0a, 0x09, 0x0a, 0x36, 0x36, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x00, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x00, 0x00, 0x00, - 0x00, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x36, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x24, 0x21, 0x21, 0x16, 0x16, 0x16, 0x16, 0x16, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x00, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x00, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x21, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x00, 0x22, 0x22, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x22, 0x22, 0x22, 0x22, 0x24, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x36, 0x36, 0x21, 0x21, 0x21, - 0x21, 0x36, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x36, 0x21, 0x21, 0x36, 0x36, 0x21, 0x21, 0x16, - 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x36, 0x36, 0x21, 0x21, 0x16, 0x16, 0x16, 0x16, 0x21, 0x21, - 0x21, 0x16, 0x36, 0x36, 0x36, 0x16, 0x16, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x16, 0x16, - 0x16, 0x21, 0x21, 0x21, 0x21, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x21, 0x36, 0x36, 0x21, 0x21, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x21, 0x16, 0x36, - 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x36, 0x36, 0x36, 0x21, 0x22, 0x22, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x24, 0x1f, 0x13, 0x13, 0x13, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x00, 0x16, 0x16, 0x16, 0x16, 0x00, 0x00, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x00, 0x16, 0x00, 0x16, 0x16, 0x16, 0x16, 0x00, 0x00, - 0x16, 0x00, 0x16, 0x16, 0x16, 0x16, 0x00, 0x00, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x00, - 0x16, 0x00, 0x16, 0x16, 0x16, 0x16, 0x00, 0x00, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x00, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x00, 0x00, 0x21, 0x21, 0x21, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, - 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x00, 0x00, 0x00, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x00, 0x00, - 0x25, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x24, 0x24, 0x16, - 0x05, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x09, 0x0a, 0x00, 0x00, 0x00, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x24, 0x24, 0x24, 0x3a, 0x3a, - 0x3a, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x00, 0x16, 0x16, - 0x16, 0x16, 0x21, 0x21, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x16, 0x16, 0x21, 0x21, 0x21, 0x24, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x16, 0x16, 0x21, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x21, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x16, 0x16, 0x16, 0x16, 0x21, 0x21, 0x36, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x21, 0x36, 0x36, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x24, 0x24, 0x24, 0x1f, 0x24, 0x24, 0x24, 0x08, 0x16, 0x21, 0x00, 0x00, - 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x25, 0x06, 0x06, 0x06, 0x06, 0x21, 0x21, 0x21, 0x18, 0x00, - 0x16, 0x16, 0x16, 0x1f, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x21, 0x21, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x21, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x00, - 0x21, 0x21, 0x21, 0x36, 0x36, 0x36, 0x36, 0x21, 0x21, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, - 0x36, 0x36, 0x21, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x21, 0x21, 0x21, 0x00, 0x00, 0x00, 0x00, - 0x15, 0x00, 0x00, 0x00, 0x06, 0x06, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x00, 0x00, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x00, 0x00, 0x00, 0x00, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x38, 0x00, 0x00, 0x00, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x21, 0x21, 0x36, 0x36, 0x21, 0x00, 0x00, 0x24, 0x24, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x36, 0x21, 0x36, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x00, - 0x21, 0x36, 0x21, 0x36, 0x36, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x00, 0x00, 0x21, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x1f, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x00, 0x00, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x23, 0x00, - 0x21, 0x21, 0x21, 0x21, 0x36, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x21, 0x36, 0x21, 0x21, 0x21, 0x21, 0x21, 0x36, 0x21, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x21, 0x36, 0x36, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x00, 0x00, 0x00, 0x00, - 0x24, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, - 0x21, 0x21, 0x36, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x36, 0x21, 0x21, 0x21, 0x21, 0x36, 0x36, 0x21, 0x21, 0x36, 0x21, 0x21, 0x21, 0x16, 0x16, - 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x21, 0x36, 0x21, 0x21, 0x36, 0x36, 0x36, 0x21, 0x36, 0x21, - 0x21, 0x21, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x24, 0x24, 0x24, - 0x16, 0x16, 0x16, 0x16, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x36, 0x36, 0x21, 0x21, 0x00, 0x00, 0x00, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x00, 0x00, 0x00, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x24, 0x24, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x10, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x21, 0x21, 0x21, 0x24, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x36, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x16, 0x16, 0x16, 0x16, 0x21, 0x16, 0x16, - 0x16, 0x16, 0x36, 0x36, 0x21, 0x16, 0x16, 0x36, 0x21, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x1f, 0x1f, 0x1f, 0x1f, - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x1f, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x00, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x10, 0x13, 0x10, 0x13, 0x10, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x10, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x00, 0x00, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x00, 0x13, 0x13, 0x10, 0x10, 0x10, 0x10, 0x1e, 0x11, 0x13, 0x11, - 0x11, 0x11, 0x13, 0x13, 0x13, 0x00, 0x13, 0x13, 0x10, 0x10, 0x10, 0x10, 0x1e, 0x11, 0x11, 0x11, - 0x13, 0x13, 0x13, 0x13, 0x00, 0x00, 0x13, 0x13, 0x10, 0x10, 0x10, 0x10, 0x00, 0x11, 0x11, 0x11, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x10, 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, - 0x00, 0x00, 0x13, 0x13, 0x13, 0x00, 0x13, 0x13, 0x10, 0x10, 0x10, 0x10, 0x1e, 0x11, 0x11, 0x00, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x18, 0x18, 0x18, 0x3b, 0x3c, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x06, 0x06, 0x17, 0x1c, 0x09, 0x17, 0x17, 0x1c, 0x09, 0x17, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x14, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x06, 0x06, 0x06, 0x17, 0x1c, 0x06, 0x06, 0x06, 0x06, 0x12, - 0x12, 0x06, 0x06, 0x06, 0x44, 0x09, 0x0a, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x0f, 0x06, 0x12, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x05, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x45, 0x46, 0x47, 0x48, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x1b, 0x1f, 0x00, 0x00, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x0b, 0x0b, 0x0f, 0x09, 0x0a, 0x1f, - 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x0b, 0x0b, 0x0f, 0x09, 0x0a, 0x00, - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x00, 0x00, 0x00, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x23, 0x23, 0x23, - 0x23, 0x21, 0x23, 0x23, 0x23, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x15, 0x15, 0x10, 0x15, 0x15, 0x15, 0x15, 0x10, 0x15, 0x15, 0x13, 0x10, 0x10, 0x10, 0x13, 0x13, - 0x10, 0x10, 0x10, 0x13, 0x15, 0x10, 0x15, 0x15, 0x0f, 0x10, 0x10, 0x10, 0x10, 0x10, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x10, 0x15, 0x10, 0x15, 0x10, 0x15, 0x10, 0x10, 0x10, 0x10, 0x19, 0x13, - 0x10, 0x10, 0x10, 0x10, 0x13, 0x16, 0x16, 0x16, 0x16, 0x13, 0x15, 0x15, 0x13, 0x13, 0x10, 0x10, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x10, 0x13, 0x13, 0x13, 0x13, 0x15, 0x0f, 0x15, 0x15, 0x13, 0x22, - 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, - 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, - 0x3a, 0x3a, 0x3a, 0x10, 0x13, 0x3a, 0x3a, 0x3a, 0x3a, 0x1d, 0x15, 0x15, 0x00, 0x00, 0x00, 0x00, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x15, 0x15, 0x15, 0x15, 0x15, 0x0f, 0x0f, 0x15, 0x15, 0x15, 0x15, - 0x0f, 0x15, 0x15, 0x0f, 0x15, 0x15, 0x0f, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x0f, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x0f, 0x0f, - 0x15, 0x15, 0x0f, 0x15, 0x0f, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0b, 0x1a, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x09, 0x0a, 0x09, 0x0a, 0x15, 0x15, 0x15, 0x15, - 0x0f, 0x0f, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x09, 0x0a, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x15, 0x0f, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x22, 0x15, 0x15, 0x15, 0x15, 0x15, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, - 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x0f, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x0f, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x0f, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x22, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x09, 0x0a, 0x09, 0x0a, 0x09, 0x0a, 0x09, 0x0a, - 0x09, 0x0a, 0x09, 0x0a, 0x09, 0x0a, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, - 0x1d, 0x1d, 0x1d, 0x1d, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x09, 0x0a, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x09, 0x0a, 0x09, 0x0a, 0x09, 0x0a, 0x09, 0x0a, 0x09, 0x0a, - 0x0f, 0x0f, 0x0f, 0x09, 0x0a, 0x09, 0x0a, 0x09, 0x0a, 0x09, 0x0a, 0x09, 0x0a, 0x09, 0x0a, 0x09, - 0x0a, 0x09, 0x0a, 0x09, 0x0a, 0x09, 0x0a, 0x09, 0x0a, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x09, 0x0a, 0x09, 0x0a, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x09, 0x0a, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x15, 0x15, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x00, 0x00, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x00, 0x00, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x00, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x00, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x00, - 0x10, 0x13, 0x10, 0x10, 0x10, 0x13, 0x13, 0x10, 0x13, 0x10, 0x13, 0x10, 0x13, 0x10, 0x10, 0x10, - 0x10, 0x13, 0x10, 0x13, 0x13, 0x10, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x1f, 0x1f, 0x10, 0x10, - 0x10, 0x13, 0x10, 0x13, 0x13, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x10, 0x13, 0x10, 0x13, 0x21, - 0x21, 0x21, 0x10, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x1d, 0x06, 0x06, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, - 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x00, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x00, - 0x06, 0x06, 0x17, 0x1c, 0x17, 0x1c, 0x06, 0x06, 0x06, 0x17, 0x1c, 0x06, 0x17, 0x1c, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x25, 0x06, 0x06, 0x25, 0x06, 0x17, 0x1c, 0x06, 0x06, - 0x17, 0x1c, 0x09, 0x0a, 0x09, 0x0a, 0x09, 0x0a, 0x09, 0x0a, 0x06, 0x06, 0x06, 0x06, 0x06, 0x20, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x25, 0x25, 0x06, 0x06, 0x06, 0x06, - 0x25, 0x06, 0x09, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x00, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x00, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x00, 0x00, 0x00, 0x00, - 0x05, 0x06, 0x06, 0x06, 0x15, 0x1f, 0x16, 0x3a, 0x09, 0x0a, 0x09, 0x0a, 0x09, 0x0a, 0x09, 0x0a, - 0x09, 0x0a, 0x15, 0x15, 0x09, 0x0a, 0x09, 0x0a, 0x09, 0x0a, 0x09, 0x0a, 0x25, 0x09, 0x0a, 0x0a, - 0x15, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x21, 0x21, 0x21, 0x21, 0x36, 0x36, - 0x25, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x15, 0x15, 0x3a, 0x3a, 0x3a, 0x1f, 0x16, 0x06, 0x15, 0x15, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x00, 0x00, 0x21, 0x21, 0x11, 0x11, 0x1f, 0x1f, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x06, 0x1f, 0x1f, 0x1f, 0x16, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x22, 0x22, 0x38, 0x38, 0x38, 0x38, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x15, 0x15, 0x00, - 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, - 0x15, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x15, 0x15, 0x15, 0x22, - 0x22, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x15, 0x15, 0x15, 0x15, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x00, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x15, 0x15, 0x15, 0x15, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x15, 0x15, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x15, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x1f, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x1f, 0x06, 0x06, 0x06, - 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x16, 0x16, 0x00, 0x00, 0x00, 0x00, - 0x10, 0x13, 0x10, 0x13, 0x10, 0x13, 0x10, 0x13, 0x10, 0x13, 0x10, 0x13, 0x10, 0x13, 0x16, 0x21, - 0x23, 0x23, 0x23, 0x06, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x06, 0x20, - 0x10, 0x13, 0x10, 0x13, 0x10, 0x13, 0x10, 0x13, 0x10, 0x13, 0x10, 0x13, 0x1f, 0x1f, 0x21, 0x21, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, - 0x21, 0x21, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x11, 0x11, 0x10, 0x13, 0x10, 0x13, 0x10, 0x13, 0x10, 0x13, 0x10, 0x13, 0x10, 0x13, 0x10, 0x13, - 0x13, 0x13, 0x10, 0x13, 0x10, 0x13, 0x10, 0x13, 0x10, 0x13, 0x10, 0x13, 0x10, 0x13, 0x10, 0x13, - 0x1f, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x10, 0x13, 0x10, 0x13, 0x10, 0x10, 0x13, - 0x10, 0x13, 0x10, 0x13, 0x10, 0x13, 0x10, 0x13, 0x20, 0x49, 0x49, 0x10, 0x13, 0x10, 0x13, 0x16, - 0x10, 0x13, 0x10, 0x13, 0x13, 0x13, 0x10, 0x13, 0x10, 0x13, 0x10, 0x13, 0x10, 0x13, 0x10, 0x13, - 0x10, 0x13, 0x10, 0x13, 0x10, 0x13, 0x10, 0x13, 0x10, 0x13, 0x10, 0x10, 0x10, 0x10, 0x10, 0x13, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x13, 0x10, 0x13, 0x10, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x1f, 0x1f, 0x13, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x21, 0x16, 0x16, 0x16, 0x21, 0x16, 0x16, 0x16, 0x16, 0x21, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x36, 0x36, 0x21, 0x21, 0x36, 0x15, 0x15, 0x15, 0x15, 0x00, 0x00, 0x00, 0x00, - 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x22, 0x22, 0x08, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x16, 0x16, 0x16, 0x16, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x36, 0x36, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x21, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x24, - 0x21, 0x21, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x24, 0x24, 0x24, 0x16, 0x24, 0x16, 0x16, 0x21, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x24, 0x24, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, - 0x16, 0x16, 0x16, 0x21, 0x36, 0x36, 0x21, 0x21, 0x21, 0x21, 0x36, 0x36, 0x21, 0x36, 0x36, 0x36, - 0x36, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x00, 0x1f, - 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x00, 0x00, 0x00, 0x00, 0x24, 0x24, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x21, 0x1f, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x16, 0x16, 0x16, 0x16, 0x16, 0x00, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x36, - 0x36, 0x21, 0x21, 0x36, 0x36, 0x21, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x16, 0x16, 0x16, 0x21, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x21, 0x36, 0x00, 0x00, - 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x00, 0x00, 0x24, 0x24, 0x24, 0x24, - 0x1f, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x22, 0x22, 0x22, 0x16, 0x36, 0x21, 0x36, 0x16, 0x16, - 0x21, 0x16, 0x21, 0x21, 0x21, 0x16, 0x16, 0x21, 0x21, 0x16, 0x16, 0x16, 0x16, 0x16, 0x21, 0x21, - 0x16, 0x21, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x16, 0x1f, 0x24, 0x24, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x36, 0x21, 0x21, 0x36, 0x36, - 0x24, 0x24, 0x16, 0x1f, 0x1f, 0x36, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x00, 0x00, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x00, - 0x00, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x49, 0x1f, 0x1f, 0x1f, 0x1f, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x16, 0x16, 0x16, 0x36, 0x36, 0x21, 0x36, 0x36, 0x21, 0x36, 0x36, 0x24, 0x36, 0x21, 0x00, 0x00, - 0x16, 0x16, 0x16, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x00, 0x00, 0x00, 0x00, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, - 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x13, 0x13, 0x13, 0x13, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x21, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x0b, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x00, 0x28, 0x28, 0x28, 0x28, 0x28, 0x00, 0x28, 0x00, - 0x28, 0x28, 0x00, 0x28, 0x28, 0x00, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x2e, 0x2e, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, - 0x4c, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x0a, 0x09, - 0x00, 0x00, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2b, 0x15, 0x00, 0x00, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x09, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x06, 0x25, 0x25, 0x12, 0x12, 0x09, 0x0a, 0x09, 0x0a, 0x09, 0x0a, 0x09, 0x0a, 0x09, 0x0a, 0x09, - 0x0a, 0x09, 0x0a, 0x09, 0x0a, 0x06, 0x06, 0x09, 0x0a, 0x06, 0x06, 0x06, 0x06, 0x12, 0x12, 0x12, - 0x0c, 0x06, 0x0c, 0x00, 0x06, 0x0c, 0x06, 0x06, 0x25, 0x09, 0x0a, 0x09, 0x0a, 0x09, 0x0a, 0x07, - 0x06, 0x06, 0x0b, 0x0d, 0x0f, 0x0f, 0x0f, 0x00, 0x06, 0x08, 0x07, 0x06, 0x00, 0x00, 0x00, 0x00, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x00, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x00, 0x00, 0x18, - 0x00, 0x06, 0x06, 0x07, 0x08, 0x07, 0x06, 0x06, 0x09, 0x0a, 0x06, 0x0b, 0x0c, 0x0d, 0x0c, 0x0c, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x09, 0x0f, 0x0a, 0x0f, 0x09, - 0x0a, 0x06, 0x09, 0x0a, 0x06, 0x06, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x1f, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x1f, 0x1f, - 0x00, 0x00, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x00, 0x00, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x00, 0x00, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x00, 0x00, 0x16, 0x16, 0x16, 0x00, 0x00, 0x00, - 0x08, 0x08, 0x0f, 0x11, 0x15, 0x08, 0x08, 0x00, 0x15, 0x0f, 0x0f, 0x0f, 0x0f, 0x15, 0x15, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4d, 0x4d, 0x4d, 0x15, 0x15, 0x00, 0x00, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x00, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x00, 0x16, 0x16, 0x00, 0x16, - 0x24, 0x06, 0x24, 0x00, 0x00, 0x00, 0x00, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, - 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, - 0x38, 0x38, 0x38, 0x38, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, - 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x1d, 0x1d, 0x1d, 0x1d, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x1d, 0x1d, 0x15, 0x22, 0x22, 0x00, - 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x21, 0x00, 0x00, - 0x21, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, - 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00, - 0x38, 0x38, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x16, 0x16, - 0x16, 0x3a, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x21, 0x21, 0x21, 0x21, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x00, 0x24, - 0x16, 0x16, 0x16, 0x16, 0x00, 0x00, 0x00, 0x00, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x24, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x00, 0x00, 0x00, 0x00, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x16, 0x16, 0x16, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x00, 0x00, 0x28, 0x00, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x00, 0x28, 0x28, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x00, 0x27, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x50, 0x50, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, - 0x28, 0x28, 0x28, 0x00, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x00, 0x00, 0x00, 0x06, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x4f, 0x28, 0x28, - 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, - 0x00, 0x00, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, - 0x28, 0x21, 0x21, 0x21, 0x00, 0x21, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x21, 0x21, 0x21, - 0x28, 0x28, 0x28, 0x28, 0x00, 0x28, 0x28, 0x28, 0x00, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x00, 0x00, 0x21, 0x21, 0x21, 0x00, 0x00, 0x00, 0x00, 0x21, - 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x4f, 0x4f, 0x27, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x4f, 0x4f, 0x4f, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x50, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x21, 0x21, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x00, 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x00, 0x00, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, - 0x28, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, - 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x27, 0x27, 0x27, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, - 0x51, 0x51, 0x51, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, - 0x52, 0x52, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, - 0x2e, 0x2e, 0x2e, 0x2e, 0x21, 0x21, 0x21, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, - 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x00, - 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x21, 0x54, 0x54, 0x54, 0x54, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x36, 0x21, 0x36, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x00, 0x00, - 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, - 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, - 0x36, 0x36, 0x36, 0x21, 0x21, 0x21, 0x21, 0x36, 0x36, 0x21, 0x21, 0x24, 0x24, 0x3b, 0x24, 0x24, - 0x24, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, - 0x21, 0x21, 0x21, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x21, 0x21, 0x21, 0x21, 0x21, 0x36, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x00, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, - 0x24, 0x24, 0x24, 0x24, 0x16, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x16, 0x16, 0x16, 0x21, 0x24, 0x24, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x16, 0x16, 0x16, 0x36, 0x36, 0x36, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x36, - 0x36, 0x16, 0x16, 0x16, 0x16, 0x24, 0x24, 0x24, 0x24, 0x21, 0x21, 0x21, 0x21, 0x24, 0x00, 0x00, - 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x16, 0x24, 0x16, 0x24, 0x24, 0x24, - 0x00, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, - 0x38, 0x38, 0x38, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x36, 0x36, 0x36, 0x21, - 0x21, 0x21, 0x36, 0x36, 0x21, 0x36, 0x21, 0x21, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x21, 0x00, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x00, 0x16, 0x00, 0x16, 0x16, 0x16, 0x16, 0x00, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x00, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x21, - 0x36, 0x36, 0x36, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x21, 0x21, 0x36, 0x36, 0x00, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x00, 0x00, 0x16, - 0x16, 0x00, 0x16, 0x16, 0x00, 0x16, 0x16, 0x16, 0x16, 0x16, 0x00, 0x21, 0x21, 0x16, 0x36, 0x36, - 0x21, 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x36, 0x36, 0x00, 0x00, 0x36, 0x36, 0x36, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x36, 0x36, 0x00, 0x00, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x00, 0x00, 0x00, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x36, 0x36, 0x36, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x36, 0x36, 0x21, 0x21, 0x21, 0x36, 0x21, 0x16, 0x16, 0x16, 0x16, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x00, 0x24, 0x00, 0x24, 0x21, 0x00, - 0x36, 0x36, 0x36, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x36, 0x21, 0x36, 0x36, 0x36, 0x36, 0x21, - 0x21, 0x36, 0x21, 0x21, 0x16, 0x16, 0x24, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x36, - 0x36, 0x36, 0x21, 0x21, 0x21, 0x21, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0x21, 0x21, 0x36, 0x21, - 0x21, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x16, 0x16, 0x16, 0x16, 0x21, 0x21, 0x00, 0x00, - 0x36, 0x36, 0x36, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x36, 0x36, 0x21, 0x36, 0x21, - 0x21, 0x24, 0x24, 0x24, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x21, 0x36, 0x21, 0x36, 0x36, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x36, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x36, 0x36, 0x21, 0x21, 0x21, 0x21, 0x36, 0x21, 0x21, 0x21, 0x21, 0x21, 0x00, 0x00, 0x00, 0x00, - 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x38, 0x38, 0x24, 0x24, 0x24, 0x22, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x36, 0x21, 0x21, 0x24, 0x00, 0x00, 0x00, 0x00, - 0x38, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, - 0x16, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x39, 0x39, 0x21, 0x21, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x36, 0x16, 0x21, 0x21, 0x21, 0x21, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x16, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x36, 0x36, 0x21, 0x21, 0x21, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x00, 0x00, 0x16, 0x16, 0x16, 0x16, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x36, 0x21, 0x21, 0x24, 0x24, 0x24, 0x16, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x00, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x36, 0x39, - 0x16, 0x24, 0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x24, 0x24, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x00, 0x00, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x00, 0x36, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x36, 0x21, 0x21, 0x36, 0x21, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x00, 0x16, 0x16, 0x00, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x00, 0x00, 0x00, 0x21, 0x00, 0x21, 0x21, 0x00, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x16, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x00, 0x16, 0x16, 0x00, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x36, 0x36, 0x36, 0x36, 0x36, 0x00, - 0x21, 0x21, 0x00, 0x36, 0x36, 0x21, 0x36, 0x21, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x16, 0x16, 0x16, 0x21, 0x21, 0x36, 0x36, 0x24, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x00, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x24, 0x24, 0x24, 0x24, 0x24, 0x22, 0x22, 0x22, 0x22, - 0x1f, 0x1f, 0x1f, 0x1f, 0x24, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x00, 0x38, 0x38, 0x38, 0x38, 0x38, - 0x38, 0x38, 0x00, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x16, 0x16, - 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x16, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x00, - 0x21, 0x21, 0x21, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, - 0x1f, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x16, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x16, 0x16, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x00, 0x00, 0x22, 0x21, 0x21, 0x24, - 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x36, 0x36, 0x21, 0x21, 0x21, 0x22, 0x22, 0x22, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x22, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x21, 0x21, 0x21, 0x21, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x15, 0x15, 0x21, 0x21, 0x21, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x38, 0x38, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x00, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x10, 0x10, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x10, 0x00, 0x10, 0x10, - 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x13, 0x13, 0x13, 0x13, 0x00, 0x13, 0x00, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x00, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x00, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x55, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x0f, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x55, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x0f, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x55, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x0f, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x55, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x0f, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x55, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x0f, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x10, 0x13, 0x00, 0x00, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x22, 0x22, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x21, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x21, 0x22, 0x22, 0x24, 0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x00, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x00, 0x00, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x00, 0x21, 0x21, 0x00, 0x21, 0x21, 0x21, 0x21, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x00, 0x00, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x51, 0x51, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, - 0x52, 0x52, 0x52, 0x52, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x00, 0x00, 0x00, 0x00, 0x27, 0x27, - 0x00, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, - 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, - 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x32, 0x54, 0x54, 0x54, - 0x2b, 0x54, 0x54, 0x54, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x2e, 0x2e, 0x2e, 0x2e, 0x00, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x00, 0x2e, 0x2e, 0x00, 0x2e, 0x00, 0x00, 0x2e, 0x00, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x00, 0x2e, 0x2e, 0x2e, 0x2e, 0x00, 0x2e, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x2e, 0x00, 0x2e, 0x00, 0x2e, 0x2e, 0x2e, - 0x00, 0x2e, 0x2e, 0x00, 0x2e, 0x00, 0x00, 0x2e, 0x00, 0x2e, 0x00, 0x2e, 0x00, 0x2e, 0x00, 0x2e, - 0x00, 0x2e, 0x2e, 0x00, 0x2e, 0x00, 0x00, 0x2e, 0x2e, 0x2e, 0x2e, 0x00, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x00, 0x2e, 0x2e, 0x2e, 0x2e, 0x00, 0x2e, 0x2e, 0x2e, 0x2e, 0x00, 0x2e, 0x00, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x00, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x2e, 0x2e, 0x2e, 0x00, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x00, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1d, 0x1d, 0x00, 0x00, 0x00, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x15, 0x15, 0x00, 0x00, 0x00, 0x00, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, - 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x00, 0x00, 0x00, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x00, 0x00, - 0x15, 0x00, 0x00, 0x15, 0x15, 0x15, 0x15, 0x00, 0x00, 0x00, 0x15, 0x00, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x00, 0x00 - }; - - private static ReadOnlySpan<byte> CategoriesValue => new byte[172] - { - 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, 0x1a, 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, 0x0a, 0x04, 0x19, 0x00 - }; - - // 12:4:4 index table of the Unicode numeric data. - private static ReadOnlySpan<byte> NumericLevel1Index => new byte[761] - { - 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x03, 0x01, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, - 0x0b, 0x01, 0x01, 0x0c, 0x01, 0x01, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x01, 0x01, 0x01, - 0x14, 0x15, 0x01, 0x01, 0x16, 0x01, 0x01, 0x17, 0x01, 0x01, 0x01, 0x01, 0x18, 0x01, 0x01, 0x01, - 0x19, 0x1a, 0x1b, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x1c, 0x01, 0x1d, 0x1e, 0x1f, 0x20, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x21, 0x01, 0x01, 0x01, 0x01, 0x01, 0x0f, - 0x01, 0x22, 0x23, 0x24, 0x25, 0x01, 0x01, 0x01, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, - 0x2e, 0x2f, 0x20, 0x01, 0x09, 0x01, 0x30, 0x31, 0x32, 0x01, 0x01, 0x01, 0x33, 0x34, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x35, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x36, 0x37, 0x01, 0x01, 0x38, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x39, 0x3a, 0x01, 0x01, 0x01, 0x3b, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x3c, 0x1f, 0x01, 0x01, 0x3d, 0x01, 0x01, 0x01, - 0x01, 0x3e, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x3f - }; - - private static ReadOnlySpan<byte> NumericLevel2Index => new byte[1024] - { - 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x04, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x06, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x03, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x0a, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x0f, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x10, - 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x15, 0x15, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x18, 0x19, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x1c, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1e, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, - 0x21, 0x00, 0x22, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x25, 0x00, 0x26, 0x27, 0x00, 0x00, 0x25, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x00, - 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x2c, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x2e, 0x00, 0x2f, - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x3a, - 0x00, 0x00, 0x3b, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3f, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x41, - 0x00, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x44, 0x45, 0x46, 0x47, - 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x49, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x00, 0x41, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x4b, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4d, - 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x50, 0x51, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x39, 0x55, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, 0x58, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x66, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x69, 0x6a, 0x6b, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x6c, 0x6d, 0x6e, 0x6f, 0x00, 0x00, 0x00, 0x00, - 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }; - - private static ReadOnlySpan<byte> NumericLevel3Index => new byte[1824] - { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x0b, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x0e, 0x0f, 0x10, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, - 0x00, 0x00, 0x00, 0x00, 0x11, 0x12, 0x13, 0x0e, 0x10, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x15, 0x16, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x19, 0x1a, 0x1b, 0x19, 0x1a, 0x1b, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x00, - 0x15, 0x16, 0x17, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0f, 0x23, 0x24, 0x25, 0x26, 0x27, - 0x28, 0x29, 0x2a, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x0b, 0x0c, 0x2c, 0x2d, 0x2e, 0x2f, - 0x30, 0x31, 0x15, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x16, 0x3a, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x3c, - 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x18, 0x19, 0x1a, 0x1b, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x44, 0x00, 0x00, 0x00, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x44, 0x0d, 0x0b, 0x0c, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x45, 0x46, 0x20, 0x47, 0x48, 0x22, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x12, 0x4e, 0x4f, 0x50, 0x19, - 0x19, 0x1a, 0x1b, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x15, 0x51, 0x52, 0x35, 0x16, 0x53, 0x17, - 0x17, 0x54, 0x3a, 0x00, 0x00, 0x40, 0x35, 0x55, 0x56, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0d, 0x0b, 0x0c, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x15, 0x51, 0x52, 0x57, 0x58, 0x59, 0x14, - 0x3b, 0x3c, 0x3d, 0x32, 0x0d, 0x0b, 0x0c, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x15, 0x51, 0x52, - 0x57, 0x58, 0x59, 0x14, 0x3b, 0x3c, 0x3d, 0x32, 0x0d, 0x0b, 0x0c, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, - 0x31, 0x15, 0x51, 0x52, 0x57, 0x58, 0x59, 0x14, 0x3b, 0x3c, 0x3d, 0x32, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x51, 0x52, 0x57, 0x58, 0x59, - 0x14, 0x3b, 0x3c, 0x3d, 0x32, 0x0d, 0x0b, 0x0c, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x15, 0x44, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x0b, 0x0c, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x15, - 0x0d, 0x0b, 0x0c, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x15, 0x0d, 0x0b, 0x0c, 0x2c, 0x2d, 0x2e, - 0x2f, 0x30, 0x31, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x19, 0x1a, 0x1b, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x32, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x19, 0x1a, 0x1b, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x19, 0x1a, 0x1b, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, - 0x00, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x33, 0x63, 0x64, 0x65, 0x66, 0x67, - 0x00, 0x68, 0x69, 0x6a, 0x6b, 0x34, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x35, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x1a, 0x1b, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x18, - 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x1a, 0x1b, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, - 0x15, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x16, 0x75, 0x76, 0x77, 0x53, 0x78, 0x79, - 0x7a, 0x7b, 0x17, 0x7c, 0x7d, 0x7e, 0x54, 0x7f, 0x80, 0x81, 0x82, 0x3a, 0x83, 0x84, 0x85, 0x55, - 0x86, 0x87, 0x88, 0x89, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0e, 0x0f, 0x19, 0x3f, 0x35, 0x53, 0x54, 0x55, 0x3f, 0x15, 0x35, 0x16, 0x53, 0x17, 0x54, 0x3f, - 0x15, 0x35, 0x16, 0x53, 0x17, 0x3a, 0x55, 0x15, 0x19, 0x19, 0x19, 0x1a, 0x1a, 0x1a, 0x1a, 0x3f, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x33, 0x35, 0x35, 0x35, 0x35, 0x16, 0x76, 0x53, 0x53, 0x53, 0x53, - 0x53, 0x17, 0x54, 0x3f, 0x35, 0x0f, 0x0f, 0x48, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x19, 0x1a, 0x1b, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x15, 0x32, 0x33, 0x34, 0x35, 0x36, - 0x37, 0x38, 0x39, 0x16, 0x75, 0x76, 0x77, 0x53, 0x78, 0x79, 0x7a, 0x7b, 0x00, 0x00, 0x00, 0x00, - 0x19, 0x3f, 0x15, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x19, 0x1a, 0x15, 0x32, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x1a, 0x1b, 0x15, 0x32, 0x16, 0x17, 0x3a, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x1a, 0x1b, 0x3e, 0x3f, 0x15, 0x32, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x1a, 0x1b, 0x3e, 0x3e, 0x3f, 0x15, 0x32, 0x16, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x3f, 0x15, 0x32, 0x16, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x15, 0x32, 0x16, 0x1a, 0x1b, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8a, 0x0f, 0x00, 0x00, - 0x19, 0x1a, 0x1b, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x15, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, - 0x00, 0x00, 0x16, 0x75, 0x76, 0x77, 0x53, 0x78, 0x79, 0x7a, 0x7b, 0x17, 0x7c, 0x7d, 0x7e, 0x54, - 0x7f, 0x80, 0x81, 0x82, 0x3a, 0x83, 0x84, 0x85, 0x55, 0x86, 0x87, 0x88, 0x89, 0x56, 0x8b, 0x8c, - 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, - 0x0d, 0x0b, 0x0c, 0x2c, 0x15, 0x32, 0x16, 0x17, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x35, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x15, 0x32, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x1a, 0x1b, 0x3e, 0x15, 0x32, 0x16, 0x17, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x1a, 0x1b, 0x3e, 0x15, 0x32, 0x16, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x3f, 0x15, 0x35, 0x16, 0x17, - 0x0d, 0x0b, 0x0c, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x15, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, - 0x38, 0x39, 0x16, 0x75, 0x76, 0x77, 0x53, 0x78, 0x79, 0x7a, 0x7b, 0x0f, 0x0e, 0x47, 0x48, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x1a, 0x1b, - 0x3e, 0x3f, 0x15, 0x32, 0x33, 0x16, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x19, 0x15, 0x32, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x0d, 0x0b, 0x0c, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x15, 0x32, 0x33, 0x34, 0x35, - 0x36, 0x37, 0x38, 0x39, 0x16, 0x17, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, - 0x37, 0x38, 0x39, 0x16, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x15, 0x32, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x15, 0x32, 0x33, 0x34, 0x35, 0x36, - 0x37, 0x38, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x19, 0x1a, 0x1b, 0x3e, 0x3f, 0x40, - 0x41, 0x42, 0x43, 0x15, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x16, 0x00, 0x00, 0x00, - 0x1a, 0x1b, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x1b, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x3e, - 0x3f, 0x40, 0x41, 0x42, 0x43, 0x19, 0x1a, 0x1b, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x19, 0x1a, - 0x1b, 0x3e, 0x3f, 0x1a, 0x1b, 0x1b, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x19, 0x1a, 0x1b, 0x1b, - 0x3e, 0x3f, 0x9d, 0x9e, 0x19, 0x1a, 0x1b, 0x1b, 0x3e, 0x3f, 0x1b, 0x1b, 0x3e, 0x3e, 0x3e, 0x3e, - 0x40, 0x41, 0x41, 0x41, 0x42, 0x42, 0x43, 0x43, 0x43, 0x43, 0x1a, 0x1b, 0x3e, 0x3f, 0x40, 0x19, - 0x1a, 0x1b, 0x3e, 0x3e, 0x3f, 0x3f, 0x1a, 0x1b, 0x19, 0x1a, 0x47, 0x48, 0x4d, 0x47, 0x48, 0x12, - 0x0e, 0x4c, 0x0e, 0x0e, 0x0f, 0x47, 0x48, 0x34, 0x35, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x00, - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x00, 0x15, 0x16, 0x3a, 0x9f, 0xa0, - 0xa1, 0xa2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x18, 0x19, 0x1a, 0x1b, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x15, 0x51, 0x52, 0x57, 0x58, 0x59, - 0x14, 0x3b, 0x3c, 0x3d, 0x19, 0x1a, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x14, 0x3b, 0x3c, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x38, 0x39, 0x19, 0x1a, 0x1b, 0x3e, 0x3f, 0x19, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, - 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, - 0x09, 0x0a, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x01, 0x02, 0x03, 0x04, - 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, - 0x37, 0x38, 0x39, 0x16, 0x75, 0x76, 0x77, 0x53, 0x78, 0x79, 0x7a, 0x7b, 0x17, 0x7c, 0x7d, 0x7e, - 0x54, 0x7f, 0x80, 0x81, 0x82, 0x3a, 0x83, 0x84, 0x85, 0x55, 0x86, 0x87, 0x88, 0x89, 0x56, 0x8b, - 0x56, 0xa3, 0xa4, 0x19, 0x1a, 0x1b, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x00, 0x0e, 0x0f, 0x10, - 0x00, 0x19, 0x1a, 0x3a, 0x56, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x44, 0x44, 0x0d, 0x0b, 0x0c, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x18, 0x18, 0x00, 0x00, 0x00, - 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }; - - // Every item contains the value for numeric value. - private static ReadOnlySpan<byte> NumericValues => new byte[1320] - { - 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, - 0x9a, 0x99, 0x99, 0x99, 0x99, 0x99, 0x79, 0x3f, 0x9a, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x3f, - 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0xa3, 0x3f, 0x9a, 0x99, 0x99, 0x99, 0x99, 0x99, 0xa9, 0x3f, - 0x9a, 0x99, 0x99, 0x99, 0x99, 0x99, 0xb9, 0x3f, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0xc3, 0x3f, - 0x9a, 0x99, 0x99, 0x99, 0x99, 0x99, 0xc9, 0x3f, 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, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5, 0x3f, - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xe5, 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, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x12, 0x63, 0x41, - 0x00, 0x00, 0x00, 0x00, 0xd0, 0x12, 0x73, 0x41 - }; - - private static ReadOnlySpan<byte> DigitValues => new byte[330] - { - 0xff, 0xff, 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04, 0x04, 0x05, 0x05, 0x06, 0x06, - 0x07, 0x07, 0x08, 0x08, 0x09, 0x09, 0xff, 0x02, 0xff, 0x03, 0xff, 0x01, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x04, 0xff, 0x05, 0xff, 0x06, 0xff, 0x07, - 0xff, 0x08, 0xff, 0x09, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff - }; - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/ChineseLunisolarCalendar.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/ChineseLunisolarCalendar.cs deleted file mode 100644 index 01c6133d404..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/ChineseLunisolarCalendar.cs +++ /dev/null @@ -1,302 +0,0 @@ -// 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 -{ - /// <remarks> - /// Calendar support range: - /// Calendar Minimum Maximum - /// ========== ========== ========== - /// Gregorian 1901/02/19 2101/01/28 - /// ChineseLunisolar 1901/01/01 2100/12/29 - /// </remarks> - - public class ChineseLunisolarCalendar : EastAsianLunisolarCalendar - { - public const int ChineseEra = 1; - - private const int MinLunisolarYear = 1901; - private const int MaxLunisolarYear = 2100; - - private static readonly DateTime s_minDate = new DateTime(1901, 2, 19); - private static readonly DateTime s_maxDate = new DateTime((new DateTime(2101, 1, 28, 23, 59, 59, 999)).Ticks + 9999); - - public override DateTime MinSupportedDateTime => s_minDate; - - public override DateTime MaxSupportedDateTime => s_maxDate; - - protected override int DaysInYearBeforeMinSupportedYear => - // 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 [1] - // [1] Reingold, Edward M, and Nachum Dershowitz. Calendrical Tabulations, 1900 - 2200.Cambridge: Cambridge Univ. Press, 2002.Print. - 384; - - // Data for years 1901-1905 and 1907-2100 matches output of Calendrical Calculations [2] and published calendar tables [3]. - // For 1906, month 4 of the Chinese year starts on 24 Apr 1906 and has 29 days. This is historially accurate - // but different to the values in [1] and output from [2]. This is due to a change in the astronomical methods used - // by the Chinese to calculate the calendar from 1913 onwards (see warnings in [1]). - // [2] Reingold, Edward M, and Nachum Dershowitz. Calendrical Calculations: The Ultimate Edition. Cambridge [etc.: Cambridge University Press, 2018. Print. - // [3] Wang, Jianmin. Xin Bian Wan Nian Li: (1840-2050) Chong Bian Ben. Beijing: Ke xue pu ji chu ban she, 1990. Print. - 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 */ { 00, 02, 19, 0b0100101011100000 }, /* 29 30 29 29 30 29 30 29 30 30 30 29 354 -1902 */ { 00, 02, 08, 0b1010010101110000 }, /* 30 29 30 29 29 30 29 30 29 30 30 30 355 -1903 */ { 05, 01, 29, 0b0101001001101000 }, /* 29 30 29 30 29 29 30 29 29 30 30 29 30 383 -1904 */ { 00, 02, 16, 0b1101001001100000 }, /* 30 30 29 30 29 29 30 29 29 30 30 29 354 -1905 */ { 00, 02, 04, 0b1101100101010000 }, /* 30 30 29 30 30 29 29 30 29 30 29 30 355 -1906 */ { 04, 01, 25, 0b0110101010101000 }, /* 29 30 30 29 30 29 30 29 30 29 30 29 30 384 -1907 */ { 00, 02, 13, 0b0101011010100000 }, /* 29 30 29 30 29 30 30 29 30 29 30 29 354 -1908 */ { 00, 02, 02, 0b1001101011010000 }, /* 30 29 29 30 30 29 30 29 30 30 29 30 355 -1909 */ { 02, 01, 22, 0b0100101011101000 }, /* 29 30 29 29 30 29 30 29 30 30 30 29 30 384 -1910 */ { 00, 02, 10, 0b0100101011100000 }, /* 29 30 29 29 30 29 30 29 30 30 30 29 354 -1911 */ { 06, 01, 30, 0b1010010011011000 }, /* 30 29 30 29 29 30 29 29 30 30 29 30 30 384 -1912 */ { 00, 02, 18, 0b1010010011010000 }, /* 30 29 30 29 29 30 29 29 30 30 29 30 354 -1913 */ { 00, 02, 06, 0b1101001001010000 }, /* 30 30 29 30 29 29 30 29 29 30 29 30 354 -1914 */ { 05, 01, 26, 0b1101010100101000 }, /* 30 30 29 30 29 30 29 30 29 29 30 29 30 384 -1915 */ { 00, 02, 14, 0b1011010101000000 }, /* 30 29 30 30 29 30 29 30 29 30 29 29 354 -1916 */ { 00, 02, 03, 0b1101011010100000 }, /* 30 30 29 30 29 30 30 29 30 29 30 29 355 -1917 */ { 02, 01, 23, 0b1001011011010000 }, /* 30 29 29 30 29 30 30 29 30 30 29 30 29 384 -1918 */ { 00, 02, 11, 0b1001010110110000 }, /* 30 29 29 30 29 30 29 30 30 29 30 30 355 -1919 */ { 07, 02, 01, 0b0100100110111000 }, /* 29 30 29 29 30 29 29 30 30 29 30 30 30 384 -1920 */ { 00, 02, 20, 0b0100100101110000 }, /* 29 30 29 29 30 29 29 30 29 30 30 30 354 -1921 */ { 00, 02, 08, 0b1010010010110000 }, /* 30 29 30 29 29 30 29 29 30 29 30 30 354 -1922 */ { 05, 01, 28, 0b1011001001011000 }, /* 30 29 30 30 29 29 30 29 29 30 29 30 30 384 -1923 */ { 00, 02, 16, 0b0110101001010000 }, /* 29 30 30 29 30 29 30 29 29 30 29 30 354 -1924 */ { 00, 02, 05, 0b0110110101000000 }, /* 29 30 30 29 30 30 29 30 29 30 29 29 354 -1925 */ { 04, 01, 24, 0b1010110110101000 }, /* 30 29 30 29 30 30 29 30 30 29 30 29 30 385 -1926 */ { 00, 02, 13, 0b0010101101100000 }, /* 29 29 30 29 30 29 30 30 29 30 30 29 354 -1927 */ { 00, 02, 02, 0b1001010101110000 }, /* 30 29 29 30 29 30 29 30 29 30 30 30 355 -1928 */ { 02, 01, 23, 0b0100100101111000 }, /* 29 30 29 29 30 29 29 30 29 30 30 30 30 384 -1929 */ { 00, 02, 10, 0b0100100101110000 }, /* 29 30 29 29 30 29 29 30 29 30 30 30 354 -1930 */ { 06, 01, 30, 0b0110010010110000 }, /* 29 30 30 29 29 30 29 29 30 29 30 30 29 383 -1931 */ { 00, 02, 17, 0b1101010010100000 }, /* 30 30 29 30 29 30 29 29 30 29 30 29 354 -1932 */ { 00, 02, 06, 0b1110101001010000 }, /* 30 30 30 29 30 29 30 29 29 30 29 30 355 -1933 */ { 05, 01, 26, 0b0110110101001000 }, /* 29 30 30 29 30 30 29 30 29 30 29 29 30 384 -1934 */ { 00, 02, 14, 0b0101101011010000 }, /* 29 30 29 30 30 29 30 29 30 30 29 30 355 -1935 */ { 00, 02, 04, 0b0010101101100000 }, /* 29 29 30 29 30 29 30 30 29 30 30 29 354 -1936 */ { 03, 01, 24, 0b1001001101110000 }, /* 30 29 29 30 29 29 30 30 29 30 30 30 29 384 -1937 */ { 00, 02, 11, 0b1001001011100000 }, /* 30 29 29 30 29 29 30 29 30 30 30 29 354 -1938 */ { 07, 01, 31, 0b1100100101101000 }, /* 30 30 29 29 30 29 29 30 29 30 30 29 30 384 -1939 */ { 00, 02, 19, 0b1100100101010000 }, /* 30 30 29 29 30 29 29 30 29 30 29 30 354 -1940 */ { 00, 02, 08, 0b1101010010100000 }, /* 30 30 29 30 29 30 29 29 30 29 30 29 354 -1941 */ { 06, 01, 27, 0b1101101001010000 }, /* 30 30 29 30 30 29 30 29 29 30 29 30 29 384 -1942 */ { 00, 02, 15, 0b1011010101010000 }, /* 30 29 30 30 29 30 29 30 29 30 29 30 355 -1943 */ { 00, 02, 05, 0b0101011010100000 }, /* 29 30 29 30 29 30 30 29 30 29 30 29 354 -1944 */ { 04, 01, 25, 0b1010101011011000 }, /* 30 29 30 29 30 29 30 29 30 30 29 30 30 385 -1945 */ { 00, 02, 13, 0b0010010111010000 }, /* 29 29 30 29 29 30 29 30 30 30 29 30 354 -1946 */ { 00, 02, 02, 0b1001001011010000 }, /* 30 29 29 30 29 29 30 29 30 30 29 30 354 -1947 */ { 02, 01, 22, 0b1100100101011000 }, /* 30 30 29 29 30 29 29 30 29 30 29 30 30 384 -1948 */ { 00, 02, 10, 0b1010100101010000 }, /* 30 29 30 29 30 29 29 30 29 30 29 30 354 -1949 */ { 07, 01, 29, 0b1011010010101000 }, /* 30 29 30 30 29 30 29 29 30 29 30 29 30 384 -1950 */ { 00, 02, 17, 0b0110110010100000 }, /* 29 30 30 29 30 30 29 29 30 29 30 29 354 -1951 */ { 00, 02, 06, 0b1011010101010000 }, /* 30 29 30 30 29 30 29 30 29 30 29 30 355 -1952 */ { 05, 01, 27, 0b0101010110101000 }, /* 29 30 29 30 29 30 29 30 30 29 30 29 30 384 -1953 */ { 00, 02, 14, 0b0100110110100000 }, /* 29 30 29 29 30 30 29 30 30 29 30 29 354 -1954 */ { 00, 02, 03, 0b1010010110110000 }, /* 30 29 30 29 29 30 29 30 30 29 30 30 355 -1955 */ { 03, 01, 24, 0b0101001010111000 }, /* 29 30 29 30 29 29 30 29 30 29 30 30 30 384 -1956 */ { 00, 02, 12, 0b0101001010110000 }, /* 29 30 29 30 29 29 30 29 30 29 30 30 354 -1957 */ { 08, 01, 31, 0b1010100101010000 }, /* 30 29 30 29 30 29 29 30 29 30 29 30 29 383 -1958 */ { 00, 02, 18, 0b1110100101010000 }, /* 30 30 30 29 30 29 29 30 29 30 29 30 355 -1959 */ { 00, 02, 08, 0b0110101010100000 }, /* 29 30 30 29 30 29 30 29 30 29 30 29 354 -1960 */ { 06, 01, 28, 0b1010110101010000 }, /* 30 29 30 29 30 30 29 30 29 30 29 30 29 384 -1961 */ { 00, 02, 15, 0b1010101101010000 }, /* 30 29 30 29 30 29 30 30 29 30 29 30 355 -1962 */ { 00, 02, 05, 0b0100101101100000 }, /* 29 30 29 29 30 29 30 30 29 30 30 29 354 -1963 */ { 04, 01, 25, 0b1010010101110000 }, /* 30 29 30 29 29 30 29 30 29 30 30 30 29 384 -1964 */ { 00, 02, 13, 0b1010010101110000 }, /* 30 29 30 29 29 30 29 30 29 30 30 30 355 -1965 */ { 00, 02, 02, 0b0101001001100000 }, /* 29 30 29 30 29 29 30 29 29 30 30 29 353 -1966 */ { 03, 01, 21, 0b1110100100110000 }, /* 30 30 30 29 30 29 29 30 29 29 30 30 29 384 -1967 */ { 00, 02, 09, 0b1101100101010000 }, /* 30 30 29 30 30 29 29 30 29 30 29 30 355 -1968 */ { 07, 01, 30, 0b0101101010101000 }, /* 29 30 29 30 30 29 30 29 30 29 30 29 30 384 -1969 */ { 00, 02, 17, 0b0101011010100000 }, /* 29 30 29 30 29 30 30 29 30 29 30 29 354 -1970 */ { 00, 02, 06, 0b1001011011010000 }, /* 30 29 29 30 29 30 30 29 30 30 29 30 355 -1971 */ { 05, 01, 27, 0b0100101011101000 }, /* 29 30 29 29 30 29 30 29 30 30 30 29 30 384 -1972 */ { 00, 02, 15, 0b0100101011010000 }, /* 29 30 29 29 30 29 30 29 30 30 29 30 354 -1973 */ { 00, 02, 03, 0b1010010011010000 }, /* 30 29 30 29 29 30 29 29 30 30 29 30 354 -1974 */ { 04, 01, 23, 0b1101001001101000 }, /* 30 30 29 30 29 29 30 29 29 30 30 29 30 384 -1975 */ { 00, 02, 11, 0b1101001001010000 }, /* 30 30 29 30 29 29 30 29 29 30 29 30 354 -1976 */ { 08, 01, 31, 0b1101010100101000 }, /* 30 30 29 30 29 30 29 30 29 29 30 29 30 384 -1977 */ { 00, 02, 18, 0b1011010101000000 }, /* 30 29 30 30 29 30 29 30 29 30 29 29 354 -1978 */ { 00, 02, 07, 0b1011011010100000 }, /* 30 29 30 30 29 30 30 29 30 29 30 29 355 -1979 */ { 06, 01, 28, 0b1001011011010000 }, /* 30 29 29 30 29 30 30 29 30 30 29 30 29 384 -1980 */ { 00, 02, 16, 0b1001010110110000 }, /* 30 29 29 30 29 30 29 30 30 29 30 30 355 -1981 */ { 00, 02, 05, 0b0100100110110000 }, /* 29 30 29 29 30 29 29 30 30 29 30 30 354 -1982 */ { 04, 01, 25, 0b1010010010111000 }, /* 30 29 30 29 29 30 29 29 30 29 30 30 30 384 -1983 */ { 00, 02, 13, 0b1010010010110000 }, /* 30 29 30 29 29 30 29 29 30 29 30 30 354 -1984 */ { 10, 02, 02, 0b1011001001011000 }, /* 30 29 30 30 29 29 30 29 29 30 29 30 30 384 -1985 */ { 00, 02, 20, 0b0110101001010000 }, /* 29 30 30 29 30 29 30 29 29 30 29 30 354 -1986 */ { 00, 02, 09, 0b0110110101000000 }, /* 29 30 30 29 30 30 29 30 29 30 29 29 354 -1987 */ { 06, 01, 29, 0b1010110110100000 }, /* 30 29 30 29 30 30 29 30 30 29 30 29 29 384 -1988 */ { 00, 02, 17, 0b1010101101100000 }, /* 30 29 30 29 30 29 30 30 29 30 30 29 355 -1989 */ { 00, 02, 06, 0b1001010101110000 }, /* 30 29 29 30 29 30 29 30 29 30 30 30 355 -1990 */ { 05, 01, 27, 0b0100100101111000 }, /* 29 30 29 29 30 29 29 30 29 30 30 30 30 384 -1991 */ { 00, 02, 15, 0b0100100101110000 }, /* 29 30 29 29 30 29 29 30 29 30 30 30 354 -1992 */ { 00, 02, 04, 0b0110010010110000 }, /* 29 30 30 29 29 30 29 29 30 29 30 30 354 -1993 */ { 03, 01, 23, 0b0110101001010000 }, /* 29 30 30 29 30 29 30 29 29 30 29 30 29 383 -1994 */ { 00, 02, 10, 0b1110101001010000 }, /* 30 30 30 29 30 29 30 29 29 30 29 30 355 -1995 */ { 08, 01, 31, 0b0110101100101000 }, /* 29 30 30 29 30 29 30 30 29 29 30 29 30 384 -1996 */ { 00, 02, 19, 0b0101101011000000 }, /* 29 30 29 30 30 29 30 29 30 30 29 29 354 -1997 */ { 00, 02, 07, 0b1010101101100000 }, /* 30 29 30 29 30 29 30 30 29 30 30 29 355 -1998 */ { 05, 01, 28, 0b1001001101101000 }, /* 30 29 29 30 29 29 30 30 29 30 30 29 30 384 -1999 */ { 00, 02, 16, 0b1001001011100000 }, /* 30 29 29 30 29 29 30 29 30 30 30 29 354 -2000 */ { 00, 02, 05, 0b1100100101100000 }, /* 30 30 29 29 30 29 29 30 29 30 30 29 354 -2001 */ { 04, 01, 24, 0b1101010010101000 }, /* 30 30 29 30 29 30 29 29 30 29 30 29 30 384 -2002 */ { 00, 02, 12, 0b1101010010100000 }, /* 30 30 29 30 29 30 29 29 30 29 30 29 354 -2003 */ { 00, 02, 01, 0b1101101001010000 }, /* 30 30 29 30 30 29 30 29 29 30 29 30 355 -2004 */ { 02, 01, 22, 0b0101101010101000 }, /* 29 30 29 30 30 29 30 29 30 29 30 29 30 384 -2005 */ { 00, 02, 09, 0b0101011010100000 }, /* 29 30 29 30 29 30 30 29 30 29 30 29 354 -2006 */ { 07, 01, 29, 0b1010101011011000 }, /* 30 29 30 29 30 29 30 29 30 30 29 30 30 385 -2007 */ { 00, 02, 18, 0b0010010111010000 }, /* 29 29 30 29 29 30 29 30 30 30 29 30 354 -2008 */ { 00, 02, 07, 0b1001001011010000 }, /* 30 29 29 30 29 29 30 29 30 30 29 30 354 -2009 */ { 05, 01, 26, 0b1100100101011000 }, /* 30 30 29 29 30 29 29 30 29 30 29 30 30 384 -2010 */ { 00, 02, 14, 0b1010100101010000 }, /* 30 29 30 29 30 29 29 30 29 30 29 30 354 -2011 */ { 00, 02, 03, 0b1011010010100000 }, /* 30 29 30 30 29 30 29 29 30 29 30 29 354 -2012 */ { 04, 01, 23, 0b1011010101010000 }, /* 30 29 30 30 29 30 29 30 29 30 29 30 29 384 -2013 */ { 00, 02, 10, 0b1010110101010000 }, /* 30 29 30 29 30 30 29 30 29 30 29 30 355 -2014 */ { 09, 01, 31, 0b0101010110101000 }, /* 29 30 29 30 29 30 29 30 30 29 30 29 30 384 -2015 */ { 00, 02, 19, 0b0100101110100000 }, /* 29 30 29 29 30 29 30 30 30 29 30 29 354 -2016 */ { 00, 02, 08, 0b1010010110110000 }, /* 30 29 30 29 29 30 29 30 30 29 30 30 355 -2017 */ { 06, 01, 28, 0b0101001010111000 }, /* 29 30 29 30 29 29 30 29 30 29 30 30 30 384 -2018 */ { 00, 02, 16, 0b0101001010110000 }, /* 29 30 29 30 29 29 30 29 30 29 30 30 354 -2019 */ { 00, 02, 05, 0b1010100100110000 }, /* 30 29 30 29 30 29 29 30 29 29 30 30 354 -2020 */ { 04, 01, 25, 0b0111010010101000 }, /* 29 30 30 30 29 30 29 29 30 29 30 29 30 384 -2021 */ { 00, 02, 12, 0b0110101010100000 }, /* 29 30 30 29 30 29 30 29 30 29 30 29 354 -2022 */ { 00, 02, 01, 0b1010110101010000 }, /* 30 29 30 29 30 30 29 30 29 30 29 30 355 -2023 */ { 02, 01, 22, 0b0100110110101000 }, /* 29 30 29 29 30 30 29 30 30 29 30 29 30 384 -2024 */ { 00, 02, 10, 0b0100101101100000 }, /* 29 30 29 29 30 29 30 30 29 30 30 29 354 -2025 */ { 06, 01, 29, 0b1010010101110000 }, /* 30 29 30 29 29 30 29 30 29 30 30 30 29 384 -2026 */ { 00, 02, 17, 0b1010010011100000 }, /* 30 29 30 29 29 30 29 29 30 30 30 29 354 -2027 */ { 00, 02, 06, 0b1101001001100000 }, /* 30 30 29 30 29 29 30 29 29 30 30 29 354 -2028 */ { 05, 01, 26, 0b1110100100110000 }, /* 30 30 30 29 30 29 29 30 29 29 30 30 29 384 -2029 */ { 00, 02, 13, 0b1101010100110000 }, /* 30 30 29 30 29 30 29 30 29 29 30 30 355 -2030 */ { 00, 02, 03, 0b0101101010100000 }, /* 29 30 29 30 30 29 30 29 30 29 30 29 354 -2031 */ { 03, 01, 23, 0b0110101101010000 }, /* 29 30 30 29 30 29 30 30 29 30 29 30 29 384 -2032 */ { 00, 02, 11, 0b1001011011010000 }, /* 30 29 29 30 29 30 30 29 30 30 29 30 355 -2033 */ { 11, 01, 31, 0b0100101011101000 }, /* 29 30 29 29 30 29 30 29 30 30 30 29 30 384 -2034 */ { 00, 02, 19, 0b0100101011010000 }, /* 29 30 29 29 30 29 30 29 30 30 29 30 354 -2035 */ { 00, 02, 08, 0b1010010011010000 }, /* 30 29 30 29 29 30 29 29 30 30 29 30 354 -2036 */ { 06, 01, 28, 0b1101001001011000 }, /* 30 30 29 30 29 29 30 29 29 30 29 30 30 384 -2037 */ { 00, 02, 15, 0b1101001001010000 }, /* 30 30 29 30 29 29 30 29 29 30 29 30 354 -2038 */ { 00, 02, 04, 0b1101010100100000 }, /* 30 30 29 30 29 30 29 30 29 29 30 29 354 -2039 */ { 05, 01, 24, 0b1101101010100000 }, /* 30 30 29 30 30 29 30 29 30 29 30 29 29 384 -2040 */ { 00, 02, 12, 0b1011010110100000 }, /* 30 29 30 30 29 30 29 30 30 29 30 29 355 -2041 */ { 00, 02, 01, 0b0101011011010000 }, /* 29 30 29 30 29 30 30 29 30 30 29 30 355 -2042 */ { 02, 01, 22, 0b0100101011011000 }, /* 29 30 29 29 30 29 30 29 30 30 29 30 30 384 -2043 */ { 00, 02, 10, 0b0100100110110000 }, /* 29 30 29 29 30 29 29 30 30 29 30 30 354 -2044 */ { 07, 01, 30, 0b1010010010111000 }, /* 30 29 30 29 29 30 29 29 30 29 30 30 30 384 -2045 */ { 00, 02, 17, 0b1010010010110000 }, /* 30 29 30 29 29 30 29 29 30 29 30 30 354 -2046 */ { 00, 02, 06, 0b1010101001010000 }, /* 30 29 30 29 30 29 30 29 29 30 29 30 354 -2047 */ { 05, 01, 26, 0b1011010100101000 }, /* 30 29 30 30 29 30 29 30 29 29 30 29 30 384 -2048 */ { 00, 02, 14, 0b0110110100100000 }, /* 29 30 30 29 30 30 29 30 29 29 30 29 354 -2049 */ { 00, 02, 02, 0b1010110110100000 }, /* 30 29 30 29 30 30 29 30 30 29 30 29 355 -2050 */ { 03, 01, 23, 0b0101010110110000 }, /* 29 30 29 30 29 30 29 30 30 29 30 30 29 384 -2051 */ { 00, 02, 11, 0b1001001101110000 }, /* 30 29 29 30 29 29 30 30 29 30 30 30 355 -2052 */ { 08, 02, 01, 0b0100100101111000 }, /* 29 30 29 29 30 29 29 30 29 30 30 30 30 384 -2053 */ { 00, 02, 19, 0b0100100101110000 }, /* 29 30 29 29 30 29 29 30 29 30 30 30 354 -2054 */ { 00, 02, 08, 0b0110010010110000 }, /* 29 30 30 29 29 30 29 29 30 29 30 30 354 -2055 */ { 06, 01, 28, 0b0110101001010000 }, /* 29 30 30 29 30 29 30 29 29 30 29 30 29 383 -2056 */ { 00, 02, 15, 0b1110101001010000 }, /* 30 30 30 29 30 29 30 29 29 30 29 30 355 -2057 */ { 00, 02, 04, 0b0110101010100000 }, /* 29 30 30 29 30 29 30 29 30 29 30 29 354 -2058 */ { 04, 01, 24, 0b1010101101100000 }, /* 30 29 30 29 30 29 30 30 29 30 30 29 29 384 -2059 */ { 00, 02, 12, 0b1010101011100000 }, /* 30 29 30 29 30 29 30 29 30 30 30 29 355 -2060 */ { 00, 02, 02, 0b1001001011100000 }, /* 30 29 29 30 29 29 30 29 30 30 30 29 354 -2061 */ { 03, 01, 21, 0b1100100101110000 }, /* 30 30 29 29 30 29 29 30 29 30 30 30 29 384 -2062 */ { 00, 02, 09, 0b1100100101100000 }, /* 30 30 29 29 30 29 29 30 29 30 30 29 354 -2063 */ { 07, 01, 29, 0b1101010010101000 }, /* 30 30 29 30 29 30 29 29 30 29 30 29 30 384 -2064 */ { 00, 02, 17, 0b1101010010100000 }, /* 30 30 29 30 29 30 29 29 30 29 30 29 354 -2065 */ { 00, 02, 05, 0b1101101001010000 }, /* 30 30 29 30 30 29 30 29 29 30 29 30 355 -2066 */ { 05, 01, 26, 0b0101101010101000 }, /* 29 30 29 30 30 29 30 29 30 29 30 29 30 384 -2067 */ { 00, 02, 14, 0b0101011010100000 }, /* 29 30 29 30 29 30 30 29 30 29 30 29 354 -2068 */ { 00, 02, 03, 0b1010011011010000 }, /* 30 29 30 29 29 30 30 29 30 30 29 30 355 -2069 */ { 04, 01, 23, 0b0101001011101000 }, /* 29 30 29 30 29 29 30 29 30 30 30 29 30 384 -2070 */ { 00, 02, 11, 0b0101001011010000 }, /* 29 30 29 30 29 29 30 29 30 30 29 30 354 -2071 */ { 08, 01, 31, 0b1010100101011000 }, /* 30 29 30 29 30 29 29 30 29 30 29 30 30 384 -2072 */ { 00, 02, 19, 0b1010100101010000 }, /* 30 29 30 29 30 29 29 30 29 30 29 30 354 -2073 */ { 00, 02, 07, 0b1011010010100000 }, /* 30 29 30 30 29 30 29 29 30 29 30 29 354 -2074 */ { 06, 01, 27, 0b1011010101010000 }, /* 30 29 30 30 29 30 29 30 29 30 29 30 29 384 -2075 */ { 00, 02, 15, 0b1010110101010000 }, /* 30 29 30 29 30 30 29 30 29 30 29 30 355 -2076 */ { 00, 02, 05, 0b0101010110100000 }, /* 29 30 29 30 29 30 29 30 30 29 30 29 354 -2077 */ { 04, 01, 24, 0b1010010111010000 }, /* 30 29 30 29 29 30 29 30 30 30 29 30 29 384 -2078 */ { 00, 02, 12, 0b1010010110110000 }, /* 30 29 30 29 29 30 29 30 30 29 30 30 355 -2079 */ { 00, 02, 02, 0b0101001010110000 }, /* 29 30 29 30 29 29 30 29 30 29 30 30 354 -2080 */ { 03, 01, 22, 0b1010100100111000 }, /* 30 29 30 29 30 29 29 30 29 29 30 30 30 384 -2081 */ { 00, 02, 09, 0b0110100100110000 }, /* 29 30 30 29 30 29 29 30 29 29 30 30 354 -2082 */ { 07, 01, 29, 0b0111001010011000 }, /* 29 30 30 30 29 29 30 29 30 29 29 30 30 384 -2083 */ { 00, 02, 17, 0b0110101010100000 }, /* 29 30 30 29 30 29 30 29 30 29 30 29 354 -2084 */ { 00, 02, 06, 0b1010110101010000 }, /* 30 29 30 29 30 30 29 30 29 30 29 30 355 -2085 */ { 05, 01, 26, 0b0100110110101000 }, /* 29 30 29 29 30 30 29 30 30 29 30 29 30 384 -2086 */ { 00, 02, 14, 0b0100101101100000 }, /* 29 30 29 29 30 29 30 30 29 30 30 29 354 -2087 */ { 00, 02, 03, 0b1010010101110000 }, /* 30 29 30 29 29 30 29 30 29 30 30 30 355 -2088 */ { 04, 01, 24, 0b0101001001110000 }, /* 29 30 29 30 29 29 30 29 29 30 30 30 29 383 -2089 */ { 00, 02, 10, 0b1101000101100000 }, /* 30 30 29 30 29 29 29 30 29 30 30 29 354 -2090 */ { 08, 01, 30, 0b1110100100110000 }, /* 30 30 30 29 30 29 29 30 29 29 30 30 29 384 -2091 */ { 00, 02, 18, 0b1101010100100000 }, /* 30 30 29 30 29 30 29 30 29 29 30 29 354 -2092 */ { 00, 02, 07, 0b1101101010100000 }, /* 30 30 29 30 30 29 30 29 30 29 30 29 355 -2093 */ { 06, 01, 27, 0b0110101101010000 }, /* 29 30 30 29 30 29 30 30 29 30 29 30 29 384 -2094 */ { 00, 02, 15, 0b0101011011010000 }, /* 29 30 29 30 29 30 30 29 30 30 29 30 355 -2095 */ { 00, 02, 05, 0b0100101011100000 }, /* 29 30 29 29 30 29 30 29 30 30 30 29 354 -2096 */ { 04, 01, 25, 0b1010010011101000 }, /* 30 29 30 29 29 30 29 29 30 30 30 29 30 384 -2097 */ { 00, 02, 12, 0b1010001011010000 }, /* 30 29 30 29 29 29 30 29 30 30 29 30 354 -2098 */ { 00, 02, 01, 0b1101000101010000 }, /* 30 30 29 30 29 29 29 30 29 30 29 30 354 -2099 */ { 02, 01, 21, 0b1101100100101000 }, /* 30 30 29 30 30 29 29 30 29 29 30 29 30 384 -2100 */ { 00, 02, 09, 0b1101010100100000 }, /* 30 30 29 30 29 30 29 30 29 29 30 29 354 - */ }; - - internal override int MinCalendarYear => MinLunisolarYear; - - internal override int MaxCalendarYear => MaxLunisolarYear; - - internal override DateTime MinDate => s_minDate; - - internal override DateTime MaxDate => s_maxDate; - - internal override EraInfo[]? CalEraInfo => null; - - internal override int GetYearInfo(int lunarYear, int index) - { - if (lunarYear < MinLunisolarYear || lunarYear > MaxLunisolarYear) - { - throw new ArgumentOutOfRangeException("year", lunarYear, SR.Format(SR.ArgumentOutOfRange_Range, MinLunisolarYear, MaxLunisolarYear)); - } - - return s_yinfo[lunarYear - MinLunisolarYear, 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(nameof(era), era, SR.ArgumentOutOfRange_InvalidEraValue); - } - if (year < MinLunisolarYear || year > MaxLunisolarYear) - { - throw new ArgumentOutOfRangeException(nameof(year), year, SR.Format(SR.ArgumentOutOfRange_Range, MinLunisolarYear, MaxLunisolarYear)); - } - - return year; - } - - public ChineseLunisolarCalendar() - { - } - - public override int GetEra(DateTime time) - { - CheckTicksRange(time.Ticks); - return ChineseEra; - } - - internal override CalendarId ID => CalendarId.CHINESELUNISOLAR; - - internal override CalendarId BaseCalendarID => - // Use CAL_GREGORIAN just to get CurrentEraValue as 1 since we do not have data under the ID CAL_ChineseLunisolar yet - CalendarId.GREGORIAN; - - public override int[] Eras => new int[] { ChineseEra }; - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/CompareInfo.Invariant.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/CompareInfo.Invariant.cs deleted file mode 100644 index 92a962b5273..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/CompareInfo.Invariant.cs +++ /dev/null @@ -1,249 +0,0 @@ -// 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; -using System.Runtime.InteropServices; - -namespace System.Globalization -{ - public partial class CompareInfo - { - internal static unsafe int InvariantIndexOf(string source, string value, int startIndex, int count, bool ignoreCase) - { - Debug.Assert(source != null); - Debug.Assert(value != null); - Debug.Assert(startIndex >= 0 && startIndex < source.Length); - - fixed (char* pSource = source) fixed (char* pValue = value) - { - char* pSrc = &pSource[startIndex]; - int index = InvariantFindString(pSrc, count, pValue, value.Length, ignoreCase, fromBeginning: true); - if (index >= 0) - { - return index + startIndex; - } - return -1; - } - } - - internal static unsafe int InvariantIndexOf(ReadOnlySpan<char> source, ReadOnlySpan<char> value, bool ignoreCase, bool fromBeginning = true) - { - Debug.Assert(source.Length != 0); - Debug.Assert(value.Length != 0); - - fixed (char* pSource = &MemoryMarshal.GetReference(source)) - fixed (char* pValue = &MemoryMarshal.GetReference(value)) - { - return InvariantFindString(pSource, source.Length, pValue, value.Length, ignoreCase, fromBeginning); - } - } - - internal static unsafe int InvariantLastIndexOf(string source, string value, int startIndex, int count, bool ignoreCase) - { - Debug.Assert(source != null); - Debug.Assert(value != null); - Debug.Assert(startIndex >= 0 && startIndex < source.Length); - - fixed (char* pSource = source) fixed (char* pValue = value) - { - char* pSrc = &pSource[startIndex - count + 1]; - int index = InvariantFindString(pSrc, count, pValue, value.Length, ignoreCase, fromBeginning: false); - if (index >= 0) - { - return index + startIndex - count + 1; - } - return -1; - } - } - - private static unsafe int InvariantFindString(char* source, int sourceCount, char* value, int valueCount, bool ignoreCase, bool fromBeginning) - { - int ctrSource = 0; // index value into source - int ctrValue = 0; // index value into value - char sourceChar; // Character for case lookup in source - char valueChar; // Character for case lookup in value - int lastSourceStart; - - Debug.Assert(source != null); - Debug.Assert(value != null); - Debug.Assert(sourceCount >= 0); - Debug.Assert(valueCount >= 0); - - if (valueCount == 0) - { - return fromBeginning ? 0 : sourceCount - 1; - } - - if (sourceCount < valueCount) - { - return -1; - } - - if (fromBeginning) - { - lastSourceStart = sourceCount - valueCount; - if (ignoreCase) - { - char firstValueChar = InvariantToUpper(value[0]); - for (ctrSource = 0; ctrSource <= lastSourceStart; ctrSource++) - { - sourceChar = InvariantToUpper(source[ctrSource]); - if (sourceChar != firstValueChar) - { - continue; - } - - for (ctrValue = 1; ctrValue < valueCount; ctrValue++) - { - sourceChar = InvariantToUpper(source[ctrSource + ctrValue]); - valueChar = InvariantToUpper(value[ctrValue]); - - if (sourceChar != valueChar) - { - break; - } - } - - if (ctrValue == valueCount) - { - return ctrSource; - } - } - } - else - { - char firstValueChar = value[0]; - for (ctrSource = 0; ctrSource <= lastSourceStart; ctrSource++) - { - sourceChar = source[ctrSource]; - if (sourceChar != firstValueChar) - { - continue; - } - - for (ctrValue = 1; ctrValue < valueCount; ctrValue++) - { - sourceChar = source[ctrSource + ctrValue]; - valueChar = value[ctrValue]; - - if (sourceChar != valueChar) - { - break; - } - } - - if (ctrValue == valueCount) - { - return ctrSource; - } - } - } - } - else - { - lastSourceStart = sourceCount - valueCount; - if (ignoreCase) - { - char firstValueChar = InvariantToUpper(value[0]); - for (ctrSource = lastSourceStart; ctrSource >= 0; ctrSource--) - { - sourceChar = InvariantToUpper(source[ctrSource]); - if (sourceChar != firstValueChar) - { - continue; - } - for (ctrValue = 1; ctrValue < valueCount; ctrValue++) - { - sourceChar = InvariantToUpper(source[ctrSource + ctrValue]); - valueChar = InvariantToUpper(value[ctrValue]); - - if (sourceChar != valueChar) - { - break; - } - } - - if (ctrValue == valueCount) - { - return ctrSource; - } - } - } - else - { - char firstValueChar = value[0]; - for (ctrSource = lastSourceStart; ctrSource >= 0; ctrSource--) - { - sourceChar = source[ctrSource]; - if (sourceChar != firstValueChar) - { - continue; - } - - for (ctrValue = 1; ctrValue < valueCount; ctrValue++) - { - sourceChar = source[ctrSource + ctrValue]; - valueChar = value[ctrValue]; - - if (sourceChar != valueChar) - { - break; - } - } - - if (ctrValue == valueCount) - { - return ctrSource; - } - } - } - } - - return -1; - } - - private static char InvariantToUpper(char c) - { - return (uint)(c - 'a') <= (uint)('z' - 'a') ? (char)(c - 0x20) : c; - } - - private unsafe SortKey InvariantCreateSortKey(string source, CompareOptions options) - { - if (source == null) { throw new ArgumentNullException(nameof(source)); } - - if ((options & ValidSortkeyCtorMaskOffFlags) != 0) - { - throw new ArgumentException(SR.Argument_InvalidFlag, nameof(options)); - } - - byte[] keyData; - if (source.Length == 0) - { - keyData = Array.Empty<byte>(); - } - else - { - // In the invariant mode, all string comparisons are done as ordinal so when generating the sort keys we generate it according to this fact - keyData = new byte[source.Length * sizeof(char)]; - - fixed (char* pChar = source) fixed (byte* pByte = keyData) - { - if ((options & (CompareOptions.IgnoreCase | CompareOptions.OrdinalIgnoreCase)) != 0) - { - short* pShort = (short*)pByte; - for (int i = 0; i < source.Length; i++) - { - pShort[i] = (short)InvariantToUpper(source[i]); - } - } - else - { - Buffer.MemoryCopy(pChar, pByte, keyData.Length, keyData.Length); - } - } - } - return new SortKey(Name, source, options, keyData); - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/CompareInfo.Unix.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/CompareInfo.Unix.cs deleted file mode 100644 index f77c3913cae..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/CompareInfo.Unix.cs +++ /dev/null @@ -1,1148 +0,0 @@ -// 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.Buffers; -using System.Collections.Generic; -using System.Diagnostics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Security; -using System.Threading; - -using Internal.Runtime.CompilerServices; - -namespace System.Globalization -{ - public partial class CompareInfo - { - [NonSerialized] - private IntPtr _sortHandle; - - [NonSerialized] - private bool _isAsciiEqualityOrdinal; - - private void InitSort(CultureInfo culture) - { - _sortName = culture.SortName; - - if (GlobalizationMode.Invariant) - { - _isAsciiEqualityOrdinal = true; - } - else - { - // Inline the following condition to avoid potential implementation cycles within globalization - // - // _isAsciiEqualityOrdinal = _sortName == "" || _sortName == "en" || _sortName.StartsWith("en-", StringComparison.Ordinal); - // - _isAsciiEqualityOrdinal = _sortName.Length == 0 || - (_sortName.Length >= 2 && _sortName[0] == 'e' && _sortName[1] == 'n' && (_sortName.Length == 2 || _sortName[2] == '-')); - - _sortHandle = SortHandleCache.GetCachedSortHandle(_sortName); - } - } - - internal static unsafe int IndexOfOrdinalCore(string source, string value, int startIndex, int count, bool ignoreCase) - { - Debug.Assert(!GlobalizationMode.Invariant); - - Debug.Assert(source != null); - Debug.Assert(value != null); - - if (value.Length == 0) - { - return startIndex; - } - - if (count < value.Length) - { - return -1; - } - - if (ignoreCase) - { - fixed (char* pSource = source) - { - int index = Interop.Globalization.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 IndexOfOrdinalCore(ReadOnlySpan<char> source, ReadOnlySpan<char> value, bool ignoreCase, bool fromBeginning) - { - Debug.Assert(!GlobalizationMode.Invariant); - - Debug.Assert(source.Length != 0); - Debug.Assert(value.Length != 0); - - if (source.Length < value.Length) - { - return -1; - } - - if (ignoreCase) - { - fixed (char* pSource = &MemoryMarshal.GetReference(source)) - fixed (char* pValue = &MemoryMarshal.GetReference(value)) - { - return Interop.Globalization.IndexOfOrdinalIgnoreCase(pValue, value.Length, pSource, source.Length, findLast: !fromBeginning); - } - } - - int startIndex, endIndex, jump; - if (fromBeginning) - { - // Left to right, from zero to last possible index in the source string. - // Incrementing by one after each iteration. Stop condition is last possible index plus 1. - startIndex = 0; - endIndex = source.Length - value.Length + 1; - jump = 1; - } - else - { - // Right to left, from first possible index in the source string to zero. - // Decrementing by one after each iteration. Stop condition is last possible index minus 1. - startIndex = source.Length - value.Length; - endIndex = -1; - jump = -1; - } - - for (int i = startIndex; i != endIndex; i += jump) - { - 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 LastIndexOfOrdinalCore(string source, string value, int startIndex, int count, bool ignoreCase) - { - Debug.Assert(!GlobalizationMode.Invariant); - - Debug.Assert(source != null); - Debug.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.Globalization.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 static unsafe int CompareStringOrdinalIgnoreCase(ref char string1, int count1, ref char string2, int count2) - { - Debug.Assert(!GlobalizationMode.Invariant); - - fixed (char* char1 = &string1) - fixed (char* char2 = &string2) - { - return Interop.Globalization.CompareStringOrdinalIgnoreCase(char1, count1, char2, count2); - } - } - - // TODO https://github.com/dotnet/coreclr/issues/13827: - // This method shouldn't be necessary, as we should be able to just use the overload - // that takes two spans. But due to this issue, that's adding significant overhead. - private unsafe int CompareString(ReadOnlySpan<char> string1, string string2, CompareOptions options) - { - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert(string2 != null); - Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0); - - fixed (char* pString1 = &MemoryMarshal.GetReference(string1)) - fixed (char* pString2 = &string2.GetRawStringData()) - { - return Interop.Globalization.CompareString(_sortHandle, pString1, string1.Length, pString2, string2.Length, options); - } - } - - private unsafe int CompareString(ReadOnlySpan<char> string1, ReadOnlySpan<char> string2, CompareOptions options) - { - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0); - - fixed (char* pString1 = &MemoryMarshal.GetReference(string1)) - fixed (char* pString2 = &MemoryMarshal.GetReference(string2)) - { - return Interop.Globalization.CompareString(_sortHandle, pString1, string1.Length, pString2, string2.Length, options); - } - } - - internal unsafe int IndexOfCore(string source, string target, int startIndex, int count, CompareOptions options, int* matchLengthPtr) - { - Debug.Assert(!GlobalizationMode.Invariant); - - Debug.Assert(!string.IsNullOrEmpty(source)); - Debug.Assert(target != null); - Debug.Assert((options & CompareOptions.OrdinalIgnoreCase) == 0); - Debug.Assert((options & CompareOptions.Ordinal) == 0); - - int index; - - if (_isAsciiEqualityOrdinal && CanUseAsciiOrdinalForOptions(options)) - { - if ((options & CompareOptions.IgnoreCase) != 0) - index = IndexOfOrdinalIgnoreCaseHelper(source.AsSpan(startIndex, count), target.AsSpan(), options, matchLengthPtr, fromBeginning: true); - else - index = IndexOfOrdinalHelper(source.AsSpan(startIndex, count), target.AsSpan(), options, matchLengthPtr, fromBeginning: true); - } - else - { - fixed (char* pSource = source) - fixed (char* pTarget = target) - { - index = Interop.Globalization.IndexOf(_sortHandle, pTarget, target.Length, pSource + startIndex, count, options, matchLengthPtr); - } - } - - return index != -1 ? index + startIndex : -1; - } - - // For now, this method is only called from Span APIs with either options == CompareOptions.None or CompareOptions.IgnoreCase - internal unsafe int IndexOfCore(ReadOnlySpan<char> source, ReadOnlySpan<char> target, CompareOptions options, int* matchLengthPtr, bool fromBeginning) - { - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert(source.Length != 0); - Debug.Assert(target.Length != 0); - - if (_isAsciiEqualityOrdinal && CanUseAsciiOrdinalForOptions(options)) - { - if ((options & CompareOptions.IgnoreCase) != 0) - return IndexOfOrdinalIgnoreCaseHelper(source, target, options, matchLengthPtr, fromBeginning); - else - return IndexOfOrdinalHelper(source, target, options, matchLengthPtr, fromBeginning); - } - else - { - fixed (char* pSource = &MemoryMarshal.GetReference(source)) - fixed (char* pTarget = &MemoryMarshal.GetReference(target)) - { - if (fromBeginning) - return Interop.Globalization.IndexOf(_sortHandle, pTarget, target.Length, pSource, source.Length, options, matchLengthPtr); - else - return Interop.Globalization.LastIndexOf(_sortHandle, pTarget, target.Length, pSource, source.Length, options); - } - } - } - - /// <summary> - /// Duplicate of IndexOfOrdinalHelper that also handles ignore case. Can't converge both methods - /// as the JIT wouldn't be able to optimize the ignoreCase path away. - /// </summary> - /// <returns></returns> - private unsafe int IndexOfOrdinalIgnoreCaseHelper(ReadOnlySpan<char> source, ReadOnlySpan<char> target, CompareOptions options, int* matchLengthPtr, bool fromBeginning) - { - Debug.Assert(!GlobalizationMode.Invariant); - - Debug.Assert(!target.IsEmpty); - Debug.Assert(_isAsciiEqualityOrdinal); - - fixed (char* ap = &MemoryMarshal.GetReference(source)) - fixed (char* bp = &MemoryMarshal.GetReference(target)) - { - char* a = ap; - char* b = bp; - - for (int j = 0; j < target.Length; j++) - { - char targetChar = *(b + j); - if (targetChar >= 0x80 || HighCharTable[targetChar]) - goto InteropCall; - } - - if (target.Length > source.Length) - { - for (int k = 0; k < source.Length; k++) - { - char targetChar = *(a + k); - if (targetChar >= 0x80 || HighCharTable[targetChar]) - goto InteropCall; - } - return -1; - } - - int startIndex, endIndex, jump; - if (fromBeginning) - { - // Left to right, from zero to last possible index in the source string. - // Incrementing by one after each iteration. Stop condition is last possible index plus 1. - startIndex = 0; - endIndex = source.Length - target.Length + 1; - jump = 1; - } - else - { - // Right to left, from first possible index in the source string to zero. - // Decrementing by one after each iteration. Stop condition is last possible index minus 1. - startIndex = source.Length - target.Length; - endIndex = -1; - jump = -1; - } - - for (int i = startIndex; i != endIndex; i += jump) - { - int targetIndex = 0; - int sourceIndex = i; - - for (; targetIndex < target.Length; targetIndex++, sourceIndex++) - { - char valueChar = *(a + sourceIndex); - char targetChar = *(b + targetIndex); - - if (valueChar >= 0x80 || HighCharTable[valueChar]) - goto InteropCall; - - if (valueChar == targetChar) - { - continue; - } - - // uppercase both chars - notice that we need just one compare per char - if ((uint)(valueChar - 'a') <= ('z' - 'a')) - valueChar = (char)(valueChar - 0x20); - if ((uint)(targetChar - 'a') <= ('z' - 'a')) - targetChar = (char)(targetChar - 0x20); - - if (valueChar == targetChar) - { - continue; - } - - // The match may be affected by special character. Verify that the following character is regular ASCII. - if (sourceIndex < source.Length - 1 && *(a + sourceIndex + 1) >= 0x80) - goto InteropCall; - goto Next; - } - - // The match may be affected by special character. Verify that the following character is regular ASCII. - if (sourceIndex < source.Length && *(a + sourceIndex) >= 0x80) - goto InteropCall; - if (matchLengthPtr != null) - *matchLengthPtr = target.Length; - return i; - - Next: ; - } - - return -1; - - InteropCall: - if (fromBeginning) - return Interop.Globalization.IndexOf(_sortHandle, b, target.Length, a, source.Length, options, matchLengthPtr); - else - return Interop.Globalization.LastIndexOf(_sortHandle, b, target.Length, a, source.Length, options); - } - } - - private unsafe int IndexOfOrdinalHelper(ReadOnlySpan<char> source, ReadOnlySpan<char> target, CompareOptions options, int* matchLengthPtr, bool fromBeginning) - { - Debug.Assert(!GlobalizationMode.Invariant); - - Debug.Assert(!target.IsEmpty); - Debug.Assert(_isAsciiEqualityOrdinal); - - fixed (char* ap = &MemoryMarshal.GetReference(source)) - fixed (char* bp = &MemoryMarshal.GetReference(target)) - { - char* a = ap; - char* b = bp; - - for (int j = 0; j < target.Length; j++) - { - char targetChar = *(b + j); - if (targetChar >= 0x80 || HighCharTable[targetChar]) - goto InteropCall; - } - - if (target.Length > source.Length) - { - for (int k = 0; k < source.Length; k++) - { - char targetChar = *(a + k); - if (targetChar >= 0x80 || HighCharTable[targetChar]) - goto InteropCall; - } - return -1; - } - - int startIndex, endIndex, jump; - if (fromBeginning) - { - // Left to right, from zero to last possible index in the source string. - // Incrementing by one after each iteration. Stop condition is last possible index plus 1. - startIndex = 0; - endIndex = source.Length - target.Length + 1; - jump = 1; - } - else - { - // Right to left, from first possible index in the source string to zero. - // Decrementing by one after each iteration. Stop condition is last possible index minus 1. - startIndex = source.Length - target.Length; - endIndex = -1; - jump = -1; - } - - for (int i = startIndex; i != endIndex; i += jump) - { - int targetIndex = 0; - int sourceIndex = i; - - for (; targetIndex < target.Length; targetIndex++, sourceIndex++) - { - char valueChar = *(a + sourceIndex); - char targetChar = *(b + targetIndex); - - if (valueChar >= 0x80 || HighCharTable[valueChar]) - goto InteropCall; - - if (valueChar == targetChar) - { - continue; - } - - // The match may be affected by special character. Verify that the following character is regular ASCII. - if (sourceIndex < source.Length - 1 && *(a + sourceIndex + 1) >= 0x80) - goto InteropCall; - goto Next; - } - - // The match may be affected by special character. Verify that the following character is regular ASCII. - if (sourceIndex < source.Length && *(a + sourceIndex) >= 0x80) - goto InteropCall; - if (matchLengthPtr != null) - *matchLengthPtr = target.Length; - return i; - - Next: ; - } - - return -1; - - InteropCall: - if (fromBeginning) - return Interop.Globalization.IndexOf(_sortHandle, b, target.Length, a, source.Length, options, matchLengthPtr); - else - return Interop.Globalization.LastIndexOf(_sortHandle, b, target.Length, a, source.Length, options); - } - } - - private unsafe int LastIndexOfCore(string source, string target, int startIndex, int count, CompareOptions options) - { - Debug.Assert(!GlobalizationMode.Invariant); - - Debug.Assert(!string.IsNullOrEmpty(source)); - Debug.Assert(target != null); - Debug.Assert((options & CompareOptions.OrdinalIgnoreCase) == 0); - - if (target.Length == 0) - { - return startIndex; - } - - if (options == CompareOptions.Ordinal) - { - return LastIndexOfOrdinalCore(source, target, startIndex, count, ignoreCase: false); - } - - // 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); - - int lastIndex; - - if (_isAsciiEqualityOrdinal && CanUseAsciiOrdinalForOptions(options)) - { - if ((options & CompareOptions.IgnoreCase) != 0) - lastIndex = IndexOfOrdinalIgnoreCaseHelper(source.AsSpan(leftStartIndex, count), target.AsSpan(), options, matchLengthPtr: null, fromBeginning: false); - else - lastIndex = IndexOfOrdinalHelper(source.AsSpan(leftStartIndex, count), target.AsSpan(), options, matchLengthPtr: null, fromBeginning: false); - } - else - { - fixed (char* pSource = source) - fixed (char* pTarget = target) - { - lastIndex = Interop.Globalization.LastIndexOf(_sortHandle, pTarget, target.Length, pSource + (startIndex - count + 1), count, options); - } - } - - return lastIndex != -1 ? lastIndex + leftStartIndex : -1; - } - - private unsafe bool StartsWith(ReadOnlySpan<char> source, ReadOnlySpan<char> prefix, CompareOptions options) - { - Debug.Assert(!GlobalizationMode.Invariant); - - Debug.Assert(!source.IsEmpty); - Debug.Assert(!prefix.IsEmpty); - Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0); - - if (_isAsciiEqualityOrdinal && CanUseAsciiOrdinalForOptions(options)) - { - if ((options & CompareOptions.IgnoreCase) != 0) - return StartsWithOrdinalIgnoreCaseHelper(source, prefix, options); - else - return StartsWithOrdinalHelper(source, prefix, options); - } - else - { - fixed (char* pSource = &MemoryMarshal.GetReference(source)) - fixed (char* pPrefix = &MemoryMarshal.GetReference(prefix)) - { - return Interop.Globalization.StartsWith(_sortHandle, pPrefix, prefix.Length, pSource, source.Length, options); - } - } - } - - private unsafe bool StartsWithOrdinalIgnoreCaseHelper(ReadOnlySpan<char> source, ReadOnlySpan<char> prefix, CompareOptions options) - { - Debug.Assert(!GlobalizationMode.Invariant); - - Debug.Assert(!source.IsEmpty); - Debug.Assert(!prefix.IsEmpty); - Debug.Assert(_isAsciiEqualityOrdinal); - - int length = Math.Min(source.Length, prefix.Length); - - fixed (char* ap = &MemoryMarshal.GetReference(source)) - fixed (char* bp = &MemoryMarshal.GetReference(prefix)) - { - char* a = ap; - char* b = bp; - - while (length != 0) - { - int charA = *a; - int charB = *b; - - if (charA >= 0x80 || charB >= 0x80 || HighCharTable[charA] || HighCharTable[charB]) - goto InteropCall; - - 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; - - if (charA == charB) - { - a++; b++; - length--; - continue; - } - - // The match may be affected by special character. Verify that the following character is regular ASCII. - if (a < ap + source.Length - 1 && *(a + 1) >= 0x80) - goto InteropCall; - if (b < bp + prefix.Length - 1 && *(b + 1) >= 0x80) - goto InteropCall; - return false; - } - - // The match may be affected by special character. Verify that the following character is regular ASCII. - - if (source.Length < prefix.Length) - { - if (*b >= 0x80) - goto InteropCall; - return false; - } - - if (source.Length > prefix.Length) - { - if (*a >= 0x80) - goto InteropCall; - } - return true; - - InteropCall: - return Interop.Globalization.StartsWith(_sortHandle, bp, prefix.Length, ap, source.Length, options); - } - } - - private unsafe bool StartsWithOrdinalHelper(ReadOnlySpan<char> source, ReadOnlySpan<char> prefix, CompareOptions options) - { - Debug.Assert(!GlobalizationMode.Invariant); - - Debug.Assert(!source.IsEmpty); - Debug.Assert(!prefix.IsEmpty); - Debug.Assert(_isAsciiEqualityOrdinal); - - int length = Math.Min(source.Length, prefix.Length); - - fixed (char* ap = &MemoryMarshal.GetReference(source)) - fixed (char* bp = &MemoryMarshal.GetReference(prefix)) - { - char* a = ap; - char* b = bp; - - while (length != 0) - { - int charA = *a; - int charB = *b; - - if (charA >= 0x80 || charB >= 0x80 || HighCharTable[charA] || HighCharTable[charB]) - goto InteropCall; - - if (charA == charB) - { - a++; b++; - length--; - continue; - } - - // The match may be affected by special character. Verify that the following character is regular ASCII. - if (a < ap + source.Length - 1 && *(a + 1) >= 0x80) - goto InteropCall; - if (b < bp + prefix.Length - 1 && *(b + 1) >= 0x80) - goto InteropCall; - return false; - } - - // The match may be affected by special character. Verify that the following character is regular ASCII. - - if (source.Length < prefix.Length) - { - if (*b >= 0x80) - goto InteropCall; - return false; - } - - if (source.Length > prefix.Length) - { - if (*a >= 0x80) - goto InteropCall; - } - return true; - - InteropCall: - return Interop.Globalization.StartsWith(_sortHandle, bp, prefix.Length, ap, source.Length, options); - } - } - - private unsafe bool EndsWith(ReadOnlySpan<char> source, ReadOnlySpan<char> suffix, CompareOptions options) - { - Debug.Assert(!GlobalizationMode.Invariant); - - Debug.Assert(!source.IsEmpty); - Debug.Assert(!suffix.IsEmpty); - Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0); - - if (_isAsciiEqualityOrdinal && CanUseAsciiOrdinalForOptions(options)) - { - if ((options & CompareOptions.IgnoreCase) != 0) - return EndsWithOrdinalIgnoreCaseHelper(source, suffix, options); - else - return EndsWithOrdinalHelper(source, suffix, options); - } - else - { - fixed (char* pSource = &MemoryMarshal.GetReference(source)) - fixed (char* pSuffix = &MemoryMarshal.GetReference(suffix)) - { - return Interop.Globalization.EndsWith(_sortHandle, pSuffix, suffix.Length, pSource, source.Length, options); - } - } - } - - private unsafe bool EndsWithOrdinalIgnoreCaseHelper(ReadOnlySpan<char> source, ReadOnlySpan<char> suffix, CompareOptions options) - { - Debug.Assert(!GlobalizationMode.Invariant); - - Debug.Assert(!source.IsEmpty); - Debug.Assert(!suffix.IsEmpty); - Debug.Assert(_isAsciiEqualityOrdinal); - - int length = Math.Min(source.Length, suffix.Length); - - fixed (char* ap = &MemoryMarshal.GetReference(source)) - fixed (char* bp = &MemoryMarshal.GetReference(suffix)) - { - char* a = ap + source.Length - 1; - char* b = bp + suffix.Length - 1; - - while (length != 0) - { - int charA = *a; - int charB = *b; - - if (charA >= 0x80 || charB >= 0x80 || HighCharTable[charA] || HighCharTable[charB]) - goto InteropCall; - - 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; - - if (charA == charB) - { - a--; b--; - length--; - continue; - } - - return false; - } - - return (source.Length >= suffix.Length); - - InteropCall: - return Interop.Globalization.EndsWith(_sortHandle, bp, suffix.Length, ap, source.Length, options); - } - } - - private unsafe bool EndsWithOrdinalHelper(ReadOnlySpan<char> source, ReadOnlySpan<char> suffix, CompareOptions options) - { - Debug.Assert(!GlobalizationMode.Invariant); - - Debug.Assert(!source.IsEmpty); - Debug.Assert(!suffix.IsEmpty); - Debug.Assert(_isAsciiEqualityOrdinal); - - int length = Math.Min(source.Length, suffix.Length); - - fixed (char* ap = &MemoryMarshal.GetReference(source)) - fixed (char* bp = &MemoryMarshal.GetReference(suffix)) - { - char* a = ap + source.Length - 1; - char* b = bp + suffix.Length - 1; - - while (length != 0) - { - int charA = *a; - int charB = *b; - - if (charA >= 0x80 || charB >= 0x80 || HighCharTable[charA] || HighCharTable[charB]) - goto InteropCall; - - if (charA == charB) - { - a--; b--; - length--; - continue; - } - - return false; - } - - return (source.Length >= suffix.Length); - - InteropCall: - return Interop.Globalization.EndsWith(_sortHandle, bp, suffix.Length, ap, source.Length, options); - } - } - - private unsafe SortKey CreateSortKey(string source, CompareOptions options) - { - Debug.Assert(!GlobalizationMode.Invariant); - - if (source==null) { throw new ArgumentNullException(nameof(source)); } - - if ((options & ValidSortkeyCtorMaskOffFlags) != 0) - { - throw new ArgumentException(SR.Argument_InvalidFlag, nameof(options)); - } - - byte [] keyData; - if (source.Length == 0) - { - keyData = Array.Empty<byte>(); - } - else - { - fixed (char* pSource = source) - { - int sortKeyLength = Interop.Globalization.GetSortKey(_sortHandle, pSource, source.Length, null, 0, options); - keyData = new byte[sortKeyLength]; - - fixed (byte* pSortKey = keyData) - { - if (Interop.Globalization.GetSortKey(_sortHandle, pSource, source.Length, pSortKey, sortKeyLength, options) != sortKeyLength) - { - throw new ArgumentException(SR.Arg_ExternalException); - } - } - } - } - - return new SortKey(Name, source, options, keyData); - } - - private static unsafe bool IsSortable(char *text, int length) - { - Debug.Assert(!GlobalizationMode.Invariant); - - int index = 0; - UnicodeCategory uc; - - while (index < length) - { - if (char.IsHighSurrogate(text[index])) - { - if (index == length - 1 || !char.IsLowSurrogate(text[index+1])) - return false; // unpaired surrogate - - uc = CharUnicodeInfo.GetUnicodeCategory(char.ConvertToUtf32(text[index], text[index+1])); - if (uc == UnicodeCategory.PrivateUse || uc == UnicodeCategory.OtherNotAssigned) - return false; - - index += 2; - continue; - } - - if (char.IsLowSurrogate(text[index])) - { - return false; // unpaired surrogate - } - - uc = CharUnicodeInfo.GetUnicodeCategory(text[index]); - if (uc == UnicodeCategory.PrivateUse || uc == UnicodeCategory.OtherNotAssigned) - { - return false; - } - - index++; - } - - return true; - } - - // ----------------------------- - // ---- PAL layer ends here ---- - // ----------------------------- - - internal unsafe int GetHashCodeOfStringCore(ReadOnlySpan<char> source, CompareOptions options) - { - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0); - - if (source.Length == 0) - { - return 0; - } - - // according to ICU User Guide the performance of ucol_getSortKey is worse when it is called with null output buffer - // the solution is to try to fill the sort key in a temporary buffer of size equal 4 x string length - // 1MB is the biggest array that can be rented from ArrayPool.Shared without memory allocation - int sortKeyLength = (source.Length > 1024 * 1024 / 4) ? 0 : 4 * source.Length; - - byte[]? borrowedArray = null; - Span<byte> sortKey = sortKeyLength <= 1024 - ? stackalloc byte[1024] - : (borrowedArray = ArrayPool<byte>.Shared.Rent(sortKeyLength)); - - fixed (char* pSource = &MemoryMarshal.GetReference(source)) - { - fixed (byte* pSortKey = &MemoryMarshal.GetReference(sortKey)) - { - sortKeyLength = Interop.Globalization.GetSortKey(_sortHandle, pSource, source.Length, pSortKey, sortKey.Length, options); - } - - if (sortKeyLength > sortKey.Length) // slow path for big strings - { - if (borrowedArray != null) - { - ArrayPool<byte>.Shared.Return(borrowedArray); - } - - sortKey = (borrowedArray = ArrayPool<byte>.Shared.Rent(sortKeyLength)); - - fixed (byte* pSortKey = &MemoryMarshal.GetReference(sortKey)) - { - sortKeyLength = Interop.Globalization.GetSortKey(_sortHandle, pSource, source.Length, pSortKey, sortKey.Length, options); - } - } - } - - if (sortKeyLength == 0 || sortKeyLength > sortKey.Length) // internal error (0) or a bug (2nd call failed) in ucol_getSortKey - { - throw new ArgumentException(SR.Arg_ExternalException); - } - - int hash = Marvin.ComputeHash32(sortKey.Slice(0, sortKeyLength), Marvin.DefaultSeed); - - if (borrowedArray != null) - { - ArrayPool<byte>.Shared.Return(borrowedArray); - } - - return hash; - } - - private static CompareOptions GetOrdinalCompareOptions(CompareOptions options) - { - if ((options & CompareOptions.IgnoreCase) != 0) - { - 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 SortVersion GetSortVersion() - { - Debug.Assert(!GlobalizationMode.Invariant); - - int sortVersion = Interop.Globalization.GetSortVersion(_sortHandle); - return new SortVersion(sortVersion, LCID, new Guid(sortVersion, 0, 0, 0, 0, 0, 0, - (byte) (LCID >> 24), - (byte) ((LCID & 0x00FF0000) >> 16), - (byte) ((LCID & 0x0000FF00) >> 8), - (byte) (LCID & 0xFF))); - } - - private static class SortHandleCache - { - // in most scenarios there is a limited number of cultures with limited number of sort options - // so caching the sort handles and not freeing them is OK, see https://github.com/dotnet/coreclr/pull/25117 for more - private static readonly Dictionary<string, IntPtr> s_sortNameToSortHandleCache = new Dictionary<string, IntPtr>(); - - internal static IntPtr GetCachedSortHandle(string sortName) - { - lock (s_sortNameToSortHandleCache) - { - if (!s_sortNameToSortHandleCache.TryGetValue(sortName, out IntPtr result)) - { - Interop.Globalization.ResultCode resultCode = Interop.Globalization.GetSortHandle(sortName, out result); - - if (resultCode == Interop.Globalization.ResultCode.OutOfMemory) - throw new OutOfMemoryException(); - else if (resultCode != Interop.Globalization.ResultCode.Success) - throw new ExternalException(SR.Arg_ExternalException); - - try - { - s_sortNameToSortHandleCache.Add(sortName, result); - } - catch - { - Interop.Globalization.CloseSortHandle(result); - - throw; - } - } - - return result; - } - } - } - - private static ReadOnlySpan<bool> HighCharTable => new bool[0x80] - { - true, /* 0x0, 0x0 */ - true, /* 0x1, .*/ - true, /* 0x2, .*/ - true, /* 0x3, .*/ - true, /* 0x4, .*/ - true, /* 0x5, .*/ - true, /* 0x6, .*/ - true, /* 0x7, .*/ - true, /* 0x8, .*/ - false, /* 0x9, */ - true, /* 0xA, */ - false, /* 0xB, .*/ - false, /* 0xC, .*/ - true, /* 0xD, */ - true, /* 0xE, .*/ - true, /* 0xF, .*/ - true, /* 0x10, .*/ - true, /* 0x11, .*/ - true, /* 0x12, .*/ - true, /* 0x13, .*/ - true, /* 0x14, .*/ - true, /* 0x15, .*/ - true, /* 0x16, .*/ - true, /* 0x17, .*/ - true, /* 0x18, .*/ - true, /* 0x19, .*/ - true, /* 0x1A, */ - true, /* 0x1B, .*/ - true, /* 0x1C, .*/ - true, /* 0x1D, .*/ - true, /* 0x1E, .*/ - true, /* 0x1F, .*/ - false, /*0x20, */ - false, /*0x21, !*/ - false, /*0x22, "*/ - false, /*0x23, #*/ - false, /*0x24, $*/ - false, /*0x25, %*/ - false, /*0x26, &*/ - true, /*0x27, '*/ - false, /*0x28, (*/ - false, /*0x29, )*/ - false, /*0x2A **/ - false, /*0x2B, +*/ - false, /*0x2C, ,*/ - true, /*0x2D, -*/ - false, /*0x2E, .*/ - false, /*0x2F, /*/ - false, /*0x30, 0*/ - false, /*0x31, 1*/ - false, /*0x32, 2*/ - false, /*0x33, 3*/ - false, /*0x34, 4*/ - false, /*0x35, 5*/ - false, /*0x36, 6*/ - false, /*0x37, 7*/ - false, /*0x38, 8*/ - false, /*0x39, 9*/ - false, /*0x3A, :*/ - false, /*0x3B, ;*/ - false, /*0x3C, <*/ - false, /*0x3D, =*/ - false, /*0x3E, >*/ - false, /*0x3F, ?*/ - false, /*0x40, @*/ - false, /*0x41, A*/ - false, /*0x42, B*/ - false, /*0x43, C*/ - false, /*0x44, D*/ - false, /*0x45, E*/ - false, /*0x46, F*/ - false, /*0x47, G*/ - false, /*0x48, H*/ - false, /*0x49, I*/ - false, /*0x4A, J*/ - false, /*0x4B, K*/ - false, /*0x4C, L*/ - false, /*0x4D, M*/ - false, /*0x4E, N*/ - false, /*0x4F, O*/ - false, /*0x50, P*/ - false, /*0x51, Q*/ - false, /*0x52, R*/ - false, /*0x53, S*/ - false, /*0x54, T*/ - false, /*0x55, U*/ - false, /*0x56, V*/ - false, /*0x57, W*/ - false, /*0x58, X*/ - false, /*0x59, Y*/ - false, /*0x5A, Z*/ - false, /*0x5B, [*/ - false, /*0x5C, \*/ - false, /*0x5D, ]*/ - false, /*0x5E, ^*/ - false, /*0x5F, _*/ - false, /*0x60, `*/ - false, /*0x61, a*/ - false, /*0x62, b*/ - false, /*0x63, c*/ - false, /*0x64, d*/ - false, /*0x65, e*/ - false, /*0x66, f*/ - false, /*0x67, g*/ - false, /*0x68, h*/ - false, /*0x69, i*/ - false, /*0x6A, j*/ - false, /*0x6B, k*/ - false, /*0x6C, l*/ - false, /*0x6D, m*/ - false, /*0x6E, n*/ - false, /*0x6F, o*/ - false, /*0x70, p*/ - false, /*0x71, q*/ - false, /*0x72, r*/ - false, /*0x73, s*/ - false, /*0x74, t*/ - false, /*0x75, u*/ - false, /*0x76, v*/ - false, /*0x77, w*/ - false, /*0x78, x*/ - false, /*0x79, y*/ - false, /*0x7A, z*/ - false, /*0x7B, {*/ - false, /*0x7C, |*/ - false, /*0x7D, }*/ - false, /*0x7E, ~*/ - true, /*0x7F, */ - }; - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/CompareInfo.Windows.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/CompareInfo.Windows.cs deleted file mode 100644 index 595f64221b1..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/CompareInfo.Windows.cs +++ /dev/null @@ -1,606 +0,0 @@ -// 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.Buffers; -using System.Diagnostics; -using System.Runtime.InteropServices; - -namespace System.Globalization -{ - public partial class CompareInfo - { - internal static unsafe IntPtr GetSortHandle(string cultureName) - { - if (GlobalizationMode.Invariant) - { - return IntPtr.Zero; - } - - IntPtr handle; - int ret = Interop.Kernel32.LCMapStringEx(cultureName, Interop.Kernel32.LCMAP_SORTHANDLE, null, 0, &handle, IntPtr.Size, null, null, IntPtr.Zero); - if (ret > 0) - { - // Even if we can get the sort handle, it is not guaranteed to work when Windows compatibility shim is applied - // e.g. Windows 7 compatibility mode. We need to ensure it is working before using it. - // otherwise the whole framework app will not start. - int hashValue = 0; - char a = 'a'; - ret = Interop.Kernel32.LCMapStringEx(null, Interop.Kernel32.LCMAP_HASH, &a, 1, &hashValue, sizeof(int), null, null, handle); - if (ret > 1) - { - return handle; - } - } - - return IntPtr.Zero; - } - - private void InitSort(CultureInfo culture) - { - _sortName = culture.SortName; - _sortHandle = GetSortHandle(_sortName); - } - - private static unsafe int FindStringOrdinal( - uint dwFindStringOrdinalFlags, - string stringSource, - int offset, - int cchSource, - string value, - int cchValue, - bool bIgnoreCase) - { - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert(stringSource != null); - Debug.Assert(value != null); - - fixed (char* pSource = stringSource) - fixed (char* pValue = value) - { - int ret = Interop.Kernel32.FindStringOrdinal( - dwFindStringOrdinalFlags, - pSource + offset, - cchSource, - pValue, - cchValue, - bIgnoreCase ? 1 : 0); - return ret < 0 ? ret : ret + offset; - } - } - - private static unsafe int FindStringOrdinal( - uint dwFindStringOrdinalFlags, - ReadOnlySpan<char> source, - ReadOnlySpan<char> value, - bool bIgnoreCase) - { - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert(!source.IsEmpty); - Debug.Assert(!value.IsEmpty); - - fixed (char* pSource = &MemoryMarshal.GetReference(source)) - fixed (char* pValue = &MemoryMarshal.GetReference(value)) - { - int ret = Interop.Kernel32.FindStringOrdinal( - dwFindStringOrdinalFlags, - pSource, - source.Length, - pValue, - value.Length, - bIgnoreCase ? 1 : 0); - return ret; - } - } - - internal static int IndexOfOrdinalCore(string source, string value, int startIndex, int count, bool ignoreCase) - { - Debug.Assert(!GlobalizationMode.Invariant); - - Debug.Assert(source != null); - Debug.Assert(value != null); - - return FindStringOrdinal(FIND_FROMSTART, source, startIndex, count, value, value.Length, ignoreCase); - } - - internal static int IndexOfOrdinalCore(ReadOnlySpan<char> source, ReadOnlySpan<char> value, bool ignoreCase, bool fromBeginning) - { - Debug.Assert(!GlobalizationMode.Invariant); - - Debug.Assert(source.Length != 0); - Debug.Assert(value.Length != 0); - - uint positionFlag = fromBeginning ? (uint)FIND_FROMSTART : FIND_FROMEND; - return FindStringOrdinal(positionFlag, source, value, ignoreCase); - } - - internal static int LastIndexOfOrdinalCore(string source, string value, int startIndex, int count, bool ignoreCase) - { - Debug.Assert(!GlobalizationMode.Invariant); - - Debug.Assert(source != null); - Debug.Assert(value != null); - - return FindStringOrdinal(FIND_FROMEND, source, startIndex - count + 1, count, value, value.Length, ignoreCase); - } - - private unsafe int GetHashCodeOfStringCore(ReadOnlySpan<char> source, CompareOptions options) - { - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0); - - if (source.Length == 0) - { - return 0; - } - - uint flags = LCMAP_SORTKEY | (uint)GetNativeCompareFlags(options); - - fixed (char* pSource = source) - { - int sortKeyLength = Interop.Kernel32.LCMapStringEx(_sortHandle != IntPtr.Zero ? null : _sortName, - flags, - pSource, source.Length /* in chars */, - null, 0, - null, null, _sortHandle); - if (sortKeyLength == 0) - { - throw new ArgumentException(SR.Arg_ExternalException); - } - - // Note in calls to LCMapStringEx below, the input buffer is specified in wchars (and wchar count), - // but the output buffer is specified in bytes (and byte count). This is because when generating - // sort keys, LCMapStringEx treats the output buffer as containing opaque binary data. - // See https://docs.microsoft.com/en-us/windows/desktop/api/winnls/nf-winnls-lcmapstringex. - - byte[]? borrowedArr = null; - Span<byte> span = sortKeyLength <= 512 ? - stackalloc byte[512] : - (borrowedArr = ArrayPool<byte>.Shared.Rent(sortKeyLength)); - - fixed (byte* pSortKey = &MemoryMarshal.GetReference(span)) - { - if (Interop.Kernel32.LCMapStringEx(_sortHandle != IntPtr.Zero ? null : _sortName, - flags, - pSource, source.Length /* in chars */, - pSortKey, sortKeyLength, - null, null, _sortHandle) != sortKeyLength) - { - throw new ArgumentException(SR.Arg_ExternalException); - } - } - - int hash = Marvin.ComputeHash32(span.Slice(0, sortKeyLength), Marvin.DefaultSeed); - - // Return the borrowed array if necessary. - if (borrowedArr != null) - { - ArrayPool<byte>.Shared.Return(borrowedArr); - } - - return hash; - } - } - - private static unsafe int CompareStringOrdinalIgnoreCase(ref char string1, int count1, ref char string2, int count2) - { - Debug.Assert(!GlobalizationMode.Invariant); - - fixed (char* char1 = &string1) - fixed (char* char2 = &string2) - { - // Use the OS to compare and then convert the result to expected value by subtracting 2 - return Interop.Kernel32.CompareStringOrdinal(char1, count1, char2, count2, true) - 2; - } - } - - // TODO https://github.com/dotnet/coreclr/issues/13827: - // This method shouldn't be necessary, as we should be able to just use the overload - // that takes two spans. But due to this issue, that's adding significant overhead. - private unsafe int CompareString(ReadOnlySpan<char> string1, string string2, CompareOptions options) - { - Debug.Assert(string2 != null); - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0); - - string? localeName = _sortHandle != IntPtr.Zero ? null : _sortName; - - fixed (char* pLocaleName = localeName) - fixed (char* pString1 = &MemoryMarshal.GetReference(string1)) - fixed (char* pString2 = &string2.GetRawStringData()) - { - Debug.Assert(pString1 != null); - int result = Interop.Kernel32.CompareStringEx( - pLocaleName, - (uint)GetNativeCompareFlags(options), - pString1, - string1.Length, - pString2, - string2.Length, - null, - null, - _sortHandle); - - if (result == 0) - { - throw new ArgumentException(SR.Arg_ExternalException); - } - - // Map CompareStringEx return value to -1, 0, 1. - return result - 2; - } - } - - private unsafe int CompareString(ReadOnlySpan<char> string1, ReadOnlySpan<char> string2, CompareOptions options) - { - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0); - - string? localeName = _sortHandle != IntPtr.Zero ? null : _sortName; - - fixed (char* pLocaleName = localeName) - fixed (char* pString1 = &MemoryMarshal.GetReference(string1)) - fixed (char* pString2 = &MemoryMarshal.GetReference(string2)) - { - Debug.Assert(pString1 != null); - Debug.Assert(pString2 != null); - int result = Interop.Kernel32.CompareStringEx( - pLocaleName, - (uint)GetNativeCompareFlags(options), - pString1, - string1.Length, - pString2, - string2.Length, - null, - null, - _sortHandle); - - if (result == 0) - { - throw new ArgumentException(SR.Arg_ExternalException); - } - - // Map CompareStringEx return value to -1, 0, 1. - return result - 2; - } - } - - private unsafe int FindString( - uint dwFindNLSStringFlags, - ReadOnlySpan<char> lpStringSource, - ReadOnlySpan<char> lpStringValue, - int* pcchFound) - { - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert(!lpStringSource.IsEmpty); - Debug.Assert(!lpStringValue.IsEmpty); - - string? localeName = _sortHandle != IntPtr.Zero ? null : _sortName; - - fixed (char* pLocaleName = localeName) - fixed (char* pSource = &MemoryMarshal.GetReference(lpStringSource)) - fixed (char* pValue = &MemoryMarshal.GetReference(lpStringValue)) - { - return Interop.Kernel32.FindNLSStringEx( - pLocaleName, - dwFindNLSStringFlags, - pSource, - lpStringSource.Length, - pValue, - lpStringValue.Length, - pcchFound, - null, - null, - _sortHandle); - } - } - - private unsafe int FindString( - uint dwFindNLSStringFlags, - string lpStringSource, - int startSource, - int cchSource, - string lpStringValue, - int startValue, - int cchValue, - int* pcchFound) - { - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert(lpStringSource != null); - Debug.Assert(lpStringValue != null); - - 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.Kernel32.FindNLSStringEx( - pLocaleName, - dwFindNLSStringFlags, - pS, - cchSource, - pV, - cchValue, - pcchFound, - null, - null, - _sortHandle); - } - } - - internal unsafe int IndexOfCore(string source, string target, int startIndex, int count, CompareOptions options, int* matchLengthPtr) - { - Debug.Assert(!GlobalizationMode.Invariant); - - Debug.Assert(source != null); - Debug.Assert(target != null); - Debug.Assert((options & CompareOptions.OrdinalIgnoreCase) == 0); - Debug.Assert((options & CompareOptions.Ordinal) == 0); - - int retValue = FindString(FIND_FROMSTART | (uint)GetNativeCompareFlags(options), source, startIndex, count, - target, 0, target.Length, matchLengthPtr); - if (retValue >= 0) - { - return retValue + startIndex; - } - - return -1; - } - - internal unsafe int IndexOfCore(ReadOnlySpan<char> source, ReadOnlySpan<char> target, CompareOptions options, int* matchLengthPtr, bool fromBeginning) - { - Debug.Assert(!GlobalizationMode.Invariant); - - Debug.Assert(source.Length != 0); - Debug.Assert(target.Length != 0); - Debug.Assert(options == CompareOptions.None || options == CompareOptions.IgnoreCase); - - uint positionFlag = fromBeginning ? (uint)FIND_FROMSTART : FIND_FROMEND; - return FindString(positionFlag | (uint)GetNativeCompareFlags(options), source, target, matchLengthPtr); - } - - private unsafe int LastIndexOfCore(string source, string target, int startIndex, int count, CompareOptions options) - { - Debug.Assert(!GlobalizationMode.Invariant); - - Debug.Assert(!string.IsNullOrEmpty(source)); - Debug.Assert(target != null); - Debug.Assert((options & CompareOptions.OrdinalIgnoreCase) == 0); - - if (target.Length == 0) - return startIndex; - - if ((options & CompareOptions.Ordinal) != 0) - { - return FastLastIndexOfString(source, target, startIndex, count, target.Length); - } - else - { - int retValue = FindString(FIND_FROMEND | (uint)GetNativeCompareFlags(options), source, startIndex - count + 1, - count, target, 0, target.Length, null); - - if (retValue >= 0) - { - return retValue + startIndex - (count - 1); - } - } - - return -1; - } - - private unsafe bool StartsWith(string source, string prefix, CompareOptions options) - { - Debug.Assert(!GlobalizationMode.Invariant); - - Debug.Assert(!string.IsNullOrEmpty(source)); - Debug.Assert(!string.IsNullOrEmpty(prefix)); - Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0); - - return FindString(FIND_STARTSWITH | (uint)GetNativeCompareFlags(options), source, 0, source.Length, - prefix, 0, prefix.Length, null) >= 0; - } - - private unsafe bool StartsWith(ReadOnlySpan<char> source, ReadOnlySpan<char> prefix, CompareOptions options) - { - Debug.Assert(!GlobalizationMode.Invariant); - - Debug.Assert(!source.IsEmpty); - Debug.Assert(!prefix.IsEmpty); - Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0); - - return FindString(FIND_STARTSWITH | (uint)GetNativeCompareFlags(options), source, prefix, null) >= 0; - } - - private unsafe bool EndsWith(string source, string suffix, CompareOptions options) - { - Debug.Assert(!GlobalizationMode.Invariant); - - Debug.Assert(!string.IsNullOrEmpty(source)); - Debug.Assert(!string.IsNullOrEmpty(suffix)); - Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0); - - return FindString(FIND_ENDSWITH | (uint)GetNativeCompareFlags(options), source, 0, source.Length, - suffix, 0, suffix.Length, null) >= 0; - } - - private unsafe bool EndsWith(ReadOnlySpan<char> source, ReadOnlySpan<char> suffix, CompareOptions options) - { - Debug.Assert(!GlobalizationMode.Invariant); - - Debug.Assert(!source.IsEmpty); - Debug.Assert(!suffix.IsEmpty); - Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0); - - return FindString(FIND_ENDSWITH | (uint)GetNativeCompareFlags(options), source, suffix, null) >= 0; - } - - // PAL ends here - [NonSerialized] - private IntPtr _sortHandle; - - private const uint LCMAP_SORTKEY = 0x00000400; - - 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 LastIndexOfOrdinal with ignoreCase = false? - private static unsafe int FastLastIndexOfString(string source, string target, int startIndex, int sourceCount, int targetCount) - { - int retValue = -1; - - int sourceStartIndex = startIndex - sourceCount + 1; - - fixed (char* pSource = source, spTarget = target) - { - char* spSubSource = pSource + sourceStartIndex; - - int endPattern = sourceCount - targetCount; - if (endPattern < 0) - return -1; - - Debug.Assert(target.Length >= 1); - char patternChar0 = spTarget[0]; - for (int ctrSrc = endPattern; 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; - } - } - - return retValue; - } - - private unsafe SortKey CreateSortKey(string source, CompareOptions options) - { - Debug.Assert(!GlobalizationMode.Invariant); - - if (source == null) { throw new ArgumentNullException(nameof(source)); } - - if ((options & ValidSortkeyCtorMaskOffFlags) != 0) - { - throw new ArgumentException(SR.Argument_InvalidFlag, nameof(options)); - } - - byte[] keyData; - if (source.Length == 0) - { - keyData = Array.Empty<byte>(); - } - else - { - uint flags = LCMAP_SORTKEY | (uint)GetNativeCompareFlags(options); - - fixed (char* pSource = source) - { - int sortKeyLength = Interop.Kernel32.LCMapStringEx(_sortHandle != IntPtr.Zero ? null : _sortName, - flags, - pSource, source.Length, - null, 0, - null, null, _sortHandle); - if (sortKeyLength == 0) - { - throw new ArgumentException(SR.Arg_ExternalException); - } - - keyData = new byte[sortKeyLength]; - - fixed (byte* pBytes = keyData) - { - if (Interop.Kernel32.LCMapStringEx(_sortHandle != IntPtr.Zero ? null : _sortName, - flags, - pSource, source.Length, - pBytes, keyData.Length, - null, null, _sortHandle) != sortKeyLength) - { - throw new ArgumentException(SR.Arg_ExternalException); - } - } - } - } - - return new SortKey(Name, source, options, keyData); - } - - private static unsafe bool IsSortable(char* text, int length) - { - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert(text != null); - - return Interop.Kernel32.IsNLSDefinedString(Interop.Kernel32.COMPARE_STRING, 0, IntPtr.Zero, text, length); - } - - 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; } - - Debug.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; - } - - private unsafe SortVersion GetSortVersion() - { - Debug.Assert(!GlobalizationMode.Invariant); - - Interop.Kernel32.NlsVersionInfoEx nlsVersion = default; - nlsVersion.dwNLSVersionInfoSize = sizeof(Interop.Kernel32.NlsVersionInfoEx); - Interop.Kernel32.GetNLSVersionEx(Interop.Kernel32.COMPARE_STRING, _sortName, &nlsVersion); - return new SortVersion( - nlsVersion.dwNLSVersion, - nlsVersion.dwEffectiveId == 0 ? LCID : nlsVersion.dwEffectiveId, - nlsVersion.guidCustomVersion); - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/CompareInfo.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/CompareInfo.cs deleted file mode 100644 index 3b8350f34ea..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/CompareInfo.cs +++ /dev/null @@ -1,1503 +0,0 @@ -// 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; -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Runtime.Serialization; -using System.Text.Unicode; -using Internal.Runtime.CompilerServices; - -namespace System.Globalization -{ - /// <summary> - /// This class implements a set of methods for comparing strings. - /// </summary> - [Serializable] - [TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] - 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); - - // Mask used to check if we have the right flags. - private const CompareOptions ValidSortkeyCtorMaskOffFlags = - ~(CompareOptions.IgnoreCase | CompareOptions.IgnoreSymbols | CompareOptions.IgnoreNonSpace | - CompareOptions.IgnoreWidth | CompareOptions.IgnoreKanaType | CompareOptions.StringSort); - - // Cache the invariant CompareInfo - internal static readonly CompareInfo Invariant = CultureInfo.InvariantCulture.CompareInfo; - - // 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 m_name; // The name used to construct this CompareInfo. Do not rename (binary serialization) - - [NonSerialized] - private string _sortName = null!; // The name that defines our behavior - - [OptionalField(VersionAdded = 3)] - private SortVersion? m_SortVersion; // Do not rename (binary serialization) - - private int culture; // Do not rename (binary serialization). The fields sole purpose is to support Desktop serialization. - - internal CompareInfo(CultureInfo culture) - { - m_name = culture._name; - InitSort(culture); - } - - /// <summary> - /// Get the CompareInfo constructed from the data table in the specified - /// assembly for the specified culture. - /// Warning: The assembly versioning mechanism is dead! - /// </summary> - public static CompareInfo GetCompareInfo(int culture, Assembly assembly) - { - // Parameter checking. - if (assembly == null) - { - throw new ArgumentNullException(nameof(assembly)); - } - if (assembly != typeof(object).Module.Assembly) - { - throw new ArgumentException(SR.Argument_OnlyMscorlib, nameof(assembly)); - } - - return GetCompareInfo(culture); - } - - /// <summary> - /// Get the CompareInfo constructed from the data table in the specified - /// assembly for the specified culture. - /// The purpose of this method is to provide version for CompareInfo tables. - /// </summary> - public static CompareInfo GetCompareInfo(string name, Assembly assembly) - { - if (name == null) - { - throw new ArgumentNullException(nameof(name)); - } - if (assembly == null) - { - throw new ArgumentNullException(nameof(assembly)); - } - if (assembly != typeof(object).Module.Assembly) - { - throw new ArgumentException(SR.Argument_OnlyMscorlib, nameof(assembly)); - } - - return GetCompareInfo(name); - } - - /// <summary> - /// Get the CompareInfo for the specified culture. - /// This method is provided for ease of integration with NLS-based software. - /// </summary> - public static CompareInfo GetCompareInfo(int culture) - { - if (CultureData.IsCustomCultureId(culture)) - { - throw new ArgumentException(SR.Argument_CustomCultureCannotBePassedByNumber, nameof(culture)); - } - - return CultureInfo.GetCultureInfo(culture).CompareInfo; - } - - /// <summary> - /// Get the CompareInfo for the specified culture. - /// </summary> - public static CompareInfo GetCompareInfo(string name) - { - if (name == null) - { - throw new ArgumentNullException(nameof(name)); - } - - return CultureInfo.GetCultureInfo(name).CompareInfo; - } - - public static unsafe bool IsSortable(char ch) - { - if (GlobalizationMode.Invariant) - { - return true; - } - - char* pChar = &ch; - return IsSortable(pChar, 1); - } - - public static unsafe bool IsSortable(string text) - { - if (text == null) - { - throw new ArgumentNullException(nameof(text)); - } - - if (text.Length == 0) - { - return false; - } - - if (GlobalizationMode.Invariant) - { - return true; - } - - fixed (char* pChar = text) - { - return IsSortable(pChar, text.Length); - } - } - - [OnDeserializing] - private void OnDeserializing(StreamingContext ctx) - { - // this becomes null for a brief moment before deserialization - // after serialization is finished it is never null. - m_name = null!; - } - - void IDeserializationCallback.OnDeserialization(object? sender) - { - OnDeserialized(); - } - - [OnDeserialized] - private void OnDeserialized(StreamingContext ctx) - { - OnDeserialized(); - } - - private void OnDeserialized() - { - // If we didn't have a name, use the LCID - if (m_name == null) - { - // From whidbey, didn't have a name - m_name = CultureInfo.GetCultureInfo(culture)._name; - } - else - { - InitSort(CultureInfo.GetCultureInfo(m_name)); - } - } - - [OnSerializing] - private void OnSerializing(StreamingContext ctx) - { - // This is merely for serialization compatibility with Whidbey/Orcas, it can go away when we don't want that compat any more. - culture = CultureInfo.GetCultureInfo(Name).LCID; // This is the lcid of the constructing culture (still have to dereference to get target sort) - Debug.Assert(m_name != null, "CompareInfo.OnSerializing - expected m_name to be set already"); - } - - /// <summary> - /// 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) - /// </summary> - public virtual string Name - { - get - { - Debug.Assert(m_name != null, "CompareInfo.Name Expected _name to be set"); - if (m_name == "zh-CHT" || m_name == "zh-CHS") - { - return m_name; - } - - return _sortName; - } - } - - /// <summary> - /// 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. - /// </summary> - public virtual int Compare(string? string1, string? string2) - { - return Compare(string1, string2, CompareOptions.None); - } - - public 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, nameof(options)); - } - - return string.CompareOrdinal(string1, string2); - } - - if ((options & ValidCompareMaskOffFlags) != 0) - { - throw new ArgumentException(SR.Argument_InvalidFlag, nameof(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; - } - return -1; // null < non-null - } - if (string2 == null) - { - return 1; // non-null > null - } - - if (GlobalizationMode.Invariant) - { - if ((options & CompareOptions.IgnoreCase) != 0) - { - return CompareOrdinalIgnoreCase(string1, string2); - } - - return string.CompareOrdinal(string1, string2); - } - - return CompareString(string1.AsSpan(), string2.AsSpan(), options); - } - - // TODO https://github.com/dotnet/coreclr/issues/13827: - // This method shouldn't be necessary, as we should be able to just use the overload - // that takes two spans. But due to this issue, that's adding significant overhead. - internal int Compare(ReadOnlySpan<char> string1, string? string2, CompareOptions options) - { - if (options == CompareOptions.OrdinalIgnoreCase) - { - return CompareOrdinalIgnoreCase(string1, string2.AsSpan()); - } - - // Verify the options before we do any real comparison. - if ((options & CompareOptions.Ordinal) != 0) - { - if (options != CompareOptions.Ordinal) - { - throw new ArgumentException(SR.Argument_CompareOptionOrdinal, nameof(options)); - } - - return string.CompareOrdinal(string1, string2.AsSpan()); - } - - if ((options & ValidCompareMaskOffFlags) != 0) - { - throw new ArgumentException(SR.Argument_InvalidFlag, nameof(options)); - } - - // null sorts less than any other string. - if (string2 == null) - { - return 1; - } - - if (GlobalizationMode.Invariant) - { - return (options & CompareOptions.IgnoreCase) != 0 ? - CompareOrdinalIgnoreCase(string1, string2.AsSpan()) : - string.CompareOrdinal(string1, string2.AsSpan()); - } - - return CompareString(string1, string2, options); - } - - internal int CompareOptionNone(ReadOnlySpan<char> string1, ReadOnlySpan<char> string2) - { - // Check for empty span or span from a null string - if (string1.Length == 0 || string2.Length == 0) - { - return string1.Length - string2.Length; - } - - return GlobalizationMode.Invariant ? - string.CompareOrdinal(string1, string2) : - CompareString(string1, string2, CompareOptions.None); - } - - internal int CompareOptionIgnoreCase(ReadOnlySpan<char> string1, ReadOnlySpan<char> string2) - { - // Check for empty span or span from a null string - if (string1.Length == 0 || string2.Length == 0) - { - return string1.Length - string2.Length; - } - - return GlobalizationMode.Invariant ? - CompareOrdinalIgnoreCase(string1, string2) : - CompareString(string1, string2, CompareOptions.IgnoreCase); - } - - /// <summary> - /// 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. - /// </summary> - public 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 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 virtual int Compare(string? string1, int offset1, string? string2, int offset2) - { - return Compare(string1, offset1, string2, offset2, 0); - } - - public 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; - } - - if (length1 < 0 || length2 < 0) - { - throw new ArgumentOutOfRangeException((length1 < 0) ? nameof(length1) : nameof(length2), SR.ArgumentOutOfRange_NeedPosNum); - } - if (offset1 < 0 || offset2 < 0) - { - throw new ArgumentOutOfRangeException((offset1 < 0) ? nameof(offset1) : nameof(offset2), SR.ArgumentOutOfRange_NeedPosNum); - } - if (offset1 > (string1 == null ? 0 : string1.Length) - length1) - { - throw new ArgumentOutOfRangeException(nameof(string1), SR.ArgumentOutOfRange_OffsetLength); - } - if (offset2 > (string2 == null ? 0 : string2.Length) - length2) - { - throw new ArgumentOutOfRangeException(nameof(string2), SR.ArgumentOutOfRange_OffsetLength); - } - if ((options & CompareOptions.Ordinal) != 0) - { - if (options != CompareOptions.Ordinal) - { - throw new ArgumentException(SR.Argument_CompareOptionOrdinal, - nameof(options)); - } - } - else if ((options & ValidCompareMaskOffFlags) != 0) - { - throw new ArgumentException(SR.Argument_InvalidFlag, nameof(options)); - } - - if (string1 == null) - { - if (string2 == null) - { - return 0; - } - return -1; - } - if (string2 == null) - { - return 1; - } - - ReadOnlySpan<char> span1 = string1.AsSpan(offset1, length1); - ReadOnlySpan<char> span2 = string2.AsSpan(offset2, length2); - - if (options == CompareOptions.Ordinal) - { - return string.CompareOrdinal(span1, span2); - } - - if (GlobalizationMode.Invariant) - { - if ((options & CompareOptions.IgnoreCase) != 0) - { - return CompareOrdinalIgnoreCase(span1, span2); - } - - return string.CompareOrdinal(span1, span2); - } - - return CompareString(span1, span2, options); - } - - /// <summary> - /// CompareOrdinalIgnoreCase compare two string ordinally 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. - /// </summary> - internal static int CompareOrdinalIgnoreCase(string strA, int indexA, int lengthA, string strB, int indexB, int lengthB) - { - Debug.Assert(indexA + lengthA <= strA.Length); - Debug.Assert(indexB + lengthB <= strB.Length); - return CompareOrdinalIgnoreCase( - ref Unsafe.Add(ref strA.GetRawStringData(), indexA), - lengthA, - ref Unsafe.Add(ref strB.GetRawStringData(), indexB), - lengthB); - } - - internal static int CompareOrdinalIgnoreCase(ReadOnlySpan<char> strA, ReadOnlySpan<char> strB) - { - return CompareOrdinalIgnoreCase(ref MemoryMarshal.GetReference(strA), strA.Length, ref MemoryMarshal.GetReference(strB), strB.Length); - } - - internal static int CompareOrdinalIgnoreCase(string strA, string strB) - { - return CompareOrdinalIgnoreCase(ref strA.GetRawStringData(), strA.Length, ref strB.GetRawStringData(), strB.Length); - } - - internal static int CompareOrdinalIgnoreCase(ref char strA, int lengthA, ref char strB, int lengthB) - { - int length = Math.Min(lengthA, lengthB); - int range = length; - - ref char charA = ref strA; - ref char charB = ref strB; - - // in InvariantMode we support all range and not only the ascii characters. - char maxChar = (GlobalizationMode.Invariant ? (char)0xFFFF : (char)0x7F); - - while (length != 0 && charA <= maxChar && charB <= maxChar) - { - // Ordinal equals or lowercase equals if the result ends up in the a-z range - if (charA == charB || - ((charA | 0x20) == (charB | 0x20) && - (uint)((charA | 0x20) - 'a') <= (uint)('z' - 'a'))) - { - length--; - charA = ref Unsafe.Add(ref charA, 1); - charB = ref Unsafe.Add(ref charB, 1); - } - else - { - int currentA = charA; - int currentB = charB; - - // Uppercase both chars if needed - if ((uint)(charA - 'a') <= 'z' - 'a') - { - currentA -= 0x20; - } - if ((uint)(charB - 'a') <= 'z' - 'a') - { - currentB -= 0x20; - } - - // Return the (case-insensitive) difference between them. - return currentA - currentB; - } - } - - if (length == 0) - { - return lengthA - lengthB; - } - - Debug.Assert(!GlobalizationMode.Invariant); - - range -= length; - - return CompareStringOrdinalIgnoreCase(ref charA, lengthA - range, ref charB, lengthB - range); - } - - internal static bool EqualsOrdinalIgnoreCase(ref char charA, ref char charB, int length) - { - IntPtr byteOffset = IntPtr.Zero; - -#if BIT64 - // Read 4 chars (64 bits) at a time from each string - while ((uint)length >= 4) - { - ulong valueA = Unsafe.ReadUnaligned<ulong>(ref Unsafe.As<char, byte>(ref Unsafe.AddByteOffset(ref charA, byteOffset))); - ulong valueB = Unsafe.ReadUnaligned<ulong>(ref Unsafe.As<char, byte>(ref Unsafe.AddByteOffset(ref charB, byteOffset))); - - // A 32-bit test - even with the bit-twiddling here - is more efficient than a 64-bit test. - ulong temp = valueA | valueB; - if (!Utf16Utility.AllCharsInUInt32AreAscii((uint)temp | (uint)(temp >> 32))) - { - goto NonAscii; // one of the inputs contains non-ASCII data - } - - // Generally, the caller has likely performed a first-pass check that the input strings - // are likely equal. Consider a dictionary which computes the hash code of its key before - // performing a proper deep equality check of the string contents. We want to optimize for - // the case where the equality check is likely to succeed, which means that we want to avoid - // branching within this loop unless we're about to exit the loop, either due to failure or - // due to us running out of input data. - - if (!Utf16Utility.UInt64OrdinalIgnoreCaseAscii(valueA, valueB)) - { - return false; - } - - byteOffset += 8; - length -= 4; - } -#endif - - // Read 2 chars (32 bits) at a time from each string -#if BIT64 - if ((uint)length >= 2) -#else - while ((uint)length >= 2) -#endif - { - uint valueA = Unsafe.ReadUnaligned<uint>(ref Unsafe.As<char, byte>(ref Unsafe.AddByteOffset(ref charA, byteOffset))); - uint valueB = Unsafe.ReadUnaligned<uint>(ref Unsafe.As<char, byte>(ref Unsafe.AddByteOffset(ref charB, byteOffset))); - - if (!Utf16Utility.AllCharsInUInt32AreAscii(valueA | valueB)) - { - goto NonAscii; // one of the inputs contains non-ASCII data - } - - // Generally, the caller has likely performed a first-pass check that the input strings - // are likely equal. Consider a dictionary which computes the hash code of its key before - // performing a proper deep equality check of the string contents. We want to optimize for - // the case where the equality check is likely to succeed, which means that we want to avoid - // branching within this loop unless we're about to exit the loop, either due to failure or - // due to us running out of input data. - - if (!Utf16Utility.UInt32OrdinalIgnoreCaseAscii(valueA, valueB)) - { - return false; - } - - byteOffset += 4; - length -= 2; - } - - if (length != 0) - { - Debug.Assert(length == 1); - - uint valueA = Unsafe.AddByteOffset(ref charA, byteOffset); - uint valueB = Unsafe.AddByteOffset(ref charB, byteOffset); - - if ((valueA | valueB) > 0x7Fu) - { - goto NonAscii; // one of the inputs contains non-ASCII data - } - - if (valueA == valueB) - { - return true; // exact match - } - - valueA |= 0x20u; - if ((uint)(valueA - 'a') > (uint)('z' - 'a')) - { - return false; // not exact match, and first input isn't in [A-Za-z] - } - - // The ternary operator below seems redundant but helps RyuJIT generate more optimal code. - // See https://github.com/dotnet/coreclr/issues/914. - return (valueA == (valueB | 0x20u)) ? true : false; - } - - Debug.Assert(length == 0); - return true; - - NonAscii: - // The non-ASCII case is factored out into its own helper method so that the JIT - // doesn't need to emit a complex prolog for its caller (this method). - return EqualsOrdinalIgnoreCaseNonAscii(ref Unsafe.AddByteOffset(ref charA, byteOffset), ref Unsafe.AddByteOffset(ref charB, byteOffset), length); - } - - private static bool EqualsOrdinalIgnoreCaseNonAscii(ref char charA, ref char charB, int length) - { - if (!GlobalizationMode.Invariant) - { - return CompareStringOrdinalIgnoreCase(ref charA, length, ref charB, length) == 0; - } - else - { - // If we don't have localization tables to consult, we'll still perform a case-insensitive - // check for ASCII characters, but if we see anything outside the ASCII range we'll immediately - // fail if it doesn't have true bitwise equality. - - IntPtr byteOffset = IntPtr.Zero; - while (length != 0) - { - // Ordinal equals or lowercase equals if the result ends up in the a-z range - uint valueA = Unsafe.AddByteOffset(ref charA, byteOffset); - uint valueB = Unsafe.AddByteOffset(ref charB, byteOffset); - - if (valueA == valueB || - ((valueA | 0x20) == (valueB | 0x20) && - (uint)((valueA | 0x20) - 'a') <= (uint)('z' - 'a'))) - { - byteOffset += 2; - length--; - } - else - { - return false; - } - } - - return true; - } - } - - /// <summary> - /// Determines whether prefix is a prefix of string. If prefix equals - /// string.Empty, true is returned. - /// </summary> - public virtual bool IsPrefix(string source, string prefix, CompareOptions options) - { - if (source == null) - { - throw new ArgumentNullException(nameof(source)); - } - if (prefix == null) - { - throw new ArgumentNullException(nameof(prefix)); - } - - 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, nameof(options)); - } - - if (GlobalizationMode.Invariant) - { - return source.StartsWith(prefix, (options & CompareOptions.IgnoreCase) != 0 ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal); - } - - return StartsWith(source, prefix, options); - } - - internal bool IsPrefix(ReadOnlySpan<char> source, ReadOnlySpan<char> prefix, CompareOptions options) - { - Debug.Assert(prefix.Length != 0); - Debug.Assert(source.Length != 0); - Debug.Assert((options & ValidIndexMaskOffFlags) == 0); - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0); - - return StartsWith(source, prefix, options); - } - - public virtual bool IsPrefix(string source, string prefix) - { - return IsPrefix(source, prefix, 0); - } - - /// <summary> - /// Determines whether suffix is a suffix of string. If suffix equals - /// string.Empty, true is returned. - /// </summary> - public virtual bool IsSuffix(string source, string suffix, CompareOptions options) - { - if (source == null) - { - throw new ArgumentNullException(nameof(source)); - } - if (suffix == null) - { - throw new ArgumentNullException(nameof(suffix)); - } - - 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, nameof(options)); - } - - if (GlobalizationMode.Invariant) - { - return source.EndsWith(suffix, (options & CompareOptions.IgnoreCase) != 0 ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal); - } - - return EndsWith(source, suffix, options); - } - - internal bool IsSuffix(ReadOnlySpan<char> source, ReadOnlySpan<char> suffix, CompareOptions options) - { - Debug.Assert(suffix.Length != 0); - Debug.Assert(source.Length != 0); - Debug.Assert((options & ValidIndexMaskOffFlags) == 0); - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0); - - return EndsWith(source, suffix, options); - } - - public virtual bool IsSuffix(string source, string suffix) - { - return IsSuffix(source, suffix, 0); - } - - /// <summary> - /// 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. - /// </summary> - public virtual int IndexOf(string source, char value) - { - if (source == null) - { - throw new ArgumentNullException(nameof(source)); - } - - return IndexOf(source, value, 0, source.Length, CompareOptions.None); - } - - public virtual int IndexOf(string source, string value) - { - if (source == null) - throw new ArgumentNullException(nameof(source)); - - return IndexOf(source, value, 0, source.Length, CompareOptions.None); - } - - public virtual int IndexOf(string source, char value, CompareOptions options) - { - if (source == null) - { - throw new ArgumentNullException(nameof(source)); - } - - return IndexOf(source, value, 0, source.Length, options); - } - - public virtual int IndexOf(string source, string value, CompareOptions options) - { - if (source == null) - { - throw new ArgumentNullException(nameof(source)); - } - - return IndexOf(source, value, 0, source.Length, options); - } - - public virtual int IndexOf(string source, char value, int startIndex) - { - if (source == null) - { - throw new ArgumentNullException(nameof(source)); - } - - return IndexOf(source, value, startIndex, source.Length - startIndex, CompareOptions.None); - } - - public virtual int IndexOf(string source, string value, int startIndex) - { - if (source == null) - throw new ArgumentNullException(nameof(source)); - - return IndexOf(source, value, startIndex, source.Length - startIndex, CompareOptions.None); - } - - public virtual int IndexOf(string source, char value, int startIndex, CompareOptions options) - { - if (source == null) - { - throw new ArgumentNullException(nameof(source)); - } - - return IndexOf(source, value, startIndex, source.Length - startIndex, options); - } - - public virtual int IndexOf(string source, string value, int startIndex, CompareOptions options) - { - if (source == null) - { - throw new ArgumentNullException(nameof(source)); - } - - return IndexOf(source, value, startIndex, source.Length - startIndex, options); - } - - public virtual int IndexOf(string source, char value, int startIndex, int count) - { - return IndexOf(source, value, startIndex, count, CompareOptions.None); - } - - public virtual int IndexOf(string source, string value, int startIndex, int count) - { - return IndexOf(source, value, startIndex, count, CompareOptions.None); - } - - public virtual unsafe int IndexOf(string source, char value, int startIndex, int count, CompareOptions options) - { - if (source == null) - { - throw new ArgumentNullException(nameof(source)); - } - if (startIndex < 0 || startIndex > source.Length) - { - throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index); - } - if (count < 0 || startIndex > source.Length - count) - { - throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_Count); - } - - if (source.Length == 0) - { - return -1; - } - - // 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, nameof(options)); - } - - return IndexOf(source, char.ToString(value), startIndex, count, options, null); - } - - public virtual unsafe int IndexOf(string source, string value, int startIndex, int count, CompareOptions options) - { - if (source == null) - { - throw new ArgumentNullException(nameof(source)); - } - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - if (startIndex > source.Length) - { - throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index); - } - - // 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(nameof(startIndex), SR.ArgumentOutOfRange_Index); - } - - if (count < 0 || startIndex > source.Length - count) - { - throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_Count); - } - - // 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, nameof(options)); - } - - return IndexOf(source, value, startIndex, count, options, null); - } - - internal int IndexOfOrdinalIgnoreCase(ReadOnlySpan<char> source, ReadOnlySpan<char> value) - { - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert(!source.IsEmpty); - Debug.Assert(!value.IsEmpty); - - return IndexOfOrdinalCore(source, value, ignoreCase: true, fromBeginning: true); - } - - internal int LastIndexOfOrdinal(ReadOnlySpan<char> source, ReadOnlySpan<char> value, bool ignoreCase) - { - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert(!source.IsEmpty); - Debug.Assert(!value.IsEmpty); - return IndexOfOrdinalCore(source, value, ignoreCase, fromBeginning: false); - } - - internal unsafe int IndexOf(ReadOnlySpan<char> source, ReadOnlySpan<char> value, CompareOptions options) - { - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert(!source.IsEmpty); - Debug.Assert(!value.IsEmpty); - return IndexOfCore(source, value, options, null, fromBeginning: true); - } - - internal unsafe int LastIndexOf(ReadOnlySpan<char> source, ReadOnlySpan<char> value, CompareOptions options) - { - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert(!source.IsEmpty); - Debug.Assert(!value.IsEmpty); - return IndexOfCore(source, value, options, null, fromBeginning: false); - } - - /// <summary> - /// The following IndexOf overload is mainly used by String.Replace. This overload assumes the parameters are already validated - /// and the caller is passing a valid matchLengthPtr pointer. - /// </summary> - internal unsafe int IndexOf(string source, string value, int startIndex, int count, CompareOptions options, int* matchLengthPtr, bool fromBeginning = true) - { - Debug.Assert(source != null); - Debug.Assert(value != null); - Debug.Assert(startIndex >= 0); - - if (matchLengthPtr != null) - { - *matchLengthPtr = 0; - } - - if (value.Length == 0) - { - return startIndex; - } - - if (startIndex >= source.Length) - { - return -1; - } - - if (options == CompareOptions.OrdinalIgnoreCase) - { - int res; - if (fromBeginning) - { - res = IndexOfOrdinal(source, value, startIndex, count, ignoreCase: true); - } - else - { - res = LastIndexOfOrdinal(source, value, startIndex, count, ignoreCase: true); - } - - if (res >= 0 && matchLengthPtr != null) - { - *matchLengthPtr = value.Length; - } - return res; - } - - if (GlobalizationMode.Invariant) - { - bool ignoreCase = (options & (CompareOptions.IgnoreCase | CompareOptions.OrdinalIgnoreCase)) != 0; - int res; - - if (fromBeginning) - { - res = IndexOfOrdinal(source, value, startIndex, count, ignoreCase); - } - else - { - res = LastIndexOfOrdinal(source, value, startIndex, count, ignoreCase); - } - - if (res >= 0 && matchLengthPtr != null) - { - *matchLengthPtr = value.Length; - } - return res; - } - - if (options == CompareOptions.Ordinal) - { - int retValue; - - if (fromBeginning) - { - retValue = SpanHelpers.IndexOf( - ref Unsafe.Add(ref source.GetRawStringData(), startIndex), - count, - ref value.GetRawStringData(), - value.Length); - } - else - { - retValue = SpanHelpers.LastIndexOf( - ref Unsafe.Add(ref source.GetRawStringData(), startIndex), - count, - ref value.GetRawStringData(), - value.Length); - } - - if (retValue >= 0) - { - retValue += startIndex; - if (matchLengthPtr != null) - { - *matchLengthPtr = value.Length; - } - } - - return retValue; - } - else - { - if (fromBeginning) - { - // Call the string-based overload, as it special-cases IsFastSort as a perf optimization. - return IndexOfCore(source, value, startIndex, count, options, matchLengthPtr); - } - else - { - return IndexOfCore(source.AsSpan(startIndex, count), value, options, matchLengthPtr, fromBeginning: false); - } - } - } - - internal static int IndexOfOrdinal(string source, string value, int startIndex, int count, bool ignoreCase) - { - if (!ignoreCase) - { - int result = SpanHelpers.IndexOf( - ref Unsafe.Add(ref source.GetRawStringData(), startIndex), - count, - ref value.GetRawStringData(), - value.Length); - - return (result >= 0 ? startIndex : 0) + result; - } - - if (GlobalizationMode.Invariant) - { - return InvariantIndexOf(source, value, startIndex, count, ignoreCase); - } - - return IndexOfOrdinalCore(source, value, startIndex, count, ignoreCase); - } - - /// <summary> - /// 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. - /// </summary> - public virtual int LastIndexOf(string source, char value) - { - if (source == null) - { - throw new ArgumentNullException(nameof(source)); - } - - // 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(nameof(source)); - } - - // 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(nameof(source)); - } - - // 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 virtual int LastIndexOf(string source, string value, CompareOptions options) - { - if (source == null) - { - throw new ArgumentNullException(nameof(source)); - } - - // 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 virtual int LastIndexOf(string source, char value, int startIndex) - { - return LastIndexOf(source, value, startIndex, startIndex + 1, CompareOptions.None); - } - - public virtual int LastIndexOf(string source, string value, int startIndex) - { - return LastIndexOf(source, value, startIndex, startIndex + 1, CompareOptions.None); - } - - public virtual int LastIndexOf(string source, char value, int startIndex, CompareOptions options) - { - return LastIndexOf(source, value, startIndex, startIndex + 1, options); - } - - public virtual int LastIndexOf(string source, string value, int startIndex, CompareOptions options) - { - return LastIndexOf(source, value, startIndex, startIndex + 1, options); - } - - public virtual int LastIndexOf(string source, char value, int startIndex, int count) - { - return LastIndexOf(source, value, startIndex, count, CompareOptions.None); - } - - public virtual int LastIndexOf(string source, string value, int startIndex, int count) - { - return LastIndexOf(source, value, startIndex, count, CompareOptions.None); - } - - public virtual int LastIndexOf(string source, char value, int startIndex, int count, CompareOptions options) - { - if (source == null) - { - throw new ArgumentNullException(nameof(source)); - } - // 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, nameof(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(nameof(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(nameof(count), SR.ArgumentOutOfRange_Count); - } - - if (options == CompareOptions.OrdinalIgnoreCase) - { - return source.LastIndexOf(value.ToString(), startIndex, count, StringComparison.OrdinalIgnoreCase); - } - - if (GlobalizationMode.Invariant) - { - return InvariantLastIndexOf(source, char.ToString(value), startIndex, count, (options & (CompareOptions.IgnoreCase | CompareOptions.OrdinalIgnoreCase)) != 0); - } - - return LastIndexOfCore(source, value.ToString(), startIndex, count, options); - } - - public virtual int LastIndexOf(string source, string value, int startIndex, int count, CompareOptions options) - { - if (source == null) - { - throw new ArgumentNullException(nameof(source)); - } - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - - // 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, nameof(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(nameof(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(nameof(count), SR.ArgumentOutOfRange_Count); - } - - if (options == CompareOptions.OrdinalIgnoreCase) - { - return LastIndexOfOrdinal(source, value, startIndex, count, ignoreCase: true); - } - - if (GlobalizationMode.Invariant) - return InvariantLastIndexOf(source, value, startIndex, count, (options & (CompareOptions.IgnoreCase | CompareOptions.OrdinalIgnoreCase)) != 0); - - return LastIndexOfCore(source, value, startIndex, count, options); - } - - internal static int LastIndexOfOrdinal(string source, string value, int startIndex, int count, bool ignoreCase) - { - if (GlobalizationMode.Invariant) - { - return InvariantLastIndexOf(source, value, startIndex, count, ignoreCase); - } - - return LastIndexOfOrdinalCore(source, value, startIndex, count, ignoreCase); - } - - /// <summary> - /// Gets the SortKey for the given string with the given options. - /// </summary> - public virtual SortKey GetSortKey(string source, CompareOptions options) - { - if (GlobalizationMode.Invariant) - { - return InvariantCreateSortKey(source, options); - } - - return CreateSortKey(source, options); - } - - public virtual SortKey GetSortKey(string source) - { - if (GlobalizationMode.Invariant) - { - return InvariantCreateSortKey(source, CompareOptions.None); - } - - return CreateSortKey(source, CompareOptions.None); - } - - public override bool Equals(object? value) - { - return value is CompareInfo otherCompareInfo - && Name == otherCompareInfo.Name; - } - - public override int GetHashCode() => Name.GetHashCode(); - - /// <summary> - /// 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) - /// </summary> - internal int GetHashCodeOfString(string source, CompareOptions options) - { - if (source == null) - { - throw new ArgumentNullException(nameof(source)); - } - if ((options & ValidHashCodeOfStringMaskOffFlags) == 0) - { - // No unsupported flags are set - continue on with the regular logic - if (GlobalizationMode.Invariant) - { - return ((options & CompareOptions.IgnoreCase) != 0) ? source.GetHashCodeOrdinalIgnoreCase() : source.GetHashCode(); - } - - return GetHashCodeOfStringCore(source, options); - } - else if (options == CompareOptions.Ordinal) - { - // We allow Ordinal in isolation - return source.GetHashCode(); - } - else if (options == CompareOptions.OrdinalIgnoreCase) - { - // We allow OrdinalIgnoreCase in isolation - return source.GetHashCodeOrdinalIgnoreCase(); - } - else - { - // Unsupported combination of flags specified - throw new ArgumentException(SR.Argument_InvalidFlag, nameof(options)); - } - } - - public virtual int GetHashCode(string source, CompareOptions options) - { - // virtual method delegates to non-virtual method - return GetHashCodeOfString(source, options); - } - - public int GetHashCode(ReadOnlySpan<char> source, CompareOptions options) - { - if ((options & ValidHashCodeOfStringMaskOffFlags) == 0) - { - // No unsupported flags are set - continue on with the regular logic - if (GlobalizationMode.Invariant) - { - return ((options & CompareOptions.IgnoreCase) != 0) ? string.GetHashCodeOrdinalIgnoreCase(source) : string.GetHashCode(source); - } - - return GetHashCodeOfStringCore(source, options); - } - else if (options == CompareOptions.Ordinal) - { - // We allow Ordinal in isolation - return string.GetHashCode(source); - } - else if (options == CompareOptions.OrdinalIgnoreCase) - { - // We allow OrdinalIgnoreCase in isolation - return string.GetHashCodeOrdinalIgnoreCase(source); - } - else - { - // Unsupported combination of flags specified - throw new ArgumentException(SR.Argument_InvalidFlag, nameof(options)); - } - } - - public override string ToString() => "CompareInfo - " + Name; - - public SortVersion Version - { - get - { - if (m_SortVersion == null) - { - if (GlobalizationMode.Invariant) - { - m_SortVersion = new SortVersion(0, CultureInfo.LOCALE_INVARIANT, new Guid(0, 0, 0, 0, 0, 0, 0, - (byte)(CultureInfo.LOCALE_INVARIANT >> 24), - (byte)((CultureInfo.LOCALE_INVARIANT & 0x00FF0000) >> 16), - (byte)((CultureInfo.LOCALE_INVARIANT & 0x0000FF00) >> 8), - (byte)(CultureInfo.LOCALE_INVARIANT & 0xFF))); - } - else - { - m_SortVersion = GetSortVersion(); - } - } - - return m_SortVersion; - } - } - - public int LCID => CultureInfo.GetCultureInfo(Name).LCID; - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/CompareOptions.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/CompareOptions.cs deleted file mode 100644 index 366ece403c0..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/CompareOptions.cs +++ /dev/null @@ -1,20 +0,0 @@ -// 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 -{ - [Flags] - public enum CompareOptions - { - None = 0x00000000, - IgnoreCase = 0x00000001, - IgnoreNonSpace = 0x00000002, - IgnoreSymbols = 0x00000004, - IgnoreKanaType = 0x00000008, - IgnoreWidth = 0x00000010, - OrdinalIgnoreCase = 0x10000000, // This flag can not be used with other flags. - StringSort = 0x20000000, - Ordinal = 0x40000000, // This flag can not be used with other flags. - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/CultureData.Unix.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/CultureData.Unix.cs deleted file mode 100644 index cbd42e62fd6..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/CultureData.Unix.cs +++ /dev/null @@ -1,421 +0,0 @@ -// 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; -using System.Runtime.InteropServices; -using System.Security; -using System.Text; - -namespace System.Globalization -{ - internal partial class CultureData - { - // ICU constants - private const int ICU_ULOC_KEYWORD_AND_VALUES_CAPACITY = 100; // max size of keyword or value - private const int ICU_ULOC_FULLNAME_CAPACITY = 157; // max size of locale name - private 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> - private unsafe bool InitCultureData() - { - Debug.Assert(_sRealName != null); - - Debug.Assert(!GlobalizationMode.Invariant); - - 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 - ReadOnlySpan<char> alternateSortName = default; - int index = realNameBuffer.IndexOf('_'); - if (index > 0) - { - if (index >= (realNameBuffer.Length - 1) // must have characters after _ - || realNameBuffer.IndexOf('_', index + 1) >= 0) // only one _ allowed - { - return false; // fail - } - alternateSortName = realNameBuffer.AsSpan(index + 1); - realNameBuffer = string.Concat(realNameBuffer.AsSpan(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 _ - Debug.Assert(_sWindowsName != null); - index = _sWindowsName.IndexOf(ICU_COLLATION_KEYWORD, StringComparison.Ordinal); - if (index >= 0) - { - _sName = string.Concat(_sWindowsName.AsSpan(0, index), "_", alternateSortName); - } - else - { - _sName = _sWindowsName; - } - _sRealName = _sName; - - _iLanguage = LCID; - if (_iLanguage == 0) - { - _iLanguage = CultureInfo.LOCALE_CUSTOM_UNSPECIFIED; - } - - _bNeutral = TwoLetterISOCountryName.Length == 0; - - _sSpecificCulture = _bNeutral ? LocaleData.GetSpecificCultureName(_sRealName) : _sRealName; - - // Remove the sort from sName unless custom culture - if (index > 0 && !_bNeutral && !IsCustomCultureId(_iLanguage)) - { - _sName = _sWindowsName.Substring(0, index); - } - return true; - } - - internal static unsafe bool GetLocaleName(string localeName, out string? windowsName) - { - // Get the locale name from ICU - char* buffer = stackalloc char[ICU_ULOC_FULLNAME_CAPACITY]; - if (!Interop.Globalization.GetLocaleName(localeName, buffer, ICU_ULOC_FULLNAME_CAPACITY)) - { - windowsName = null; - return false; // fail - } - - // Success - use the locale name returned which may be different than realNameBuffer (casing) - windowsName = new string(buffer); // the name passed to subsequent ICU calls - return true; - } - - internal static unsafe bool GetDefaultLocaleName(out string? windowsName) - { - // Get the default (system) locale name from ICU - char* buffer = stackalloc char[ICU_ULOC_FULLNAME_CAPACITY]; - if (!Interop.Globalization.GetDefaultLocaleName(buffer, ICU_ULOC_FULLNAME_CAPACITY)) - { - windowsName = null; - return false; // fail - } - - // Success - use the locale name returned which may be different than realNameBuffer (casing) - windowsName = new string(buffer); // the name passed to subsequent ICU calls - return true; - } - - private string GetLocaleInfo(LocaleStringData type) - { - Debug.Assert(!GlobalizationMode.Invariant); - - Debug.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. - private unsafe string GetLocaleInfo(string localeName, LocaleStringData type) - { - Debug.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); - } - - char* buffer = stackalloc char[ICU_ULOC_KEYWORD_AND_VALUES_CAPACITY]; - bool result = Interop.Globalization.GetLocaleInfoString(localeName, (uint)type, buffer, ICU_ULOC_KEYWORD_AND_VALUES_CAPACITY); - if (!result) - { - // Failed, just use empty string - Debug.Fail("[CultureData.GetLocaleInfo(LocaleStringData)] Failed"); - return string.Empty; - } - - return new string(buffer); - } - - private int GetLocaleInfo(LocaleNumberData type) - { - Debug.Assert(!GlobalizationMode.Invariant); - - Debug.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.Globalization.GetLocaleInfoInt(_sWindowsName, (uint)type, ref value); - if (!result) - { - // Failed, just use 0 - Debug.Fail("[CultureData.GetLocaleInfo(LocaleNumberData)] failed"); - } - - return value; - } - - private int[] GetLocaleInfo(LocaleGroupingData type) - { - Debug.Assert(_sWindowsName != null, "[CultureData.GetLocaleInfo(LocaleGroupingData)] Expected _sWindowsName to be populated already"); - - int primaryGroupingSize = 0; - int secondaryGroupingSize = 0; - bool result = Interop.Globalization.GetLocaleInfoGroupingSizes(_sWindowsName, (uint)type, ref primaryGroupingSize, ref secondaryGroupingSize); - if (!result) - { - Debug.Fail("[CultureData.GetLocaleInfo(LocaleGroupingData type)] failed"); - } - - if (secondaryGroupingSize == 0) - { - return new int[] { primaryGroupingSize }; - } - - return new int[] { primaryGroupingSize, secondaryGroupingSize }; - } - - private string GetTimeFormatString() => GetTimeFormatString(shortFormat: false); - - private unsafe string GetTimeFormatString(bool shortFormat) - { - Debug.Assert(_sWindowsName != null, "[CultureData.GetTimeFormatString(bool shortFormat)] Expected _sWindowsName to be populated already"); - - char* buffer = stackalloc char[ICU_ULOC_KEYWORD_AND_VALUES_CAPACITY]; - - bool result = Interop.Globalization.GetLocaleTimeFormat(_sWindowsName, shortFormat, buffer, ICU_ULOC_KEYWORD_AND_VALUES_CAPACITY); - if (!result) - { - // Failed, just use empty string - Debug.Fail("[CultureData.GetTimeFormatString(bool shortFormat)] Failed"); - return string.Empty; - } - - var span = new ReadOnlySpan<char>(buffer, ICU_ULOC_KEYWORD_AND_VALUES_CAPACITY); - return ConvertIcuTimeFormatString(span.Slice(0, span.IndexOf('\0'))); - } - - private int GetFirstDayOfWeek() => 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)._cultureData.GetLocaleInfo(cultureName, LocaleStringData.LocalizedDisplayName); - } - - private static string? GetRegionDisplayName() - { - // use the fallback which is to return NativeName - return null; - } - - private static string ConvertIcuTimeFormatString(ReadOnlySpan<char> icuFormatString) - { - Debug.Assert(icuFormatString.Length < ICU_ULOC_FULLNAME_CAPACITY); - Span<char> result = stackalloc char[ICU_ULOC_FULLNAME_CAPACITY]; - - bool amPmAdded = false; - int resultPos = 0; - - for (int i = 0; i < icuFormatString.Length; i++) - { - switch (icuFormatString[i]) - { - case '\'': - result[resultPos++] = icuFormatString[i++]; - while (i < icuFormatString.Length) - { - char current = icuFormatString[i++]; - result[resultPos++] = current; - if (current == '\'') - { - break; - } - } - break; - - case ':': - case '.': - case 'H': - case 'h': - case 'm': - case 's': - result[resultPos++] = icuFormatString[i]; - break; - - case ' ': - case '\u00A0': - // Convert nonbreaking spaces into regular spaces - result[resultPos++] = ' '; - break; - - case 'a': // AM/PM - if (!amPmAdded) - { - amPmAdded = true; - result[resultPos++] = 't'; - result[resultPos++] = 't'; - } - break; - - } - } - - return result.Slice(0, resultPos).ToString(); - } - - private static string? LCIDToLocaleName(int culture) - { - Debug.Assert(!GlobalizationMode.Invariant); - - return LocaleData.LCIDToLocaleName(culture); - } - - private static int LocaleNameToLCID(string cultureName) - { - Debug.Assert(!GlobalizationMode.Invariant); - - int lcid = LocaleData.GetLocaleDataNumericPart(cultureName, LocaleDataParts.Lcid); - return lcid == -1 ? CultureInfo.LOCALE_CUSTOM_UNSPECIFIED : lcid; - } - - private static int GetAnsiCodePage(string cultureName) - { - int ansiCodePage = LocaleData.GetLocaleDataNumericPart(cultureName, LocaleDataParts.AnsiCodePage); - return ansiCodePage == -1 ? CultureData.Invariant.ANSICodePage : ansiCodePage; - } - - private static int GetOemCodePage(string cultureName) - { - int oemCodePage = LocaleData.GetLocaleDataNumericPart(cultureName, LocaleDataParts.OemCodePage); - return oemCodePage == -1 ? CultureData.Invariant.OEMCodePage : oemCodePage; - } - - private static int GetMacCodePage(string cultureName) - { - int macCodePage = LocaleData.GetLocaleDataNumericPart(cultureName, LocaleDataParts.MacCodePage); - return macCodePage == -1 ? CultureData.Invariant.MacCodePage : macCodePage; - } - - private static int GetEbcdicCodePage(string cultureName) - { - int ebcdicCodePage = LocaleData.GetLocaleDataNumericPart(cultureName, LocaleDataParts.EbcdicCodePage); - return ebcdicCodePage == -1 ? CultureData.Invariant.EBCDICCodePage : ebcdicCodePage; - } - - private static int GetGeoId(string cultureName) - { - int geoId = LocaleData.GetLocaleDataNumericPart(cultureName, LocaleDataParts.GeoId); - return geoId == -1 ? CultureData.Invariant.GeoId : geoId; - } - - private static int GetDigitSubstitution(string cultureName) - { - int digitSubstitution = LocaleData.GetLocaleDataNumericPart(cultureName, LocaleDataParts.DigitSubstitution); - return digitSubstitution == -1 ? (int) DigitShapes.None : digitSubstitution; - } - - private static string GetThreeLetterWindowsLanguageName(string cultureName) - { - return LocaleData.GetThreeLetterWindowsLanguageName(cultureName) ?? "ZZZ" /* default lang name */; - } - - private static CultureInfo[] EnumCultures(CultureTypes types) - { - Debug.Assert(!GlobalizationMode.Invariant); - - if ((types & (CultureTypes.NeutralCultures | CultureTypes.SpecificCultures)) == 0) - { - return Array.Empty<CultureInfo>(); - } - - int bufferLength = Interop.Globalization.GetLocales(null, 0); - if (bufferLength <= 0) - { - return Array.Empty<CultureInfo>(); - } - - char [] chars = new char[bufferLength]; - - bufferLength = Interop.Globalization.GetLocales(chars, bufferLength); - if (bufferLength <= 0) - { - return Array.Empty<CultureInfo>(); - } - - bool enumNeutrals = (types & CultureTypes.NeutralCultures) != 0; - bool enumSpecificss = (types & CultureTypes.SpecificCultures) != 0; - - List<CultureInfo> list = new List<CultureInfo>(); - if (enumNeutrals) - { - list.Add(CultureInfo.InvariantCulture); - } - - int index = 0; - while (index < bufferLength) - { - int length = (int) chars[index++]; - if (index + length <= bufferLength) - { - CultureInfo ci = CultureInfo.GetCultureInfo(new string(chars, index, length)); - if ((enumNeutrals && ci.IsNeutralCulture) || (enumSpecificss && !ci.IsNeutralCulture)) - { - list.Add(ci); - } - } - - index += length; - } - - return list.ToArray(); - } - - private static string GetConsoleFallbackName(string cultureName) - { - return LocaleData.GetConsoleUICulture(cultureName); - } - - internal bool IsWin32Installed => false; - - internal bool IsReplacementCulture => false; - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/CultureData.Windows.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/CultureData.Windows.cs deleted file mode 100644 index b8ae4083724..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/CultureData.Windows.cs +++ /dev/null @@ -1,718 +0,0 @@ -// 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; -using System.Diagnostics.CodeAnalysis; -using System.Text; -using Internal.Runtime.CompilerServices; - -namespace System.Globalization -{ - internal partial class CultureData - { - /// <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() - { - Debug.Assert(!GlobalizationMode.Invariant); - - int result; - string realNameBuffer = _sRealName; - char* pBuffer = stackalloc char[Interop.Kernel32.LOCALE_NAME_MAX_LENGTH]; - - result = GetLocaleInfoEx(realNameBuffer, Interop.Kernel32.LOCALE_SNAME, pBuffer, Interop.Kernel32.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 = GetLocaleInfoEx(realNameBuffer, Interop.Kernel32.LOCALE_INEUTRAL | Interop.Kernel32.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 will 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.Kernel32.ResolveLocaleName(realNameBuffer, pBuffer, Interop.Kernel32.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 = GetLocaleInfoEx(realNameBuffer, Interop.Kernel32.LOCALE_ILANGUAGE | Interop.Kernel32.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; - } - - // Wrappers around the GetLocaleInfoEx APIs which handle marshalling the returned - // data as either and Int or string. - internal static unsafe string? GetLocaleInfoEx(string localeName, uint field) - { - // REVIEW: Determine the maximum size for the buffer - const int BUFFER_SIZE = 530; - - char* pBuffer = stackalloc char[BUFFER_SIZE]; - int resultCode = GetLocaleInfoEx(localeName, field, pBuffer, BUFFER_SIZE); - if (resultCode > 0) - { - return new string(pBuffer); - } - - return null; - } - - internal static unsafe int GetLocaleInfoExInt(string localeName, uint field) - { - field |= Interop.Kernel32.LOCALE_RETURN_NUMBER; - int value = 0; - GetLocaleInfoEx(localeName, field, (char*)&value, sizeof(int)); - return value; - } - - internal static unsafe int GetLocaleInfoEx(string lpLocaleName, uint lcType, char* lpLCData, int cchData) - { - Debug.Assert(!GlobalizationMode.Invariant); - - return Interop.Kernel32.GetLocaleInfoEx(lpLocaleName, lcType, lpLCData, cchData); - } - - private string GetLocaleInfo(LocaleStringData type) - { - Debug.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 |= Interop.Kernel32.LOCALE_NOUSEROVERRIDE; - } - - // Ask OS for data, note that we presume it returns success, so we have to know that - // sWindowsName is valid before calling. - Debug.Assert(_sWindowsName != null, "[CultureData.DoGetLocaleInfoInt] Expected _sWindowsName to be populated by already"); - return GetLocaleInfoExInt(_sWindowsName, lctype); - } - - private int[] GetLocaleInfo(LocaleGroupingData type) - { - Debug.Assert(_sWindowsName != null, "[CultureData.DoGetLocaleInfoInt] Expected _sWindowsName to be populated by already"); - return ConvertWin32GroupString(GetLocaleInfoFromLCType(_sWindowsName, (uint)type, UseUserOverride)); - } - - private string? GetTimeFormatString() - { - Debug.Assert(_sWindowsName != null, "[CultureData.DoGetLocaleInfoInt] Expected _sWindowsName to be populated by already"); - return ReescapeWin32String(GetLocaleInfoFromLCType(_sWindowsName, Interop.Kernel32.LOCALE_STIMEFORMAT, UseUserOverride)); - } - - private int GetFirstDayOfWeek() - { - Debug.Assert(_sWindowsName != null, "[CultureData.DoGetLocaleInfoInt] Expected _sWindowsName to be populated by already"); - - int result = GetLocaleInfoExInt(_sWindowsName, Interop.Kernel32.LOCALE_IFIRSTDAYOFWEEK | (!UseUserOverride ? Interop.Kernel32.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 - Debug.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 - Debug.Assert(_sWindowsName != null, "[CultureData.DoEnumShortTimeFormats] Expected _sWindowsName to be populated by already"); - string[]? result = ReescapeWin32Strings(nativeEnumTimeFormats(_sWindowsName, Interop.Kernel32.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) - { - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert(regionName != null); - - EnumLocaleData context; - context.cultureName = null; - context.regionName = regionName; - - unsafe - { - Interop.Kernel32.EnumSystemLocalesEx(EnumSystemLocalesProc, Interop.Kernel32.LOCALE_SPECIFICDATA | Interop.Kernel32.LOCALE_SUPPLEMENTAL, Unsafe.AsPointer(ref context), IntPtr.Zero); - } - - if (context.cultureName != null) - { - // we got a matched culture - return GetCultureData(context.cultureName, true); - } - - return null; - } - - private string GetLanguageDisplayName(string cultureName) - { - // 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 = CultureInfo.GetUserDefaultCulture()) != null) && - !CultureInfo.DefaultThreadCurrentUICulture.Name.Equals(ci.Name)) - { - return NativeName; - } - else - { - return GetLocaleInfo(cultureName, LocaleStringData.LocalizedDisplayName); - } - } - - private string GetRegionDisplayName() - { - // If the current UI culture matching the OS UI language, we'll get the display name from the OS. - // otherwise, we use the native name as we don't carry resources for the region display names anyway. - if (CultureInfo.CurrentUICulture.Name.Equals(CultureInfo.UserDefaultUICulture.Name)) - { - return GetLocaleInfo(LocaleStringData.LocalizedCountryName); - } - - return NativeCountryName; - } - - // PAL methods end here. - - private static string GetLocaleInfoFromLCType(string localeName, uint lctype, bool useUserOveride) - { - Debug.Assert(localeName != null, "[CultureData.GetLocaleInfoFromLCType] Expected localeName to be not be null"); - - // Fix lctype if we don't want overrides - if (!useUserOveride) - { - lctype |= Interop.Kernel32.LOCALE_NOUSEROVERRIDE; - } - - // Ask OS for data - // Failed? Just use empty string - return GetLocaleInfoEx(localeName, lctype) ?? string.Empty; - } - - /// <summary> - /// 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 - /// </summary> - [return: NotNullIfNotNull("str")] - 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 - 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 - 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 - 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(); - } - - [return: NotNullIfNotNull("array")] - 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 (string.IsNullOrEmpty(win32Str)) - { - 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[^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[^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 struct EnumLocaleData - { - public string regionName; - public string? cultureName; - } - - // EnumSystemLocaleEx callback. - // [NativeCallable(CallingConvention = CallingConvention.StdCall)] - private static unsafe Interop.BOOL EnumSystemLocalesProc(char* lpLocaleString, uint flags, void* contextHandle) - { - ref EnumLocaleData context = ref Unsafe.As<byte, EnumLocaleData>(ref *(byte*)contextHandle); - try - { - string cultureName = new string(lpLocaleString); - string? regionName = GetLocaleInfoEx(cultureName, Interop.Kernel32.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; - } - } - - // EnumSystemLocaleEx callback. - // [NativeCallable(CallingConvention = CallingConvention.StdCall)] - private static unsafe Interop.BOOL EnumAllSystemLocalesProc(char* lpLocaleString, uint flags, void* contextHandle) - { - ref EnumData context = ref Unsafe.As<byte, EnumData>(ref *(byte*)contextHandle); - try - { - context.strings.Add(new string(lpLocaleString)); - return Interop.BOOL.TRUE; - } - catch (Exception) - { - return Interop.BOOL.FALSE; - } - } - - // Context for EnumTimeFormatsEx callback. - private struct EnumData - { - public List<string> strings; - } - - // EnumTimeFormatsEx callback itself. - // [NativeCallable(CallingConvention = CallingConvention.StdCall)] - private static unsafe Interop.BOOL EnumTimeCallback(char* lpTimeFormatString, void* lParam) - { - ref EnumData context = ref Unsafe.As<byte, EnumData>(ref *(byte*)lParam); - try - { - context.strings.Add(new string(lpTimeFormatString)); - return Interop.BOOL.TRUE; - } - catch (Exception) - { - return Interop.BOOL.FALSE; - } - } - - private static unsafe string[]? nativeEnumTimeFormats(string localeName, uint dwFlags, bool useUserOverride) - { - EnumData data = default; - data.strings = new List<string>(); - - // Now call the enumeration API. Work is done by our callback function - Interop.Kernel32.EnumTimeFormatsEx(EnumTimeCallback, localeName, (uint)dwFlags, Unsafe.AsPointer(ref data)); - - 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 == Interop.Kernel32.TIME_NOSECONDS) ? Interop.Kernel32.LOCALE_SSHORTTIME : Interop.Kernel32.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; - } - - private static int LocaleNameToLCID(string cultureName) - { - Debug.Assert(!GlobalizationMode.Invariant); - - return Interop.Kernel32.LocaleNameToLCID(cultureName, Interop.Kernel32.LOCALE_ALLOW_NEUTRAL_NAMES); - } - - private static unsafe string? LCIDToLocaleName(int culture) - { - Debug.Assert(!GlobalizationMode.Invariant); - - char* pBuffer = stackalloc char[Interop.Kernel32.LOCALE_NAME_MAX_LENGTH + 1]; // +1 for the null termination - int length = Interop.Kernel32.LCIDToLocaleName(culture, pBuffer, Interop.Kernel32.LOCALE_NAME_MAX_LENGTH + 1, Interop.Kernel32.LOCALE_ALLOW_NEUTRAL_NAMES); - - if (length > 0) - { - return new string(pBuffer); - } - - return null; - } - - private int GetAnsiCodePage(string cultureName) - { - return GetLocaleInfo(LocaleNumberData.AnsiCodePage); - } - - private int GetOemCodePage(string cultureName) - { - return GetLocaleInfo(LocaleNumberData.OemCodePage); - } - - private int GetMacCodePage(string cultureName) - { - return GetLocaleInfo(LocaleNumberData.MacCodePage); - } - - private int GetEbcdicCodePage(string cultureName) - { - return GetLocaleInfo(LocaleNumberData.EbcdicCodePage); - } - - private int GetGeoId(string cultureName) - { - return GetLocaleInfo(LocaleNumberData.GeoId); - } - - private int GetDigitSubstitution(string cultureName) - { - return GetLocaleInfo(LocaleNumberData.DigitSubstitution); - } - - private string GetThreeLetterWindowsLanguageName(string cultureName) - { - return GetLocaleInfo(cultureName, LocaleStringData.AbbreviatedWindowsLanguageName); - } - - private static CultureInfo[] EnumCultures(CultureTypes types) - { - Debug.Assert(!GlobalizationMode.Invariant); - - uint flags = 0; - -#pragma warning disable 618 - if ((types & (CultureTypes.FrameworkCultures | CultureTypes.InstalledWin32Cultures | CultureTypes.ReplacementCultures)) != 0) - { - flags |= Interop.Kernel32.LOCALE_NEUTRALDATA | Interop.Kernel32.LOCALE_SPECIFICDATA; - } -#pragma warning restore 618 - - if ((types & CultureTypes.NeutralCultures) != 0) - { - flags |= Interop.Kernel32.LOCALE_NEUTRALDATA; - } - - if ((types & CultureTypes.SpecificCultures) != 0) - { - flags |= Interop.Kernel32.LOCALE_SPECIFICDATA; - } - - if ((types & CultureTypes.UserCustomCulture) != 0) - { - flags |= Interop.Kernel32.LOCALE_SUPPLEMENTAL; - } - - if ((types & CultureTypes.ReplacementCultures) != 0) - { - flags |= Interop.Kernel32.LOCALE_SUPPLEMENTAL; - } - - EnumData context = default; - context.strings = new List<string>(); - - unsafe - { - Interop.Kernel32.EnumSystemLocalesEx(EnumAllSystemLocalesProc, flags, Unsafe.AsPointer(ref context), IntPtr.Zero); - } - - CultureInfo[] cultures = new CultureInfo[context.strings.Count]; - for (int i = 0; i < cultures.Length; i++) - { - cultures[i] = new CultureInfo(context.strings[i]); - } - - return cultures; - } - - private string GetConsoleFallbackName(string cultureName) - { - return GetLocaleInfo(cultureName, LocaleStringData.ConsoleFallbackName); - } - - internal bool IsWin32Installed => true; - - internal bool IsReplacementCulture - { - get - { - EnumData context = default; - context.strings = new List<string>(); - - unsafe - { - Interop.Kernel32.EnumSystemLocalesEx(EnumAllSystemLocalesProc, Interop.Kernel32.LOCALE_REPLACEMENT, Unsafe.AsPointer(ref context), IntPtr.Zero); - } - - for (int i = 0; i < context.strings.Count; i++) - { - if (string.Equals(context.strings[i], _sWindowsName, StringComparison.OrdinalIgnoreCase)) - return true; - } - - return false; - } - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/CultureData.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/CultureData.cs deleted file mode 100644 index cad208b1974..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/CultureData.cs +++ /dev/null @@ -1,2252 +0,0 @@ -// 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; -using System.Text; - -namespace System.Globalization -{ - /// <summary> - /// List of culture data - /// Note the we cache overrides. - /// Note that localized names (resource names) aren't available from here. - /// </summary> - /// <remarks> - /// 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 - /// </remarks> - internal partial class CultureData - { - private const int LocaleNameMaxLength = 85; - private const int undef = -1; - - // Override flag - private string _sRealName = null!; // Name you passed in (ie: en-US, en, or de-DE_phoneb). Initialized by helper called during initialization. - 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? _sISO639Language2; // 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 - private string? _sAbbrevLang; // abbreviated language name (Windows Language Name) ex: ENU - private string? _sConsoleFallbackName; // The culture name for the console fallback UI culture - private int _iInputLanguageHandle = undef; // input language handle - - // 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 - private string? _sISO3166CountryName2; // 3 char ISO 3166 country name 2 2(RegionInfo) ex: USA (ISO) - private int _iGeoId = undef; // GeoId - - // Numbers - private string? _sPositiveSign; // (user can override) positive sign - private string? _sNegativeSign; // (user can override) negative sign - // (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) - private string? _sEnglishCurrency; // English name for this currency - private string? _sNativeCurrency; // Native name for this currency - // (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 _iDefaultAnsiCodePage = undef; // default ansi code page ID (ACP) - private int _iDefaultOemCodePage = undef; // default oem code page ID (OCP or OEM) - private int _iDefaultMacCodePage = undef; // default macintosh code page - private int _iDefaultEbcdicCodePage = undef; // default EBCDIC code page - - 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) - - /// <summary> - /// Region Name to Culture Name mapping table - /// </summary> - /// <remarks> - /// Using a property so we avoid creating the dictionary until we need it - /// </remarks> - private static Dictionary<string, string> RegionNames => - s_regionNames ??= - new Dictionary<string, string>(211 /* prime */) - { - { "029", "en-029" }, - { "AE", "ar-AE" }, - { "AF", "prs-AF" }, - { "AL", "sq-AL" }, - { "AM", "hy-AM" }, - { "AR", "es-AR" }, - { "AT", "de-AT" }, - { "AU", "en-AU" }, - { "AZ", "az-Cyrl-AZ" }, - { "BA", "bs-Latn-BA" }, - { "BD", "bn-BD" }, - { "BE", "nl-BE" }, - { "BG", "bg-BG" }, - { "BH", "ar-BH" }, - { "BN", "ms-BN" }, - { "BO", "es-BO" }, - { "BR", "pt-BR" }, - { "BY", "be-BY" }, - { "BZ", "en-BZ" }, - { "CA", "en-CA" }, - { "CH", "it-CH" }, - { "CL", "es-CL" }, - { "CN", "zh-CN" }, - { "CO", "es-CO" }, - { "CR", "es-CR" }, - { "CS", "sr-Cyrl-CS" }, - { "CZ", "cs-CZ" }, - { "DE", "de-DE" }, - { "DK", "da-DK" }, - { "DO", "es-DO" }, - { "DZ", "ar-DZ" }, - { "EC", "es-EC" }, - { "EE", "et-EE" }, - { "EG", "ar-EG" }, - { "ES", "es-ES" }, - { "ET", "am-ET" }, - { "FI", "fi-FI" }, - { "FO", "fo-FO" }, - { "FR", "fr-FR" }, - { "GB", "en-GB" }, - { "GE", "ka-GE" }, - { "GL", "kl-GL" }, - { "GR", "el-GR" }, - { "GT", "es-GT" }, - { "HK", "zh-HK" }, - { "HN", "es-HN" }, - { "HR", "hr-HR" }, - { "HU", "hu-HU" }, - { "ID", "id-ID" }, - { "IE", "en-IE" }, - { "IL", "he-IL" }, - { "IN", "hi-IN" }, - { "IQ", "ar-IQ" }, - { "IR", "fa-IR" }, - { "IS", "is-IS" }, - { "IT", "it-IT" }, - { "IV", "" }, - { "JM", "en-JM" }, - { "JO", "ar-JO" }, - { "JP", "ja-JP" }, - { "KE", "sw-KE" }, - { "KG", "ky-KG" }, - { "KH", "km-KH" }, - { "KR", "ko-KR" }, - { "KW", "ar-KW" }, - { "KZ", "kk-KZ" }, - { "LA", "lo-LA" }, - { "LB", "ar-LB" }, - { "LI", "de-LI" }, - { "LK", "si-LK" }, - { "LT", "lt-LT" }, - { "LU", "lb-LU" }, - { "LV", "lv-LV" }, - { "LY", "ar-LY" }, - { "MA", "ar-MA" }, - { "MC", "fr-MC" }, - { "ME", "sr-Latn-ME" }, - { "MK", "mk-MK" }, - { "MN", "mn-MN" }, - { "MO", "zh-MO" }, - { "MT", "mt-MT" }, - { "MV", "dv-MV" }, - { "MX", "es-MX" }, - { "MY", "ms-MY" }, - { "NG", "ig-NG" }, - { "NI", "es-NI" }, - { "NL", "nl-NL" }, - { "NO", "nn-NO" }, - { "NP", "ne-NP" }, - { "NZ", "en-NZ" }, - { "OM", "ar-OM" }, - { "PA", "es-PA" }, - { "PE", "es-PE" }, - { "PH", "en-PH" }, - { "PK", "ur-PK" }, - { "PL", "pl-PL" }, - { "PR", "es-PR" }, - { "PT", "pt-PT" }, - { "PY", "es-PY" }, - { "QA", "ar-QA" }, - { "RO", "ro-RO" }, - { "RS", "sr-Latn-RS" }, - { "RU", "ru-RU" }, - { "RW", "rw-RW" }, - { "SA", "ar-SA" }, - { "SE", "sv-SE" }, - { "SG", "zh-SG" }, - { "SI", "sl-SI" }, - { "SK", "sk-SK" }, - { "SN", "wo-SN" }, - { "SV", "es-SV" }, - { "SY", "ar-SY" }, - { "TH", "th-TH" }, - { "TJ", "tg-Cyrl-TJ" }, - { "TM", "tk-TM" }, - { "TN", "ar-TN" }, - { "TR", "tr-TR" }, - { "TT", "en-TT" }, - { "TW", "zh-TW" }, - { "UA", "uk-UA" }, - { "US", "en-US" }, - { "UY", "es-UY" }, - { "UZ", "uz-Cyrl-UZ" }, - { "VE", "es-VE" }, - { "VN", "vi-VN" }, - { "YE", "ar-YE" }, - { "ZA", "af-ZA" }, - { "ZW", "en-ZW" } - }; - - // Cache of regions we've already looked up - private static volatile Dictionary<string, CultureData>? s_cachedRegions; - private static volatile Dictionary<string, string>? 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) - { - 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 + '*'); - Dictionary<string, CultureData>? tempHashTable = s_cachedRegions; - - if (tempHashTable == null) - { - // No table yet, make a new one - tempHashTable = new Dictionary<string, CultureData>(); - } - 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) - { - // 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 (!GlobalizationMode.Invariant && (retVal == null || retVal.IsNeutralCulture)) - { - retVal = GetCultureDataFromRegionName(cultureName); - } - - // If we found one we can use, then cache it for next time - if (retVal != null && !retVal.IsNeutralCulture) - { - // 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; - } - - // Clear our internal caches - internal static void ClearCachedData() - { - s_cachedCultures = null; - s_cachedRegions = null; - } - - internal static CultureInfo[] GetCultures(CultureTypes types) - { - // Disable warning 618: System.Globalization.CultureTypes.FrameworkCultures' is obsolete -#pragma warning disable 618 - // Validate flags - if ((int)types <= 0 || ((int)types & (int)~(CultureTypes.NeutralCultures | CultureTypes.SpecificCultures | - CultureTypes.InstalledWin32Cultures | CultureTypes.UserCustomCulture | - CultureTypes.ReplacementCultures | CultureTypes.WindowsOnlyCultures | - CultureTypes.FrameworkCultures)) != 0) - { - throw new ArgumentOutOfRangeException(nameof(types), - SR.Format(SR.ArgumentOutOfRange_Range, CultureTypes.NeutralCultures, CultureTypes.FrameworkCultures)); - } - - // We have deprecated CultureTypes.FrameworkCultures. - // When this enum is used, we will enumerate Whidbey framework cultures (for compatibility). - - // We have deprecated CultureTypes.WindowsOnlyCultures. - // When this enum is used, we will return an empty array for this enum. - if ((types & CultureTypes.WindowsOnlyCultures) != 0) - { - // Remove the enum as it is an no-op. - types &= (~CultureTypes.WindowsOnlyCultures); - } - - if (GlobalizationMode.Invariant) - { - // in invariant mode we always return invariant culture only from the enumeration - return new CultureInfo[] { new CultureInfo("") }; - } - -#pragma warning restore 618 - return EnumCultures(types); - } - - private static CultureData CreateCultureWithInvariantData() - { - // 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._sISO639Language2 = "ivl"; // 3 char ISO 639 lang name 2 - 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 - invariant._sAbbrevLang = "IVL"; // abbreviated language name (Windows Language Name) - invariant._sConsoleFallbackName = ""; // The culture name for the console fallback UI culture - invariant._iInputLanguageHandle = 0x07F; // input language handle - - // 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 - invariant._sISO3166CountryName2 = "ivc"; // 3 char ISO 3166 country name 2 2(RegionInfo) - invariant._iGeoId = 244; // GeoId (Windows Only) - - // Numbers - invariant._sPositiveSign = "+"; // positive sign - invariant._sNegativeSign = "-"; // negative sign - 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._sEnglishCurrency = "International Monetary Fund"; // English name for this currency (Windows Only) - invariant._sNativeCurrency = "International Monetary Fund"; // Native name for this currency (Windows Only) - 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._sTimeSeparator = ":"; - 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 = CultureInfo.LOCALE_INVARIANT; // locale ID (0409) - NO sort information - invariant._iDefaultAnsiCodePage = 1252; // default ansi code page ID (ACP) - invariant._iDefaultOemCodePage = 437; // default oem code page ID (OCP or OEM) - invariant._iDefaultMacCodePage = 10000; // default macintosh code page - invariant._iDefaultEbcdicCodePage = 037; // default EBCDIC code page - - if (GlobalizationMode.Invariant) - { - invariant._sLocalizedDisplayName = invariant._sNativeDisplayName; - invariant._sLocalizedCountry = invariant._sNativeCountry; - } - - return invariant; - } - - /// <summary> - /// Build our invariant information - /// We need an invariant instance, which we build hard-coded - /// </summary> - internal static CultureData Invariant => s_Invariant ??= CreateCultureWithInvariantData(); - private static volatile CultureData? s_Invariant; - - // Cache of cultures we've already looked up - private static volatile Dictionary<string, CultureData>? s_cachedCultures; - private static readonly object s_lock = new object(); - - 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 + '*'); - Dictionary<string, CultureData>? tempHashTable = s_cachedCultures; - if (tempHashTable == null) - { - // No table yet, make a new one - tempHashTable = new Dictionary<string, CultureData>(); - } - 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 string NormalizeCultureName(string name, out bool isNeutralName) - { - isNeutralName = true; - int i = 0; - - if (name.Length > LocaleNameMaxLength) - { - // Theoretically we shouldn't hit this exception. - throw new ArgumentException(SR.Format(SR.Argument_InvalidId, nameof(name))); - } - - Span<char> normalizedName = stackalloc char[name.Length]; - - bool changed = false; - - while (i < name.Length && name[i] != '-' && name[i] != '_') - { - if (name[i] >= 'A' && name[i] <= 'Z') - { - // lowercase characters before '-' - normalizedName[i] = (char)(((int)name[i]) + 0x20); - changed = true; - } - else - { - normalizedName[i] = name[i]; - } - i++; - } - - if (i < name.Length) - { - // this is not perfect to detect the non neutral cultures but it is good enough when we are running in invariant mode - isNeutralName = false; - } - - while (i < name.Length) - { - if (name[i] >= 'a' && name[i] <= 'z') - { - normalizedName[i] = (char)(((int)name[i]) - 0x20); - changed = true; - } - else - { - normalizedName[i] = name[i]; - } - i++; - } - - if (changed) - { - return new string(normalizedName); - } - - return name; - } - - private static CultureData? CreateCultureData(string cultureName, bool useUserOverride) - { - if (GlobalizationMode.Invariant) - { - if (cultureName.Length > LocaleNameMaxLength || !CultureInfo.VerifyCultureName(cultureName, false)) - { - return null; - } - CultureData cd = CreateCultureWithInvariantData(); - cd._bUseOverrides = useUserOverride; - cd._sName = NormalizeCultureName(cultureName, out cd._bNeutral); - cd._sRealName = cd._sName; - cd._sWindowsName = cd._sName; - cd._iLanguage = CultureInfo.LOCALE_CUSTOM_UNSPECIFIED; - - return cd; - } - - if (cultureName.Length == 1 && (cultureName[0] == 'C' || cultureName[0] == 'c')) - { - // Always map the "C" locale to Invariant to avoid mapping it to en_US_POSIX on Linux because POSIX - // locale collation doesn't support case insensitive comparisons. - // We do the same mapping on Windows for the sake of consistency. - return CultureData.Invariant; - } - - CultureData culture = new CultureData(); - culture._bUseOverrides = useUserOverride; - culture._sRealName = cultureName; - - // Ask native code if that one's real - if (!culture.InitCultureData() && !culture.InitCompatibilityCultureData()) - { - 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()) - { - return false; - } - - // fixup our data - _sName = realCultureName; // the name that goes back to the user - _sParent = fallbackCultureName; - - return true; - } - - /// We'd rather people use the named version since this doesn't allow custom locales - internal static CultureData GetCultureData(int culture, bool bUseUserOverride) - { - string? localeName = null; - CultureData? retVal = null; - - if (culture == CultureInfo.LOCALE_INVARIANT) - { - return Invariant; - } - - if (GlobalizationMode.Invariant) - { - // LCID is not supported in the InvariantMode - throw new CultureNotFoundException(nameof(culture), culture, SR.Argument_CultureNotSupported); - } - - // Convert the lcid to a name, then use that - // Note that this will return neutral names (unlike Vista native API) - localeName = LCIDToLocaleName(culture); - - if (!string.IsNullOrEmpty(localeName)) - { - // Valid name, use it - retVal = GetCultureData(localeName, bUseUserOverride); - } - - // If not successful, throw - if (retVal == null) - { - throw new CultureNotFoundException(nameof(culture), culture, SR.Argument_CultureNotSupported); - } - - // Return the one we found - return retVal; - } - - /// <summary> - /// The real name used to construct the locale (ie: de-DE_phoneb) - /// </summary> - internal string CultureName - { - get - { - Debug.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; - } - } - - /// <summary> - /// Are overrides enabled? - /// </summary> - internal bool UseUserOverride => _bUseOverrides; - - /// <summary> - /// locale name (ie: de-DE, NO sort information) - /// </summary> - internal string Name => _sName ?? string.Empty; - - // Parent name (which may be a custom locale/culture) - // Ask using the real name, so that we get parents of neutrals - internal string ParentName => _sParent ??= GetLocaleInfo(_sRealName!, LocaleStringData.ParentName); - - // Localized pretty name for this locale (ie: Inglis (estados Unitos)) - internal string DisplayName - { - get - { - string? localizedDisplayName = _sLocalizedDisplayName; - if (localizedDisplayName == null) - { - if (IsSupplementalCustomCulture) - { - if (IsNeutralCulture) - { - localizedDisplayName = NativeLanguageName; - } - else - { - localizedDisplayName = NativeName; - } - } - else - { - try - { - const string ZH_CHT = "zh-CHT"; - const string ZH_CHS = "zh-CHS"; - - if (Name.Equals(ZH_CHT, StringComparison.OrdinalIgnoreCase)) - { - localizedDisplayName = GetLanguageDisplayName("zh-Hant"); - } - else if (Name.Equals(ZH_CHS, StringComparison.OrdinalIgnoreCase)) - { - localizedDisplayName = GetLanguageDisplayName("zh-Hans"); - } - else - { - localizedDisplayName = GetLanguageDisplayName(Name); - } - } - catch - { - // do nothing - } - } - - // If it hasn't been found (Windows 8 and up), fallback to the system - if (string.IsNullOrEmpty(localizedDisplayName)) - { - // If its neutral use the language name - if (IsNeutralCulture) - { - localizedDisplayName = LocalizedLanguageName; - } - 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 = CultureInfo.GetUserDefaultCulture()) != null) && - !CultureInfo.DefaultThreadCurrentUICulture.Name.Equals(ci.Name)) - { - localizedDisplayName = NativeName; - } - else - { - localizedDisplayName = GetLocaleInfo(LocaleStringData.LocalizedDisplayName); - } - } - } - - _sLocalizedDisplayName = localizedDisplayName; - } - - return localizedDisplayName; - } - } - - /// <summary> - /// English pretty name for this locale (ie: English (United States)) - /// </summary> - internal string EnglishName - { - get - { - string? englishDisplayName = _sEnglishDisplayName; - if (englishDisplayName == null) - { - // If its neutral use the language name - if (IsNeutralCulture) - { - englishDisplayName = EnglishLanguageName; - // differentiate the legacy display names - switch (_sName) - { - case "zh-CHS": - case "zh-CHT": - englishDisplayName += " Legacy"; - break; - } - } - else - { - englishDisplayName = GetLocaleInfo(LocaleStringData.EnglishDisplayName); - - // if it isn't found build one: - if (string.IsNullOrEmpty(englishDisplayName)) - { - // Our existing names mostly look like: - // "English" + "United States" -> "English (United States)" - // "Azeri (Latin)" + "Azerbaijan" -> "Azeri (Latin, Azerbaijan)" - if (EnglishLanguageName[^1] == ')') - { - // "Azeri (Latin)" + "Azerbaijan" -> "Azeri (Latin, Azerbaijan)" - englishDisplayName = string.Concat( - EnglishLanguageName.AsSpan(0, _sEnglishLanguage!.Length - 1), - ", ", - EnglishCountryName, - ")"); - } - else - { - // "English" + "United States" -> "English (United States)" - englishDisplayName = EnglishLanguageName + " (" + EnglishCountryName + ")"; - } - } - } - - _sEnglishDisplayName = englishDisplayName; - } - - return englishDisplayName; - } - } - - /// <summary> - /// Native pretty name for this locale (ie: Deutsch (Deutschland)) - /// </summary> - internal string NativeName - { - get - { - string? nativeDisplayName = _sNativeDisplayName; - if (nativeDisplayName == null) - { - // If its neutral use the language name - if (IsNeutralCulture) - { - nativeDisplayName = NativeLanguageName; - // differentiate the legacy display names - switch (_sName) - { - case "zh-CHS": - nativeDisplayName += " \u65E7\u7248"; - break; - case "zh-CHT": - nativeDisplayName += " \u820A\u7248"; - break; - } - } - else - { - nativeDisplayName = GetLocaleInfo(LocaleStringData.NativeDisplayName); - - // if it isn't found build one: - if (string.IsNullOrEmpty(nativeDisplayName)) - { - // These should primarily be "Deutsch (Deutschland)" type names - nativeDisplayName = NativeLanguageName + " (" + NativeCountryName + ")"; - } - } - - _sNativeDisplayName = nativeDisplayName; - } - - return nativeDisplayName; - } - } - - /// <summary> - /// The culture name to be used in CultureInfo.CreateSpecificCulture() - /// </summary> - internal string SpecificCultureName - { - get - { - // This got populated during the culture initialization - Debug.Assert(_sSpecificCulture != null, "[CultureData.SpecificCultureName] Expected this.sSpecificCulture to be populated by culture data initialization already"); - return _sSpecificCulture; - } - } - - /// <summary> - /// iso 639 language name, ie: en - /// </summary> - internal string TwoLetterISOLanguageName => _sISO639Language ??= GetLocaleInfo(LocaleStringData.Iso639LanguageTwoLetterName); - - /// <summary> - /// iso 639 language name, ie: eng - /// </summary> - internal string ThreeLetterISOLanguageName => _sISO639Language2 ??= GetLocaleInfo(LocaleStringData.Iso639LanguageThreeLetterName); - - /// <summary> - /// abbreviated windows language name (ie: enu) (non-standard, avoid this) - /// </summary> - internal string ThreeLetterWindowsLanguageName => _sAbbrevLang ??= GetThreeLetterWindowsLanguageName(_sRealName!); - - /// <summary> - /// Localized name for this language (Windows Only) ie: Inglis - /// This is only valid for Windows 8 and higher neutrals: - /// </summary> - private string LocalizedLanguageName - { - 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 = CultureInfo.GetUserDefaultCulture()) != null) && - !CultureInfo.DefaultThreadCurrentUICulture!.Name.Equals(ci.Name)) - { - _sLocalizedLanguage = NativeLanguageName; - } - else - { - _sLocalizedLanguage = GetLocaleInfo(LocaleStringData.LocalizedLanguageName); - } - } - - return _sLocalizedLanguage; - } - } - - /// <summary> - /// English name for this language (Windows Only) ie: German - /// </summary> - private string EnglishLanguageName => _sEnglishLanguage ??= GetLocaleInfo(LocaleStringData.EnglishLanguageName); - - /// <summary> - /// Native name of this language (Windows Only) ie: Deutsch - /// </summary> - private string NativeLanguageName => _sNativeLanguage ??= GetLocaleInfo(LocaleStringData.NativeLanguageName); - - /// <summary> - /// region name (eg US) - /// </summary> - internal string RegionName => _sRegionName ??= GetLocaleInfo(LocaleStringData.Iso3166CountryName); - - internal int GeoId - { - get - { - if (_iGeoId == undef) - { - _iGeoId = GetGeoId(_sRealName!); - } - return _iGeoId; - } - } - - /// <summary> - /// localized name for the country - /// </summary> - internal string LocalizedCountryName - { - get - { - string? localizedCountry = _sLocalizedCountry; - if (localizedCountry == null) - { - try - { - localizedCountry = GetRegionDisplayName(); - } - catch - { - // do nothing. we'll fallback - } - - localizedCountry ??= NativeCountryName; - _sLocalizedCountry = localizedCountry; - } - - return localizedCountry; - } - } - - /// <summary> - /// english country name (RegionInfo) ie: Germany - /// </summary> - internal string EnglishCountryName => _sEnglishCountry ??= GetLocaleInfo(LocaleStringData.EnglishCountryName); - - /// <summary> - /// native country name (RegionInfo) ie: Deutschland - /// </summary> - internal string NativeCountryName => _sNativeCountry ??= GetLocaleInfo(LocaleStringData.NativeCountryName); - - /// <summary> - /// ISO 3166 Country Name - /// </summary> - internal string TwoLetterISOCountryName => _sISO3166CountryName ??= GetLocaleInfo(LocaleStringData.Iso3166CountryName); - - /// <summary> - /// 3 letter ISO 3166 country code - /// </summary> - internal string ThreeLetterISOCountryName => _sISO3166CountryName2 ??= GetLocaleInfo(LocaleStringData.Iso3166CountryName2); - - internal int KeyboardLayoutId - { - get - { - if (_iInputLanguageHandle == undef) - { - if (IsSupplementalCustomCulture) - { - _iInputLanguageHandle = 0x0409; - } - else - { - // Input Language is same as LCID for built-in cultures - _iInputLanguageHandle = LCID; - } - } - return _iInputLanguageHandle; - } - } - - /// <summary> - /// Console fallback name (ie: locale to use for console apps for unicode-only locales) - /// </summary> - internal string SCONSOLEFALLBACKNAME => _sConsoleFallbackName ??= GetConsoleFallbackName(_sRealName!); - - /// <summary> - /// (user can override) grouping of digits - /// </summary> - internal int[] NumberGroupSizes => _waGrouping ??= GetLocaleInfo(LocaleGroupingData.Digit); - - /// <summary> - /// Not a Number - /// </summary> - private string NaNSymbol => _sNaN ??= GetLocaleInfo(LocaleStringData.NaNSymbol); - - /// <summary> - /// + Infinity - /// </summary> - private string PositiveInfinitySymbol => _sPositiveInfinity ??= GetLocaleInfo(LocaleStringData.PositiveInfinitySymbol); - - /// <summary> - /// - Infinity - /// </summary> - private string NegativeInfinitySymbol => _sNegativeInfinity ??= GetLocaleInfo(LocaleStringData.NegativeInfinitySymbol); - - /// <summary> - /// Negative Percent (0-3) - /// </summary> - private int PercentNegativePattern - { - get - { - if (_iNegativePercent == undef) - { - // Note that <= Windows Vista this is synthesized by native code - _iNegativePercent = GetLocaleInfo(LocaleNumberData.NegativePercentFormat); - } - return _iNegativePercent; - } - } - - /// <summary> - /// Positive Percent (0-11) - /// </summary> - private int PercentPositivePattern - { - get - { - if (_iPositivePercent == undef) - { - // Note that <= Windows Vista this is synthesized by native code - _iPositivePercent = GetLocaleInfo(LocaleNumberData.PositivePercentFormat); - } - return _iPositivePercent; - } - } - - /// <summary> - /// Percent (%) symbol - /// </summary> - private string PercentSymbol => _sPercent ??= GetLocaleInfo(LocaleStringData.PercentSymbol); - - /// <summary> - /// PerMille symbol - /// </summary> - private string PerMilleSymbol => _sPerMille ??= GetLocaleInfo(LocaleStringData.PerMilleSymbol); - - /// <summary> - /// (user can override) local monetary symbol, eg: $ - /// </summary> - internal string CurrencySymbol => _sCurrency ??= GetLocaleInfo(LocaleStringData.MonetarySymbol); - - /// <summary> - /// international monetary symbol (RegionInfo), eg: USD - /// </summary> - internal string ISOCurrencySymbol => _sIntlMonetarySymbol ??= GetLocaleInfo(LocaleStringData.Iso4217MonetarySymbol); - - /// <summary> - /// English name for this currency (RegionInfo), eg: US Dollar - /// </summary> - internal string CurrencyEnglishName => _sEnglishCurrency ??= GetLocaleInfo(LocaleStringData.CurrencyEnglishName); - - /// <summary> - /// Native name for this currency (RegionInfo), eg: Schweiz Frank - /// </summary> - internal string CurrencyNativeName => _sNativeCurrency ??= GetLocaleInfo(LocaleStringData.CurrencyNativeName); - - /// <summary> - /// (user can override) monetary grouping of digits - /// </summary> - internal int[] CurrencyGroupSizes => _waMonetaryGrouping ??= GetLocaleInfo(LocaleGroupingData.Monetary); - - /// <summary> - /// (user can override) system of measurement 0=metric, 1=US (RegionInfo) - /// </summary> - internal int MeasurementSystem - { - get - { - if (_iMeasure == undef) - { - _iMeasure = GetLocaleInfo(LocaleNumberData.MeasurementSystem); - } - return _iMeasure; - } - } - - /// <summary> - /// (user can override) list Separator - /// </summary> - internal string ListSeparator => _sListSeparator ??= GetLocaleInfo(LocaleStringData.ListSeparator); - - /// <summary> - /// (user can override) AM designator - /// </summary> - internal string AMDesignator => _sAM1159 ??= GetLocaleInfo(LocaleStringData.AMDesignator); - - /// <summary> - /// (user can override) PM designator - /// </summary> - internal string PMDesignator => _sPM2359 ??= GetLocaleInfo(LocaleStringData.PMDesignator); - - /// <summary> - /// (user can override) time format - /// </summary> - internal string[] LongTimes - { - get - { - if (_saLongTimes == null) - { - Debug.Assert(!GlobalizationMode.Invariant); - - string[]? longTimes = GetTimeFormats(); - if (longTimes == null || longTimes.Length == 0) - { - _saLongTimes = Invariant._saLongTimes!; - } - else - { - _saLongTimes = longTimes; - } - } - return _saLongTimes; - } - } - - /// <summary> - /// short time format - /// Short times (derived from long times format) - /// </summary> - internal string[] ShortTimes - { - get - { - if (_saShortTimes == null) - { - Debug.Assert(!GlobalizationMode.Invariant); - - // Try to get the short times from the OS/culture.dll - string[]? 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(); - } - - // Found short times, use them - _saShortTimes = shortTimes; - } - return _saShortTimes; - } - } - - 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[] longTimes = LongTimes; - 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 = string.Concat(time.AsSpan(0, j), sep, time.AsSpan(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 shouldEscape = false; - containsSpace = false; - for (; index < time.Length; index++) - { - switch (time[index]) - { - case '\'': - shouldEscape = !shouldEscape; - continue; - case '\\': - index++; - if (time[index] == ' ') - { - containsSpace = true; - } - continue; - case ' ': - containsSpace = true; - break; - case 't': - case 'm': - case 'H': - case 'h': - if (shouldEscape) - { - continue; - } - return index; - } - } - containsSpace = false; - return index; - } - - // (user can override) first day of week - internal int FirstDayOfWeek - { - get - { - if (_iFirstDayOfWeek == undef) - { - _iFirstDayOfWeek = GetFirstDayOfWeek(); - } - return _iFirstDayOfWeek; - } - } - - // (user can override) first week of year - internal int CalendarWeekRule - { - get - { - if (_iFirstWeekOfYear == undef) - { - _iFirstWeekOfYear = GetLocaleInfo(LocaleNumberData.FirstWeekOfYear); - } - return _iFirstWeekOfYear; - } - } - - /// <summary> - /// (user can override default only) short date format - /// </summary> - internal string[] ShortDates(CalendarId calendarId) - { - return GetCalendar(calendarId).saShortDates; - } - - /// <summary> - /// (user can override default only) long date format - /// </summary> - internal string[] LongDates(CalendarId calendarId) - { - return GetCalendar(calendarId).saLongDates; - } - - /// <summary> - /// (user can override) date year/month format. - /// </summary> - internal string[] YearMonths(CalendarId calendarId) - { - return GetCalendar(calendarId).saYearMonths; - } - - internal string[] DayNames(CalendarId calendarId) - { - return GetCalendar(calendarId).saDayNames; - } - - internal string[] AbbreviatedDayNames(CalendarId calendarId) - { - return GetCalendar(calendarId).saAbbrevDayNames; - } - - internal string[] SuperShortDayNames(CalendarId calendarId) - { - return GetCalendar(calendarId).saSuperShortDayNames; - } - - internal string[] MonthNames(CalendarId calendarId) - { - return GetCalendar(calendarId).saMonthNames; - } - - internal string[] GenitiveMonthNames(CalendarId calendarId) - { - return GetCalendar(calendarId).saMonthGenitiveNames; - } - - internal string[] AbbreviatedMonthNames(CalendarId calendarId) - { - return GetCalendar(calendarId).saAbbrevMonthNames; - } - - internal string[] AbbreviatedGenitiveMonthNames(CalendarId calendarId) - { - return GetCalendar(calendarId).saAbbrevMonthGenitiveNames; - } - - /// <remarks>> - /// 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 - /// </remarks> - internal string[] LeapYearMonthNames(CalendarId calendarId) - { - return GetCalendar(calendarId).saLeapYearMonthNames; - } - - internal string MonthDay(CalendarId calendarId) - { - return GetCalendar(calendarId).sMonthDay; - } - - /// <summary> - /// All available calendar type(s). The first one is the default calendar. - /// </summary> - 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]; - Debug.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; - } - } - - /// <summary> - /// Native calendar names. Index of optional calendar - 1, empty if - /// no optional calendar at that number - /// </summary> - internal string CalendarName(CalendarId calendarId) - { - return GetCalendar(calendarId).sNativeName; - } - - internal CalendarData GetCalendar(CalendarId calendarId) - { - Debug.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 - _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) - { - Debug.Assert(_sWindowsName != null, "[CultureData.GetCalendar] Expected _sWindowsName to be populated by already"); - calendarData = new CalendarData(_sWindowsName, calendarId, UseUserOverride); - _calendars[calendarIndex] = calendarData; - } - - return calendarData; - } - - internal bool IsRightToLeft => - // 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 - ReadingLayout == 1; - - /// <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 - /// </summary> - private int ReadingLayout - { - get - { - if (_iReadingLayout == undef) - { - Debug.Assert(_sRealName != null, "[CultureData.IsRightToLeft] Expected _sRealName to be populated by already"); - _iReadingLayout = GetLocaleInfo(LocaleNumberData.ReadingLayout); - } - - return _iReadingLayout; - } - } - - /// <summary> - /// // Text info name to use for text information - /// 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 - /// </summary> - internal string TextInfoName - { - 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. - Debug.Assert(_sRealName != null, "[CultureData.TextInfoName] Expected _sRealName to be populated by already"); - return _sRealName; - } - } - - /// <summary> - /// Compare info name (including sorting key) to use if custom - /// </summary> - internal string SortName - { - get - { - Debug.Assert(_sRealName != null, "[CultureData.SortName] Expected _sRealName to be populated by already"); - return _sRealName; - } - } - - internal bool IsSupplementalCustomCulture => IsCustomCultureId(LCID); - - /// <summary> - /// Default ansi code page ID (ACP) - /// </summary> - internal int ANSICodePage - { - get - { - if (_iDefaultAnsiCodePage == undef) - { - _iDefaultAnsiCodePage = GetAnsiCodePage(_sRealName!); - } - return _iDefaultAnsiCodePage; - } - } - - /// <summary> - /// Default oem code page ID (OCP or OEM). - /// </summary> - internal int OEMCodePage - { - get - { - if (_iDefaultOemCodePage == undef) - { - _iDefaultOemCodePage = GetOemCodePage(_sRealName!); - } - return _iDefaultOemCodePage; - } - } - - /// <summary> - /// Default macintosh code page. - /// </summary> - internal int MacCodePage - { - get - { - if (_iDefaultMacCodePage == undef) - { - _iDefaultMacCodePage = GetMacCodePage(_sRealName!); - } - return _iDefaultMacCodePage; - } - } - - /// <summary> - /// Default EBCDIC code page. - /// </summary> - internal int EBCDICCodePage - { - get - { - if (_iDefaultEbcdicCodePage == undef) - { - _iDefaultEbcdicCodePage = GetEbcdicCodePage(_sRealName!); - } - return _iDefaultEbcdicCodePage; - } - } - - internal int LCID - { - get - { - if (_iLanguage == 0) - { - Debug.Assert(_sRealName != null, "[CultureData.LCID] Expected this.sRealName to be populated already"); - _iLanguage = LocaleNameToLCID(_sRealName); - } - return _iLanguage; - } - } - - internal bool IsNeutralCulture => - // InitCultureData told us if we're neutral or not - _bNeutral; - - internal bool IsInvariantCulture => string.IsNullOrEmpty(Name); - - /// <summary> - /// Get an instance of our default calendar - /// </summary> - internal Calendar DefaultCalendar - { - get - { - if (GlobalizationMode.Invariant) - { - return CultureInfo.GetCalendarInstance(CalendarIds[0]); - } - - CalendarId defaultCalId = (CalendarId)GetLocaleInfo(LocaleNumberData.CalendarType); - - if (defaultCalId == 0) - { - defaultCalId = CalendarIds[0]; - } - - return CultureInfo.GetCalendarInstance(defaultCalId); - } - } - - /// <summary> - /// All of our era names - /// </summary> - internal string[] EraNames(CalendarId calendarId) - { - Debug.Assert(calendarId > 0, "[CultureData.saEraNames] Expected Calendar.ID > 0"); - return GetCalendar(calendarId).saEraNames; - } - - internal string[] AbbrevEraNames(CalendarId calendarId) - { - Debug.Assert(calendarId > 0, "[CultureData.saAbbrevEraNames] Expected Calendar.ID > 0"); - return GetCalendar(calendarId).saAbbrevEraNames; - } - - internal string[] AbbreviatedEnglishEraNames(CalendarId calendarId) - { - Debug.Assert(calendarId > 0, "[CultureData.saAbbrevEraNames] Expected Calendar.ID > 0"); - return GetCalendar(calendarId).saAbbrevEnglishEraNames; - } - - /// <summary> - /// Time separator (derived from time format) - /// </summary> - 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; - } - } - - /// <summary> - /// Date separator (derived from short date format) - /// </summary> - internal string DateSeparator(CalendarId calendarId) - { - if (calendarId == CalendarId.JAPAN && !LocalAppContextSwitches.EnforceLegacyJapaneseDateParsing) - { - // The date separator is derived from the default short date pattern. So far this pattern is using - // '/' as date separator when using the Japanese calendar which make the formatting and parsing work fine. - // changing the default pattern is likely will happen in the near future which can easily break formatting - // and parsing. - // We are forcing here the date separator to '/' to ensure the parsing is not going to break when changing - // the default short date pattern. The application still can override this in the code by DateTimeFormatInfo.DateSeparartor. - return "/"; - } - - return GetDateSeparator(ShortDates(calendarId)[0]); - } - - /// <summary> - /// 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 \. - /// </summary> - private static string UnescapeNlsString(string str, int start, int end) - { - Debug.Assert(str != null); - Debug.Assert(start >= 0); - Debug.Assert(end >= 0); - StringBuilder? result = null; - - for (int i = start; i < str.Length && i <= end; i++) - { - switch (str[i]) - { - case '\'': - result ??= new StringBuilder(str, start, i - start, str.Length); - break; - case '\\': - result ??= new StringBuilder(str, start, i - start, str.Length); - ++i; - if (i < str.Length) - { - result.Append(str[i]); - } - break; - default: - result?.Append(str[i]); - break; - } - } - - if (result == null) - { - return str.Substring(start, end - start + 1); - } - - return result.ToString(); - } - - /// <summary> - /// Time format separator (ie: : in 12:39:00) - /// We calculate this from the provided time format - /// </summary> - private static string GetTimeSeparator(string format) - { - // Find the time separator so that we can pretend we know TimeSeparator. - return GetSeparator(format, "Hhms"); - } - - /// <summary> - /// Date format separator (ie: / in 9/1/03) - /// We calculate this from the provided short date - /// </summary> - private static string GetDateSeparator(string format) - { - // Find the date separator so that we can pretend we know DateSeparator. - 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) - { - Debug.Assert(startIndex >= 0, "startIndex cannot be negative"); - Debug.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.Contains(format[i])) - { - 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; - } - - internal static bool IsCustomCultureId(int cultureId) - { - return cultureId == CultureInfo.LOCALE_CUSTOM_DEFAULT || cultureId == CultureInfo.LOCALE_CUSTOM_UNSPECIFIED; - } - - internal void GetNFIValues(NumberFormatInfo nfi) - { - if (GlobalizationMode.Invariant || IsInvariantCulture) - { - 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 - { - Debug.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] = char.ToString(digits[i]); - } - - Debug.Assert(_sRealName != null); - nfi._digitSubstitution = GetDigitSubstitution(_sRealName); - } - - // Gather additional data - nfi._numberGroupSizes = NumberGroupSizes; - nfi._currencyGroupSizes = CurrencyGroupSizes; - - // prefer the cached value since these do not have user overrides - nfi._percentNegativePattern = PercentNegativePattern; - nfi._percentPositivePattern = PercentPositivePattern; - nfi._percentSymbol = PercentSymbol; - nfi._perMilleSymbol = PerMilleSymbol; - - nfi._negativeInfinitySymbol = NegativeInfinitySymbol; - nfi._positiveInfinitySymbol = PositiveInfinitySymbol; - nfi._nanSymbol = NaNSymbol; - - // 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 (string.IsNullOrEmpty(nfi._positiveSign)) - { - 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 (string.IsNullOrEmpty(nfi._currencyDecimalSeparator)) - { - nfi._currencyDecimalSeparator = nfi._numberDecimalSeparator; - } - } - - /// <remarks> - /// This is ONLY used for caching names and shouldn't be used for anything else - /// </remarks> - internal static string AnsiToLower(string testString) => TextInfo.ToLowerAsciiInvariant(testString); - - /// <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 (corresponds to LOCALE_SLOCALIZEDDISPLAYNAME)</summary> - LocalizedDisplayName = 0x00000002, - /// <summary>Display name (language + country usually) in English, eg "German (Germany)" (corresponds to LOCALE_SENGLISHDISPLAYNAME)</summary> - EnglishDisplayName = 0x00000072, - /// <summary>Display name in native locale language, eg "Deutsch (Deutschland) (corresponds to LOCALE_SNATIVEDISPLAYNAME)</summary> - NativeDisplayName = 0x00000073, - /// <summary>Language Display Name for a language, eg "German" in UI language (corresponds to LOCALE_SLOCALIZEDLANGUAGENAME)</summary> - LocalizedLanguageName = 0x0000006f, - /// <summary>English name of language, eg "German" (corresponds to LOCALE_SENGLISHLANGUAGENAME)</summary> - EnglishLanguageName = 0x00001001, - /// <summary>native name of language, eg "Deutsch" (corresponds to LOCALE_SNATIVELANGUAGENAME)</summary> - NativeLanguageName = 0x00000004, - /// <summary>localized name of country, eg "Germany" in UI language (corresponds to LOCALE_SLOCALIZEDCOUNTRYNAME)</summary> - LocalizedCountryName = 0x00000006, - /// <summary>English name of country, eg "Germany" (corresponds to LOCALE_SENGLISHCOUNTRYNAME)</summary> - EnglishCountryName = 0x00001002, - /// <summary>native name of country, eg "Deutschland" (corresponds to LOCALE_SNATIVECOUNTRYNAME)</summary> - NativeCountryName = 0x00000008, - /// <summary>abbreviated language name (corresponds to LOCALE_SABBREVLANGNAME)</summary> - AbbreviatedWindowsLanguageName = 0x00000003, - /// <summary>list item separator (corresponds to LOCALE_SLIST)</summary> - ListSeparator = 0x0000000C, - /// <summary>decimal separator (corresponds to LOCALE_SDECIMAL)</summary> - DecimalSeparator = 0x0000000E, - /// <summary>thousand separator (corresponds to LOCALE_STHOUSAND)</summary> - ThousandSeparator = 0x0000000F, - /// <summary>digit grouping (corresponds to LOCALE_SGROUPING)</summary> - Digits = 0x00000013, - /// <summary>local monetary symbol (corresponds to LOCALE_SCURRENCY)</summary> - MonetarySymbol = 0x00000014, - /// <summary>English currency name (corresponds to LOCALE_SENGCURRNAME)</summary> - CurrencyEnglishName = 0x00001007, - /// <summary>Native currency name (corresponds to LOCALE_SNATIVECURRNAME)</summary> - CurrencyNativeName = 0x00001008, - /// <summary>uintl monetary symbol (corresponds to LOCALE_SINTLSYMBOL)</summary> - Iso4217MonetarySymbol = 0x00000015, - /// <summary>monetary decimal separator (corresponds to LOCALE_SMONDECIMALSEP)</summary> - MonetaryDecimalSeparator = 0x00000016, - /// <summary>monetary thousand separator (corresponds to LOCALE_SMONTHOUSANDSEP)</summary> - MonetaryThousandSeparator = 0x00000017, - /// <summary>AM designator (corresponds to LOCALE_S1159)</summary> - AMDesignator = 0x00000028, - /// <summary>PM designator (corresponds to LOCALE_S2359)</summary> - PMDesignator = 0x00000029, - /// <summary>positive sign (corresponds to LOCALE_SPOSITIVESIGN)</summary> - PositiveSign = 0x00000050, - /// <summary>negative sign (corresponds to LOCALE_SNEGATIVESIGN)</summary> - NegativeSign = 0x00000051, - /// <summary>ISO abbreviated language name (corresponds to LOCALE_SISO639LANGNAME)</summary> - Iso639LanguageTwoLetterName = 0x00000059, - /// <summary>ISO abbreviated country name (corresponds to LOCALE_SISO639LANGNAME2)</summary> - Iso639LanguageThreeLetterName = 0x00000067, - /// <summary>ISO abbreviated language name (corresponds to LOCALE_SISO639LANGNAME)</summary> - Iso639LanguageName = 0x00000059, - /// <summary>ISO abbreviated country name (corresponds to LOCALE_SISO3166CTRYNAME)</summary> - Iso3166CountryName = 0x0000005A, - /// <summary>3 letter ISO country code (corresponds to LOCALE_SISO3166CTRYNAME2)</summary> - Iso3166CountryName2 = 0x00000068, // 3 character ISO country name - /// <summary>Not a Number (corresponds to LOCALE_SNAN)</summary> - NaNSymbol = 0x00000069, - /// <summary>+ Infinity (corresponds to LOCALE_SPOSINFINITY)</summary> - PositiveInfinitySymbol = 0x0000006a, - /// <summary>- Infinity (corresponds to LOCALE_SNEGINFINITY)</summary> - NegativeInfinitySymbol = 0x0000006b, - /// <summary>Fallback name for resources (corresponds to LOCALE_SPARENT)</summary> - ParentName = 0x0000006d, - /// <summary>Fallback name for within the console (corresponds to LOCALE_SCONSOLEFALLBACKNAME)</summary> - ConsoleFallbackName = 0x0000006e, - /// <summary>Returns the percent symbol (corresponds to LOCALE_SPERCENT)</summary> - PercentSymbol = 0x00000076, - /// <summary>Returns the permille (U+2030) symbol (corresponds 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 (corresponds to LOCALE_SGROUPING)</summary> - Digit = 0x00000010, - /// <summary>monetary grouping (corresponds 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 (corresponds to LOCALE_ILANGUAGE)</summary> - LanguageId = 0x00000001, - /// <summary>geographical location id, (corresponds to LOCALE_IGEOID)</summary> - GeoId = 0x0000005B, - /// <summary>0 = context, 1 = none, 2 = national (corresponds to LOCALE_IDIGITSUBSTITUTION)</summary> - DigitSubstitution = 0x00001014, - /// <summary>0 = metric, 1 = US (corresponds to LOCALE_IMEASURE)</summary> - MeasurementSystem = 0x0000000D, - /// <summary>number of fractional digits (corresponds to LOCALE_IDIGITS)</summary> - FractionalDigitsCount = 0x00000011, - /// <summary>negative number mode (corresponds to LOCALE_INEGNUMBER)</summary> - NegativeNumberFormat = 0x00001010, - /// <summary># local monetary digits (corresponds to LOCALE_ICURRDIGITS)</summary> - MonetaryFractionalDigitsCount = 0x00000019, - /// <summary>positive currency mode (corresponds to LOCALE_ICURRENCY)</summary> - PositiveMonetaryNumberFormat = 0x0000001B, - /// <summary>negative currency mode (corresponds to LOCALE_INEGCURR)</summary> - NegativeMonetaryNumberFormat = 0x0000001C, - /// <summary>type of calendar specifier (corresponds to LOCALE_ICALENDARTYPE)</summary> - CalendarType = 0x00001009, - /// <summary>first day of week specifier (corresponds to LOCALE_IFIRSTDAYOFWEEK)</summary> - FirstDayOfWeek = 0x0000100C, - /// <summary>first week of year specifier (corresponds 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 - /// (corresponds to LOCALE_IREADINGLAYOUT) - /// </summary> - ReadingLayout = 0x00000070, - /// <summary>Returns 0-11 for the negative percent format (corresponds to LOCALE_INEGATIVEPERCENT)</summary> - NegativePercentFormat = 0x00000074, - /// <summary>Returns 0-3 for the positive percent format (corresponds to LOCALE_IPOSITIVEPERCENT)</summary> - PositivePercentFormat = 0x00000075, - /// <summary>default ansi code page (corresponds to LOCALE_IDEFAULTCODEPAGE)</summary> - OemCodePage = 0x0000000B, - /// <summary>default ansi code page (corresponds to LOCALE_IDEFAULTANSICODEPAGE)</summary> - AnsiCodePage = 0x00001004, - /// <summary>default mac code page (corresponds to LOCALE_IDEFAULTMACCODEPAGE)</summary> - MacCodePage = 0x00001011, - /// <summary>default ebcdic code page (corresponds to LOCALE_IDEFAULTEBCDICCODEPAGE)</summary> - EbcdicCodePage = 0x00001012, - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/CultureInfo.Unix.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/CultureInfo.Unix.cs deleted file mode 100644 index 2a16ab6111f..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/CultureInfo.Unix.cs +++ /dev/null @@ -1,36 +0,0 @@ -// 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; - -namespace System.Globalization -{ - public partial class CultureInfo : IFormatProvider - { - internal static CultureInfo GetUserDefaultCulture() - { - if (GlobalizationMode.Invariant) - return CultureInfo.InvariantCulture; - - CultureInfo cultureInfo; - string? localeName; - if (CultureData.GetDefaultLocaleName(out localeName)) - { - Debug.Assert(localeName != null); - cultureInfo = GetCultureByName(localeName); - } - else - { - cultureInfo = CultureInfo.InvariantCulture; - } - - return cultureInfo; - } - - private static CultureInfo GetUserDefaultUICulture() - { - return InitializeUserDefaultCulture(); - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/CultureInfo.Windows.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/CultureInfo.Windows.cs deleted file mode 100644 index 1a8e8e81cb5..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/CultureInfo.Windows.cs +++ /dev/null @@ -1,59 +0,0 @@ -// 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 - { - internal static CultureInfo GetUserDefaultCulture() - { - if (GlobalizationMode.Invariant) - return CultureInfo.InvariantCulture; - - string? strDefault = CultureData.GetLocaleInfoEx(Interop.Kernel32.LOCALE_NAME_USER_DEFAULT, Interop.Kernel32.LOCALE_SNAME); - if (strDefault == null) - { - strDefault = CultureData.GetLocaleInfoEx(Interop.Kernel32.LOCALE_NAME_SYSTEM_DEFAULT, Interop.Kernel32.LOCALE_SNAME); - - if (strDefault == null) - { - // If system default doesn't work, use invariant - return CultureInfo.InvariantCulture; - } - } - - return GetCultureByName(strDefault); - } - - private static unsafe CultureInfo GetUserDefaultUICulture() - { - if (GlobalizationMode.Invariant) - return CultureInfo.InvariantCulture; - - const uint MUI_LANGUAGE_NAME = 0x8; // Use ISO language (culture) name convention - uint langCount = 0; - uint bufLen = 0; - - if (Interop.Kernel32.GetUserPreferredUILanguages(MUI_LANGUAGE_NAME, &langCount, null, &bufLen) != Interop.BOOL.FALSE) - { - char[] languages = new char[bufLen]; - fixed (char* pLanguages = languages) - { - if (Interop.Kernel32.GetUserPreferredUILanguages(MUI_LANGUAGE_NAME, &langCount, pLanguages, &bufLen) != Interop.BOOL.FALSE) - { - int index = 0; - while (languages[index] != (char)0 && index < languages.Length) - { - index++; - } - - return GetCultureByName(new string(languages, 0, index)); - } - } - } - - return InitializeUserDefaultCulture(); - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/CultureInfo.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/CultureInfo.cs deleted file mode 100644 index bc276e2bae0..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/CultureInfo.cs +++ /dev/null @@ -1,1166 +0,0 @@ -// 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.Collections.Generic; -using System.Diagnostics; -using System.Threading; - -namespace System.Globalization -{ - /// <summary> - /// 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. - /// </summary> - /// <remarks> - /// !!!! 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. - /// </remarks> - public partial class CultureInfo : IFormatProvider, ICloneable - { - // We use an RFC4646 type string to construct CultureInfo. - // This string is stored in _name and is authoritative. - // We use the _cultureData to get the data for our object - - private bool _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. - // - internal CultureData _cultureData; - - internal bool _isInherited; - - private CultureInfo? _consoleFallbackCulture; - - // Names are confusing. Here are 3 names we have: - // - // new CultureInfo() _name _nonSortName _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 - - // This has a de-DE, de-DE_phoneb or fj-FJ style name - internal string _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 - private string? _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 - private string? _sortName; - - // Get the current user default culture. This one is almost always used, so we create it by default. - private static volatile CultureInfo? s_userDefaultCulture; - - // The culture used in the user interface. This is mostly used to load correct localized resources. - private static volatile CultureInfo? s_userDefaultUICulture; - - // 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 readonly CultureInfo s_InvariantCultureInfo = new CultureInfo(CultureData.Invariant, isReadOnly: true); - - // 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 CultureInfo? s_currentThreadCulture; - [ThreadStatic] - private static CultureInfo? s_currentThreadUICulture; - - private static AsyncLocal<CultureInfo>? s_asyncLocalCurrentCulture; - private static AsyncLocal<CultureInfo>? s_asyncLocalCurrentUICulture; - - private static void AsyncLocalSetCurrentCulture(AsyncLocalValueChangedArgs<CultureInfo> args) - { - s_currentThreadCulture = args.CurrentValue; - } - - private static void AsyncLocalSetCurrentUICulture(AsyncLocalValueChangedArgs<CultureInfo> args) - { - s_currentThreadUICulture = args.CurrentValue; - } - - private static volatile Dictionary<string, CultureInfo>? s_cachedCulturesByName; - private static volatile Dictionary<int, CultureInfo>? s_cachedCulturesByLcid; - - // The parent culture. - private CultureInfo? _parent; - - // LOCALE constants of interest to us internally and privately for LCID functions - // (ie: avoid using these and use names if possible) - internal const int LOCALE_NEUTRAL = 0x0000; - private const int LOCALE_USER_DEFAULT = 0x0400; - private const int LOCALE_SYSTEM_DEFAULT = 0x0800; - internal const int LOCALE_CUSTOM_UNSPECIFIED = 0x1000; - internal const int LOCALE_CUSTOM_DEFAULT = 0x0c00; - internal const int LOCALE_INVARIANT = 0x007F; - - private static CultureInfo InitializeUserDefaultCulture() - { - Interlocked.CompareExchange(ref s_userDefaultCulture, GetUserDefaultCulture(), null); - return s_userDefaultCulture!; - } - - private static CultureInfo InitializeUserDefaultUICulture() - { - Interlocked.CompareExchange(ref s_userDefaultUICulture, GetUserDefaultUICulture(), null); - return s_userDefaultUICulture!; - } - - public CultureInfo(string name) : this(name, true) - { - } - - public CultureInfo(string name, bool useUserOverride) - { - if (name == null) - { - throw new ArgumentNullException(nameof(name)); - } - - // Get our data providing record - CultureData? cultureData = CultureData.GetCultureData(name, useUserOverride); - - if (cultureData == null) - { - throw new CultureNotFoundException(nameof(name), name, SR.Argument_CultureNotSupported); - } - - _cultureData = cultureData; - _name = _cultureData.CultureName; - _isInherited = GetType() != typeof(CultureInfo); - } - - private CultureInfo(CultureData cultureData, bool isReadOnly = false) - { - Debug.Assert(cultureData != null); - _cultureData = cultureData; - _name = cultureData.CultureName; - _isInherited = false; - _isReadOnly = isReadOnly; - } - - private static CultureInfo? CreateCultureInfoNoThrow(string name, bool useUserOverride) - { - Debug.Assert(name != null); - CultureData? cultureData = CultureData.GetCultureData(name, useUserOverride); - if (cultureData == null) - { - return null; - } - - return new CultureInfo(cultureData); - } - - public CultureInfo(int culture) : this(culture, true) - { - } - - public CultureInfo(int culture, bool useUserOverride) - { - // We don't check for other invalid LCIDS here... - if (culture < 0) - { - throw new ArgumentOutOfRangeException(nameof(culture), SR.ArgumentOutOfRange_NeedPosNum); - } - - switch (culture) - { - case LOCALE_CUSTOM_DEFAULT: - case LOCALE_SYSTEM_DEFAULT: - case LOCALE_NEUTRAL: - case LOCALE_USER_DEFAULT: - case LOCALE_CUSTOM_UNSPECIFIED: - // Can't support unknown custom cultures and we do not support neutral or - // non-custom user locales. - throw new CultureNotFoundException(nameof(culture), culture, SR.Argument_CultureNotSupported); - default: - // Now see if this LCID is supported in the system default CultureData table. - _cultureData = CultureData.GetCultureData(culture, useUserOverride); - break; - } - _isInherited = GetType() != typeof(CultureInfo); - _name = _cultureData.CultureName; - } - - /// <summary> - /// Constructor called by SQL Server's special munged culture - creates a culture with - /// a TextInfo and CompareInfo that come from a supplied alternate source. This object - /// is ALWAYS read-only. - /// Note that we really cannot use an LCID version of this override as the cached - /// name we create for it has to include both names, and the logic for this is in - /// the GetCultureInfo override *only*. - /// </summary> - internal CultureInfo(string cultureName, string textAndCompareCultureName) - { - if (cultureName == null) - { - throw new ArgumentNullException(nameof(cultureName), SR.ArgumentNull_String); - } - - CultureData? cultureData = CultureData.GetCultureData(cultureName, false) ?? - throw new CultureNotFoundException(nameof(cultureName), cultureName, SR.Argument_CultureNotSupported); - - _cultureData = cultureData; - - _name = _cultureData.CultureName; - - CultureInfo altCulture = GetCultureInfo(textAndCompareCultureName); - _compareInfo = altCulture.CompareInfo; - _textInfo = altCulture.TextInfo; - } - - /// <summary> - /// 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) - /// </summary> - private static CultureInfo GetCultureByName(string name) - { - try - { - return new CultureInfo(name) - { - _isReadOnly = true - }; - } - catch (ArgumentException) - { - return InvariantCulture; - } - } - - /// <summary> - /// 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 - /// </summary> - public static CultureInfo CreateSpecificCulture(string name) - { - CultureInfo? culture; - - try - { - culture = new CultureInfo(name); - } - catch (ArgumentException) - { - // When CultureInfo throws this exception, it may be because someone passed the form - // like "az-az" because it came out of an http accept lang. We should try a little - // parsing to perhaps fall back to "az" here and use *it* to create the neutral. - culture = null; - for (int idx = 0; idx < name.Length; idx++) - { - if ('-' == name[idx]) - { - try - { - culture = new CultureInfo(name.Substring(0, idx)); - break; - } - catch (ArgumentException) - { - // throw the original exception so the name in the string will be right - throw; - } - } - } - - if (culture == null) - { - // nothing to save here; throw the original exception - throw; - } - } - - // In the most common case, they've given us a specific culture, so we'll just return that. - if (!culture.IsNeutralCulture) - { - return culture; - } - - return new CultureInfo(culture._cultureData.SpecificCultureName); - } - - 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._isInherited) - { - return true; - } - - return VerifyCultureName(culture.Name, throwException); - } - - /// <summary> - /// This instance provides methods based on the current user settings. - /// These settings are volatile and may change over the lifetime of the - /// thread. - /// </summary> - /// <remarks> - /// 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 - /// </remarks> - public static CultureInfo CurrentCulture - { - get - { - return s_currentThreadCulture ?? - s_DefaultThreadCurrentCulture ?? - s_userDefaultCulture ?? - InitializeUserDefaultCulture(); - } - set - { - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - - if (s_asyncLocalCurrentCulture == null) - { - Interlocked.CompareExchange(ref s_asyncLocalCurrentCulture, new AsyncLocal<CultureInfo>(AsyncLocalSetCurrentCulture), null); - } - s_asyncLocalCurrentCulture!.Value = value; - } - } - - public static CultureInfo CurrentUICulture - { - get - { - return s_currentThreadUICulture ?? - s_DefaultThreadCurrentUICulture ?? - UserDefaultUICulture; - } - set - { - if (value == null) - { - throw new ArgumentNullException(nameof(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; - } - } - - internal static CultureInfo UserDefaultUICulture => s_userDefaultUICulture ?? InitializeUserDefaultUICulture(); - - public static CultureInfo InstalledUICulture => s_userDefaultCulture ?? InitializeUserDefaultCulture(); - - public static CultureInfo? DefaultThreadCurrentCulture - { - get => 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 => 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; - } - } - - /// <summary> - /// 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. - /// </summary> - public static CultureInfo InvariantCulture - { - get - { - Debug.Assert(s_InvariantCultureInfo != null); - return s_InvariantCultureInfo; - } - } - - /// <summary> - /// Return the parent CultureInfo for the current instance. - /// </summary> - public virtual CultureInfo Parent - { - get - { - if (_parent == null) - { - CultureInfo culture; - string parentName = _cultureData.ParentName; - - if (string.IsNullOrEmpty(parentName)) - { - culture = InvariantCulture; - } - else - { - culture = CreateCultureInfoNoThrow(parentName, _cultureData.UseUserOverride) ?? - // 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. - InvariantCulture; - } - - Interlocked.CompareExchange<CultureInfo?>(ref _parent, culture, null); - } - return _parent!; - } - } - - public virtual int LCID => _cultureData.LCID; - - public virtual int KeyboardLayoutId => _cultureData.KeyboardLayoutId; - - public static CultureInfo[] GetCultures(CultureTypes types) - { - // internally we treat UserCustomCultures as Supplementals but v2 - // treats as Supplementals and Replacements - if ((types & CultureTypes.UserCustomCulture) == CultureTypes.UserCustomCulture) - { - types |= CultureTypes.ReplacementCultures; - } - return CultureData.GetCultures(types); - } - - /// <summary> - /// 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. - /// </summary> - public virtual string Name => _nonSortName ??= (_cultureData.Name ?? string.Empty); - - /// <summary> - /// This one has the sort information (ie: de-DE_phoneb) - /// </summary> - internal string SortName => _sortName ??= _cultureData.SortName; - - public string IetfLanguageTag => - // special case the compatibility cultures - Name switch - { - "zh-CHT" => "zh-Hant", - "zh-CHS" => "zh-Hans", - _ => Name, - }; - - /// <summary> - /// 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. - /// </summary> - public virtual string DisplayName - { - get - { - Debug.Assert(_name != null, "[CultureInfo.DisplayName] Always expect _name to be set"); - return _cultureData.DisplayName; - } - } - - /// <summary> - /// 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. - /// </summary> - public virtual string NativeName => _cultureData.NativeName; - - /// <summary> - /// Returns the full name of the CultureInfo in English. - /// For example, if the CultureInfo is US English, "English - /// (United States)" will be returned. - /// </summary> - public virtual string EnglishName => _cultureData.EnglishName; - - /// <summary> - /// ie: en - /// </summary> - public virtual string TwoLetterISOLanguageName => _cultureData.TwoLetterISOLanguageName; - - /// <summary> - /// ie: eng - /// </summary> - public virtual string ThreeLetterISOLanguageName => _cultureData.ThreeLetterISOLanguageName; - - /// <summary> - /// Returns the 3 letter windows language name for the current instance. eg: "ENU" - /// The ISO names are much preferred - /// </summary> - public virtual string ThreeLetterWindowsLanguageName => _cultureData.ThreeLetterWindowsLanguageName; - - /// <summary> - /// Gets the CompareInfo for this culture. - /// </summary> - public virtual CompareInfo CompareInfo => _compareInfo ??= - // 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 - (UseUserOverride ? GetCultureInfo(_name).CompareInfo : new CompareInfo(this)); - - /// <summary> - /// Gets the TextInfo for this culture. - /// </summary> - public virtual TextInfo TextInfo - { - get - { - if (_textInfo == null) - { - // Make a new textInfo - TextInfo tempTextInfo = new TextInfo(_cultureData); - tempTextInfo.SetReadOnlyState(_isReadOnly); - _textInfo = tempTextInfo; - } - return _textInfo; - } - } - - public override bool Equals(object? value) - { - if (object.ReferenceEquals(this, value)) - { - return true; - } - - if (value is CultureInfo that) - { - // using CompareInfo to verify the data passed through the constructor - // CultureInfo(String cultureName, String textAndCompareCultureName) - return Name.Equals(that.Name) && CompareInfo.Equals(that.CompareInfo); - } - - return false; - } - - public override int GetHashCode() - { - return Name.GetHashCode() + CompareInfo.GetHashCode(); - } - - /// <summary> - /// Implements object.ToString(). Returns the name of the CultureInfo, - /// eg. "de-DE_phoneb", "en-US", or "fj-FJ". - /// </summary> - public override string ToString() => _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 => _cultureData.IsNeutralCulture; - - public CultureTypes CultureTypes - { - get - { - CultureTypes types = _cultureData.IsNeutralCulture ? - CultureTypes.NeutralCultures : - CultureTypes.SpecificCultures; - - if (_cultureData.IsWin32Installed) - { - types |= CultureTypes.InstalledWin32Cultures; - } - - if (_cultureData.IsSupplementalCustomCulture) - { - types |= CultureTypes.UserCustomCulture; - } - - if (_cultureData.IsReplacementCulture) - { - types |= CultureTypes.ReplacementCultures; - } - - return types; - } - } - - public virtual NumberFormatInfo NumberFormat - { - get - { - if (_numInfo == null) - { - NumberFormatInfo temp = new NumberFormatInfo(_cultureData); - temp._isReadOnly = _isReadOnly; - Interlocked.CompareExchange(ref _numInfo, temp, null); - } - return _numInfo!; - } - set - { - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - - VerifyWritable(); - _numInfo = value; - } - } - - /// <summary> - /// Create a DateTimeFormatInfo, and fill in the properties according to - /// the CultureID. - /// </summary> - public virtual DateTimeFormatInfo DateTimeFormat - { - get - { - if (_dateTimeInfo == null) - { - // Change the calendar of DTFI to the specified calendar of this CultureInfo. - DateTimeFormatInfo temp = new DateTimeFormatInfo(_cultureData, this.Calendar); - temp._isReadOnly = _isReadOnly; - Interlocked.CompareExchange(ref _dateTimeInfo, temp, null); - } - return _dateTimeInfo!; - } - - set - { - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - - VerifyWritable(); - _dateTimeInfo = value; - } - } - - public void ClearCachedData() - { - // reset the default culture values - s_userDefaultCulture = GetUserDefaultCulture(); - s_userDefaultUICulture = GetUserDefaultUICulture(); - - RegionInfo.s_currentRegionInfo = null; -#pragma warning disable 0618 // disable the obsolete warning - TimeZone.ResetTimeZone(); -#pragma warning restore 0618 - TimeZoneInfo.ClearCachedData(); - s_cachedCulturesByLcid = null; - s_cachedCulturesByName = null; - - CultureData.ClearCachedData(); - } - - /// <summary> - /// Map a Win32 CALID to an instance of supported calendar. - /// </summary> - /// <remarks> - /// 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. - /// </remarks> - internal static Calendar GetCalendarInstance(CalendarId calType) - { - if (calType == CalendarId.GREGORIAN) - { - return new GregorianCalendar(); - } - - return GetCalendarInstanceRare(calType); - } - - /// <summary> - /// This function exists as a shortcut to prevent us from loading all of the non-gregorian - /// calendars unless they're required. - /// </summary> - internal static Calendar GetCalendarInstanceRare(CalendarId calType) - { - Debug.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(); - } - - /// <summary> - /// Return/set the default calendar used by this culture. - /// This value can be overridden by regional option if this is a current culture. - /// </summary> - public virtual Calendar Calendar - { - get - { - if (_calendar == null) - { - Debug.Assert(_cultureData.CalendarIds.Length > 0, "_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 = _cultureData.DefaultCalendar; - - Interlocked.MemoryBarrier(); - newObj.SetReadOnlyState(_isReadOnly); - _calendar = newObj; - } - return _calendar; - } - } - - /// <summary> - /// Return an array of the optional calendar for this culture. - /// </summary> - public virtual Calendar[] OptionalCalendars - { - get - { - // This property always returns a new copy of the calendar array. - CalendarId[] calID = _cultureData.CalendarIds; - Calendar[] cals = new Calendar[calID.Length]; - for (int i = 0; i < cals.Length; i++) - { - cals[i] = GetCalendarInstance(calID[i]); - } - return cals; - } - } - - public bool UseUserOverride => _cultureData.UseUserOverride; - - public CultureInfo GetConsoleFallbackUICulture() - { - CultureInfo? temp = _consoleFallbackCulture; - if (temp == null) - { - temp = CreateSpecificCulture(_cultureData.SCONSOLEFALLBACKNAME); - temp._isReadOnly = true; - _consoleFallbackCulture = temp; - } - return temp; - } - - public virtual object Clone() - { - CultureInfo ci = (CultureInfo)MemberwiseClone(); - ci._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 (!_isInherited) - { - if (_dateTimeInfo != null) - { - ci._dateTimeInfo = (DateTimeFormatInfo)_dateTimeInfo.Clone(); - } - if (_numInfo != null) - { - ci._numInfo = (NumberFormatInfo)_numInfo.Clone(); - } - } - else - { - ci.DateTimeFormat = (DateTimeFormatInfo)this.DateTimeFormat.Clone(); - ci.NumberFormat = (NumberFormatInfo)this.NumberFormat.Clone(); - } - - if (_textInfo != null) - { - ci._textInfo = (TextInfo)_textInfo.Clone(); - } - - if (_dateTimeInfo != null && _dateTimeInfo.Calendar == _calendar) - { - // Usually when we access CultureInfo.DateTimeFormat first time, we create the DateTimeFormatInfo object - // using CultureInfo.Calendar. i.e. CultureInfo.DateTimeInfo.Calendar == CultureInfo.calendar. - // When cloning CultureInfo, if we know it's still the case that CultureInfo.DateTimeInfo.Calendar == CultureInfo.calendar - // then we can keep the same behavior for the cloned object and no need to create another calendar object. - ci._calendar = ci.DateTimeFormat.Calendar; - } - else if (_calendar != null) - { - ci._calendar = (Calendar)_calendar.Clone(); - } - - return ci; - } - - public static CultureInfo ReadOnly(CultureInfo ci) - { - if (ci == null) - { - throw new ArgumentNullException(nameof(ci)); - } - - 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._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._isReadOnly = true; - - return newInfo; - } - - public bool IsReadOnly => _isReadOnly; - - private void VerifyWritable() - { - if (_isReadOnly) - { - throw new InvalidOperationException(SR.InvalidOperation_ReadOnly); - } - } - - /// <summary> - /// 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. - /// </summary> - internal bool HasInvariantCultureName => Name == InvariantCulture.Name; - - /// <summary> - /// Gets a cached copy of the specified culture from an internal - /// hashtable (or creates it if not found). (LCID version) - /// </summary> - public static CultureInfo GetCultureInfo(int culture) - { - if (culture <= 0) - { - throw new ArgumentOutOfRangeException(nameof(culture), SR.ArgumentOutOfRange_NeedPosNum); - } - - Dictionary<int, CultureInfo> lcidTable = CachedCulturesByLcid; - CultureInfo? result; - - lock (lcidTable) - { - if (lcidTable.TryGetValue(culture, out result)) - { - return result; - } - } - - try - { - result = new CultureInfo(culture, useUserOverride: false) { _isReadOnly = true }; - } - catch (ArgumentException) - { - throw new CultureNotFoundException(nameof(culture), culture, SR.Argument_CultureNotSupported); - } - - lock (lcidTable) - { - lcidTable[culture] = result; - } - - return result; - } - - /// <summary> - /// Gets a cached copy of the specified culture from an internal - /// hashtable (or creates it if not found). (Named version) - /// </summary> - public static CultureInfo GetCultureInfo(string name) - { - // Make sure we have a valid, non-zero length string as name - if (name is null) - { - throw new ArgumentNullException(nameof(name)); - } - - name = CultureData.AnsiToLower(name); - Dictionary<string, CultureInfo> nameTable = CachedCulturesByName; - CultureInfo? result; - - lock (nameTable) - { - if (nameTable.TryGetValue(name, out result)) - { - return result; - } - } - - result = CreateCultureInfoNoThrow(name, useUserOverride: false) ?? - throw new CultureNotFoundException(nameof(name), name, SR.Argument_CultureNotSupported); - result._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). - name = CultureData.AnsiToLower(result._name); - - lock (nameTable) - { - nameTable[name] = result; - } - - return result; - } - - /// <summary> - /// Gets a cached copy of the specified culture from an internal - /// hashtable (or creates it if not found). - /// </summary> - public static CultureInfo GetCultureInfo(string name, string altName) - { - if (name is null) - { - throw new ArgumentNullException(nameof(name)); - } - if (altName is null) - { - throw new ArgumentNullException(nameof(altName)); - } - - name = CultureData.AnsiToLower(name); - altName = CultureData.AnsiToLower(altName); - string nameAndAltName = name + "\xfffd" + altName; - Dictionary<string, CultureInfo> nameTable = CachedCulturesByName; - CultureInfo? result; - - lock (nameTable) - { - if (nameTable.TryGetValue(nameAndAltName, out result)) - { - return result; - } - } - - try - { - result = new CultureInfo(name, altName) { _isReadOnly = true }; - result.TextInfo.SetReadOnlyState(readOnly: true); // TextInfo object is already created; we need to set it as read only. - } - catch (ArgumentException) - { - throw new CultureNotFoundException("name/altName", SR.Format(SR.Argument_OneOfCulturesNotSupported, name, altName)); - } - - lock (nameTable) - { - nameTable[nameAndAltName] = result; - } - - return result; - } - - private static Dictionary<string, CultureInfo> CachedCulturesByName - { - get - { - Dictionary<string, CultureInfo>? cache = s_cachedCulturesByName; - if (cache is null) - { - cache = new Dictionary<string, CultureInfo>(); - cache = Interlocked.CompareExchange(ref s_cachedCulturesByName, cache, null) ?? cache; - } - - return cache; - } - } - - private static Dictionary<int, CultureInfo> CachedCulturesByLcid - { - get - { - Dictionary<int, CultureInfo>? cache = s_cachedCulturesByLcid; - if (cache is null) - { - cache = new Dictionary<int, CultureInfo>(); - cache = Interlocked.CompareExchange(ref s_cachedCulturesByLcid, cache, null) ?? cache; - } - - return cache; - } - } - - public static CultureInfo GetCultureInfoByIetfLanguageTag(string name) - { - // Disallow old zh-CHT/zh-CHS names - if (name == "zh-CHT" || name == "zh-CHS") - { - throw new CultureNotFoundException(nameof(name), SR.Format(SR.Argument_CultureIetfNotSupported, name)); - } - - CultureInfo ci = GetCultureInfo(name); - - // Disallow alt sorts and es-es_TS - if (ci.LCID > 0xffff || ci.LCID == 0x040a) - { - throw new CultureNotFoundException(nameof(name), SR.Format(SR.Argument_CultureIetfNotSupported, name)); - } - - return ci; - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/CultureNotFoundException.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/CultureNotFoundException.cs deleted file mode 100644 index 5869b6ae51d..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/CultureNotFoundException.cs +++ /dev/null @@ -1,104 +0,0 @@ -// 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.Serialization; - -namespace System.Globalization -{ - [Serializable] - [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] - public class CultureNotFoundException : ArgumentException - { - private readonly string? _invalidCultureName; // unrecognized culture name - private readonly int? _invalidCultureId; // unrecognized culture Lcid - - 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; - } - - public CultureNotFoundException(string? message, int invalidCultureId, Exception? innerException) - : base(message, innerException) - { - _invalidCultureId = invalidCultureId; - } - - public CultureNotFoundException(string? paramName, int invalidCultureId, string? message) - : base(message, paramName) - { - _invalidCultureId = invalidCultureId; - } - - protected CultureNotFoundException(SerializationInfo info, StreamingContext context) - : base(info, context) - { - _invalidCultureId = (int?)info.GetValue("InvalidCultureId", typeof(int?)); - _invalidCultureName = (string?)info.GetValue("InvalidCultureName", typeof(string)); - } - - public override void GetObjectData(SerializationInfo info, StreamingContext context) - { - base.GetObjectData(info, context); - info.AddValue("InvalidCultureId", _invalidCultureId, typeof(int?)); - info.AddValue("InvalidCultureName", _invalidCultureName, typeof(string)); - } - - public virtual int? InvalidCultureId => _invalidCultureId; - - public virtual string? InvalidCultureName => _invalidCultureName; - - private static string DefaultMessage => SR.Argument_CultureNotSupported; - - private string? FormattedInvalidCultureId => - InvalidCultureId != null ? - string.Format(CultureInfo.InvariantCulture, "{0} (0x{0:x4})", (int)InvalidCultureId) : - InvalidCultureName; - - public override string Message - { - get - { - string s = base.Message; - if (_invalidCultureId != null || _invalidCultureName != null) - { - string valueMessage = SR.Format(SR.Argument_CultureInvalidIdentifier, FormattedInvalidCultureId); - if (s == null) - { - return valueMessage; - } - - return s + Environment.NewLineConst + valueMessage; - } - return s; - } - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/CultureTypes.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/CultureTypes.cs deleted file mode 100644 index f780b1ce57c..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/CultureTypes.cs +++ /dev/null @@ -1,27 +0,0 @@ -// 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. - -// The enumeration constants used in CultureInfo.GetCultures(). -// On Linux platforms, the only enum values used there is NeutralCultures and SpecificCultures -// the rest are obsolete or not valid on Linux - -namespace System.Globalization -{ - [Flags] - public enum CultureTypes - { - NeutralCultures = 0x0001, // Neutral cultures are cultures like "en", "de", "zh", etc, for enumeration this includes ALL neutrals regardless of other flags - SpecificCultures = 0x0002, // Non-netural cultuers. Examples are "en-us", "zh-tw", etc., for enumeration this includes ALL specifics regardless of other flags - InstalledWin32Cultures = 0x0004, // Win32 installed cultures in the system and exists in the framework too., this is effectively all cultures - - AllCultures = NeutralCultures | SpecificCultures | InstalledWin32Cultures, - - UserCustomCulture = 0x0008, // User defined custom culture - ReplacementCultures = 0x0010, // User defined replacement custom culture. - [Obsolete("This value has been deprecated. Please use other values in CultureTypes.")] - WindowsOnlyCultures = 0x0020, // this will always return empty list. - [Obsolete("This value has been deprecated. Please use other values in CultureTypes.")] - FrameworkCultures = 0x0040, // will return only the v2 cultures marked as Framework culture. - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/DateTimeFormat.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/DateTimeFormat.cs deleted file mode 100644 index 8f8944bba2f..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/DateTimeFormat.cs +++ /dev/null @@ -1,1380 +0,0 @@ -// 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; -using System.Globalization; -using System.Text; -using System.Runtime.InteropServices; -using System.Runtime.CompilerServices; - -namespace System -{ - /* - Customized format patterns: - P.S. Format in the table below is the internal number format used to display the pattern. - - Patterns Format Description Example - ========= ========== ===================================== ======== - "h" "0" hour (12-hour clock)w/o leading zero 3 - "hh" "00" hour (12-hour clock)with leading zero 03 - "hh*" "00" hour (12-hour clock)with leading zero 03 - - "H" "0" hour (24-hour clock)w/o leading zero 8 - "HH" "00" hour (24-hour clock)with leading zero 08 - "HH*" "00" hour (24-hour clock) 08 - - "m" "0" minute w/o leading zero - "mm" "00" minute with leading zero - "mm*" "00" minute with leading zero - - "s" "0" second w/o leading zero - "ss" "00" second with leading zero - "ss*" "00" second with leading zero - - "f" "0" second fraction (1 digit) - "ff" "00" second fraction (2 digit) - "fff" "000" second fraction (3 digit) - "ffff" "0000" second fraction (4 digit) - "fffff" "00000" second fraction (5 digit) - "ffffff" "000000" second fraction (6 digit) - "fffffff" "0000000" second fraction (7 digit) - - "F" "0" second fraction (up to 1 digit) - "FF" "00" second fraction (up to 2 digit) - "FFF" "000" second fraction (up to 3 digit) - "FFFF" "0000" second fraction (up to 4 digit) - "FFFFF" "00000" second fraction (up to 5 digit) - "FFFFFF" "000000" second fraction (up to 6 digit) - "FFFFFFF" "0000000" second fraction (up to 7 digit) - - "t" first character of AM/PM designator A - "tt" AM/PM designator AM - "tt*" AM/PM designator PM - - "d" "0" day w/o leading zero 1 - "dd" "00" day with leading zero 01 - "ddd" short weekday name (abbreviation) Mon - "dddd" full weekday name Monday - "dddd*" full weekday name Monday - - - "M" "0" month w/o leading zero 2 - "MM" "00" month with leading zero 02 - "MMM" short month name (abbreviation) Feb - "MMMM" full month name Febuary - "MMMM*" full month name Febuary - - "y" "0" two digit year (year % 100) w/o leading zero 0 - "yy" "00" two digit year (year % 100) with leading zero 00 - "yyy" "D3" year 2000 - "yyyy" "D4" year 2000 - "yyyyy" "D5" year 2000 - ... - - "z" "+0;-0" timezone offset w/o leading zero -8 - "zz" "+00;-00" timezone offset with leading zero -08 - "zzz" "+00;-00" for hour offset, "00" for minute offset full timezone offset -07:30 - "zzz*" "+00;-00" for hour offset, "00" for minute offset full timezone offset -08:00 - - "K" -Local "zzz", e.g. -08:00 - -Utc "'Z'", representing UTC - -Unspecified "" - -DateTimeOffset "zzzzz" e.g -07:30:15 - - "g*" the current era name A.D. - - ":" time separator : -- DEPRECATED - Insert separator directly into pattern (eg: "H.mm.ss") - "/" date separator /-- DEPRECATED - Insert separator directly into pattern (eg: "M-dd-yyyy") - "'" quoted string 'ABC' will insert ABC into the formatted string. - '"' quoted string "ABC" will insert ABC into the formatted string. - "%" used to quote a single pattern characters E.g.The format character "%y" is to print two digit year. - "\" escaped character E.g. '\d' insert the character 'd' into the format string. - other characters insert the character into the format string. - - Pre-defined format characters: - (U) to indicate Universal time is used. - (G) to indicate Gregorian calendar is used. - - Format Description Real format Example - ========= ================================= ====================== ======================= - "d" short date culture-specific 10/31/1999 - "D" long data culture-specific Sunday, October 31, 1999 - "f" full date (long date + short time) culture-specific Sunday, October 31, 1999 2:00 AM - "F" full date (long date + long time) culture-specific Sunday, October 31, 1999 2:00:00 AM - "g" general date (short date + short time) culture-specific 10/31/1999 2:00 AM - "G" general date (short date + long time) culture-specific 10/31/1999 2:00:00 AM - "m"/"M" Month/Day date culture-specific October 31 -(G) "o"/"O" Round Trip XML "yyyy-MM-ddTHH:mm:ss.fffffffK" 1999-10-31 02:00:00.0000000Z -(G) "r"/"R" RFC 1123 date, "ddd, dd MMM yyyy HH':'mm':'ss 'GMT'" Sun, 31 Oct 1999 10:00:00 GMT -(G) "s" Sortable format, based on ISO 8601. "yyyy-MM-dd'T'HH:mm:ss" 1999-10-31T02:00:00 - ('T' for local time) - "t" short time culture-specific 2:00 AM - "T" long time culture-specific 2:00:00 AM -(G) "u" Universal time with sortable format, "yyyy'-'MM'-'dd HH':'mm':'ss'Z'" 1999-10-31 10:00:00Z - based on ISO 8601. -(U) "U" Universal time with full culture-specific Sunday, October 31, 1999 10:00:00 AM - (long date + long time) format - "y"/"Y" Year/Month day culture-specific October, 1999 - - */ - - // This class contains only static members and does not require the serializable attribute. - internal static - class DateTimeFormat - { - internal const int MaxSecondsFractionDigits = 7; - internal static readonly TimeSpan NullOffset = TimeSpan.MinValue; - - internal static char[] allStandardFormats = - { - 'd', 'D', 'f', 'F', 'g', 'G', - 'm', 'M', 'o', 'O', 'r', 'R', - 's', 't', 'T', 'u', 'U', 'y', 'Y', - }; - - internal const string RoundtripFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss.fffffffK"; - internal const string RoundtripDateTimeUnfixed = "yyyy'-'MM'-'ddTHH':'mm':'ss zzz"; - - private const int DEFAULT_ALL_DATETIMES_SIZE = 132; - - internal static readonly DateTimeFormatInfo InvariantFormatInfo = CultureInfo.InvariantCulture.DateTimeFormat; - internal static readonly string[] InvariantAbbreviatedMonthNames = InvariantFormatInfo.AbbreviatedMonthNames; - internal static readonly string[] InvariantAbbreviatedDayNames = InvariantFormatInfo.AbbreviatedDayNames; - internal const string Gmt = "GMT"; - - internal static string[] fixedNumberFormats = new string[] { - "0", - "00", - "000", - "0000", - "00000", - "000000", - "0000000", - }; - - //////////////////////////////////////////////////////////////////////////// - // - // Format the positive integer value to a string and prefix with assigned - // length of leading zero. - // - // Parameters: - // value: The value to format - // len: The maximum length for leading zero. - // If the digits of the value is greater than len, no leading zero is added. - // - // Notes: - // The function can format to int.MaxValue. - // - //////////////////////////////////////////////////////////////////////////// - internal static void FormatDigits(StringBuilder outputBuffer, int value, int len) - { - Debug.Assert(value >= 0, "DateTimeFormat.FormatDigits(): value >= 0"); - FormatDigits(outputBuffer, value, len, false); - } - - internal static unsafe void FormatDigits(StringBuilder outputBuffer, int value, int len, bool overrideLengthLimit) - { - Debug.Assert(value >= 0, "DateTimeFormat.FormatDigits(): value >= 0"); - - // Limit the use of this function to be two-digits, so that we have the same behavior - // as RTM bits. - if (!overrideLengthLimit && len > 2) - { - len = 2; - } - - char* buffer = stackalloc char[16]; - char* p = buffer + 16; - int n = value; - do - { - *--p = (char)(n % 10 + '0'); - n /= 10; - } while ((n != 0) && (p > buffer)); - - int digits = (int)(buffer + 16 - p); - - // If the repeat count is greater than 0, we're trying - // to emulate the "00" format, so we have to prepend - // a zero if the string only has one character. - while ((digits < len) && (p > buffer)) - { - *--p = '0'; - digits++; - } - outputBuffer.Append(p, digits); - } - - private static void HebrewFormatDigits(StringBuilder outputBuffer, int digits) - { - HebrewNumber.Append(outputBuffer, digits); - } - - internal static int ParseRepeatPattern(ReadOnlySpan<char> format, int pos, char patternChar) - { - int len = format.Length; - int index = pos + 1; - while ((index < len) && (format[index] == patternChar)) - { - index++; - } - return index - pos; - } - - private static string FormatDayOfWeek(int dayOfWeek, int repeat, DateTimeFormatInfo dtfi) - { - Debug.Assert(dayOfWeek >= 0 && dayOfWeek <= 6, "dayOfWeek >= 0 && dayOfWeek <= 6"); - if (repeat == 3) - { - return dtfi.GetAbbreviatedDayName((DayOfWeek)dayOfWeek); - } - // Call dtfi.GetDayName() here, instead of accessing DayNames property, because we don't - // want a clone of DayNames, which will hurt perf. - return dtfi.GetDayName((DayOfWeek)dayOfWeek); - } - - private static string FormatMonth(int month, int repeatCount, DateTimeFormatInfo dtfi) - { - Debug.Assert(month >= 1 && month <= 12, "month >=1 && month <= 12"); - if (repeatCount == 3) - { - return dtfi.GetAbbreviatedMonthName(month); - } - // Call GetMonthName() here, instead of accessing MonthNames property, because we don't - // want a clone of MonthNames, which will hurt perf. - return dtfi.GetMonthName(month); - } - - // - // FormatHebrewMonthName - // - // Action: Return the Hebrew month name for the specified DateTime. - // Returns: The month name string for the specified DateTime. - // Arguments: - // time the time to format - // month The month is the value of HebrewCalendar.GetMonth(time). - // repeat Return abbreviated month name if repeat=3, or full month name if repeat=4 - // dtfi The DateTimeFormatInfo which uses the Hebrew calendars as its calendar. - // Exceptions: None. - // - - /* Note: - If DTFI is using Hebrew calendar, GetMonthName()/GetAbbreviatedMonthName() will return month names like this: - 1 Hebrew 1st Month - 2 Hebrew 2nd Month - .. ... - 6 Hebrew 6th Month - 7 Hebrew 6th Month II (used only in a leap year) - 8 Hebrew 7th Month - 9 Hebrew 8th Month - 10 Hebrew 9th Month - 11 Hebrew 10th Month - 12 Hebrew 11th Month - 13 Hebrew 12th Month - - Therefore, if we are in a regular year, we have to increment the month name if month is greater or equal to 7. - */ - private static string FormatHebrewMonthName(DateTime time, int month, int repeatCount, DateTimeFormatInfo dtfi) - { - Debug.Assert(repeatCount != 3 || repeatCount != 4, "repeateCount should be 3 or 4"); - if (dtfi.Calendar.IsLeapYear(dtfi.Calendar.GetYear(time))) - { - // This month is in a leap year - return dtfi.InternalGetMonthName(month, MonthNameStyles.LeapYear, repeatCount == 3); - } - // This is in a regular year. - if (month >= 7) - { - month++; - } - if (repeatCount == 3) - { - return dtfi.GetAbbreviatedMonthName(month); - } - return dtfi.GetMonthName(month); - } - - // - // The pos should point to a quote character. This method will - // append to the result StringBuilder the string enclosed by the quote character. - // - internal static int ParseQuoteString(ReadOnlySpan<char> format, int pos, StringBuilder result) - { - // - // NOTE : pos will be the index of the quote character in the 'format' string. - // - int formatLen = format.Length; - int beginPos = pos; - char quoteChar = format[pos++]; // Get the character used to quote the following string. - - bool foundQuote = false; - while (pos < formatLen) - { - char ch = format[pos++]; - if (ch == quoteChar) - { - foundQuote = true; - break; - } - else if (ch == '\\') - { - // The following are used to support escaped character. - // Escaped character is also supported in the quoted string. - // Therefore, someone can use a format like "'minute:' mm\"" to display: - // minute: 45" - // because the second double quote is escaped. - if (pos < formatLen) - { - result.Append(format[pos++]); - } - else - { - // - // This means that '\' is at the end of the formatting string. - // - throw new FormatException(SR.Format_InvalidString); - } - } - else - { - result.Append(ch); - } - } - - if (!foundQuote) - { - // Here we can't find the matching quote. - throw new FormatException(SR.Format(SR.Format_BadQuote, quoteChar)); - } - - // - // Return the character count including the begin/end quote characters and enclosed string. - // - return pos - beginPos; - } - - // - // Get the next character at the index of 'pos' in the 'format' string. - // Return value of -1 means 'pos' is already at the end of the 'format' string. - // Otherwise, return value is the int value of the next character. - // - internal static int ParseNextChar(ReadOnlySpan<char> format, int pos) - { - if (pos >= format.Length - 1) - { - return -1; - } - return (int)format[pos + 1]; - } - - // - // IsUseGenitiveForm - // - // Actions: Check the format to see if we should use genitive month in the formatting. - // Starting at the position (index) in the (format) string, look back and look ahead to - // see if there is "d" or "dd". In the case like "d MMMM" or "MMMM dd", we can use - // genitive form. Genitive form is not used if there is more than two "d". - // Arguments: - // format The format string to be scanned. - // index Where we should start the scanning. This is generally where "M" starts. - // tokenLen The len of the current pattern character. This indicates how many "M" that we have. - // patternToMatch The pattern that we want to search. This generally uses "d" - // - private static bool IsUseGenitiveForm(ReadOnlySpan<char> format, int index, int tokenLen, char patternToMatch) - { - int i; - int repeat = 0; - // - // Look back to see if we can find "d" or "ddd" - // - - // Find first "d". - for (i = index - 1; i >= 0 && format[i] != patternToMatch; i--) { /*Do nothing here */ } - - if (i >= 0) - { - // Find a "d", so look back to see how many "d" that we can find. - while (--i >= 0 && format[i] == patternToMatch) - { - repeat++; - } - // - // repeat == 0 means that we have one (patternToMatch) - // repeat == 1 means that we have two (patternToMatch) - // - if (repeat <= 1) - { - return true; - } - // Note that we can't just stop here. We may find "ddd" while looking back, and we have to look - // ahead to see if there is "d" or "dd". - } - - // - // If we can't find "d" or "dd" by looking back, try look ahead. - // - - // Find first "d" - for (i = index + tokenLen; i < format.Length && format[i] != patternToMatch; i++) { /* Do nothing here */ } - - if (i < format.Length) - { - repeat = 0; - // Find a "d", so contine the walk to see how may "d" that we can find. - while (++i < format.Length && format[i] == patternToMatch) - { - repeat++; - } - // - // repeat == 0 means that we have one (patternToMatch) - // repeat == 1 means that we have two (patternToMatch) - // - if (repeat <= 1) - { - return true; - } - } - return false; - } - - // - // FormatCustomized - // - // Actions: Format the DateTime instance using the specified format. - // - private static StringBuilder FormatCustomized( - DateTime dateTime, ReadOnlySpan<char> format, DateTimeFormatInfo dtfi, TimeSpan offset, StringBuilder? result) - { - Calendar cal = dtfi.Calendar; - - bool resultBuilderIsPooled = false; - if (result == null) - { - resultBuilderIsPooled = true; - result = StringBuilderCache.Acquire(); - } - - // This is a flag to indicate if we are formatting the dates using Hebrew calendar. - bool isHebrewCalendar = (cal.ID == CalendarId.HEBREW); - bool isJapaneseCalendar = (cal.ID == CalendarId.JAPAN); - // This is a flag to indicate if we are formatting hour/minute/second only. - bool bTimeOnly = true; - - int i = 0; - int tokenLen, hour12; - - while (i < format.Length) - { - char ch = format[i]; - int nextChar; - switch (ch) - { - case 'g': - tokenLen = ParseRepeatPattern(format, i, ch); - result.Append(dtfi.GetEraName(cal.GetEra(dateTime))); - break; - case 'h': - tokenLen = ParseRepeatPattern(format, i, ch); - hour12 = dateTime.Hour % 12; - if (hour12 == 0) - { - hour12 = 12; - } - FormatDigits(result, hour12, tokenLen); - break; - case 'H': - tokenLen = ParseRepeatPattern(format, i, ch); - FormatDigits(result, dateTime.Hour, tokenLen); - break; - case 'm': - tokenLen = ParseRepeatPattern(format, i, ch); - FormatDigits(result, dateTime.Minute, tokenLen); - break; - case 's': - tokenLen = ParseRepeatPattern(format, i, ch); - FormatDigits(result, dateTime.Second, tokenLen); - break; - case 'f': - case 'F': - tokenLen = ParseRepeatPattern(format, i, ch); - if (tokenLen <= MaxSecondsFractionDigits) - { - long fraction = (dateTime.Ticks % Calendar.TicksPerSecond); - fraction /= (long)Math.Pow(10, 7 - tokenLen); - if (ch == 'f') - { - result.AppendSpanFormattable((int)fraction, fixedNumberFormats[tokenLen - 1], CultureInfo.InvariantCulture); - } - else - { - int effectiveDigits = tokenLen; - while (effectiveDigits > 0) - { - if (fraction % 10 == 0) - { - fraction /= 10; - effectiveDigits--; - } - else - { - break; - } - } - if (effectiveDigits > 0) - { - result.AppendSpanFormattable((int)fraction, fixedNumberFormats[effectiveDigits - 1], CultureInfo.InvariantCulture); - } - else - { - // No fraction to emit, so see if we should remove decimal also. - if (result.Length > 0 && result[result.Length - 1] == '.') - { - result.Remove(result.Length - 1, 1); - } - } - } - } - else - { - if (resultBuilderIsPooled) - { - StringBuilderCache.Release(result); - } - throw new FormatException(SR.Format_InvalidString); - } - break; - case 't': - tokenLen = ParseRepeatPattern(format, i, ch); - if (tokenLen == 1) - { - if (dateTime.Hour < 12) - { - if (dtfi.AMDesignator.Length >= 1) - { - result.Append(dtfi.AMDesignator[0]); - } - } - else - { - if (dtfi.PMDesignator.Length >= 1) - { - result.Append(dtfi.PMDesignator[0]); - } - } - } - else - { - result.Append(dateTime.Hour < 12 ? dtfi.AMDesignator : dtfi.PMDesignator); - } - break; - case 'd': - // - // tokenLen == 1 : Day of month as digits with no leading zero. - // tokenLen == 2 : Day of month as digits with leading zero for single-digit months. - // tokenLen == 3 : Day of week as a three-letter abbreviation. - // tokenLen >= 4 : Day of week as its full name. - // - tokenLen = ParseRepeatPattern(format, i, ch); - if (tokenLen <= 2) - { - int day = cal.GetDayOfMonth(dateTime); - if (isHebrewCalendar) - { - // For Hebrew calendar, we need to convert numbers to Hebrew text for yyyy, MM, and dd values. - HebrewFormatDigits(result, day); - } - else - { - FormatDigits(result, day, tokenLen); - } - } - else - { - int dayOfWeek = (int)cal.GetDayOfWeek(dateTime); - result.Append(FormatDayOfWeek(dayOfWeek, tokenLen, dtfi)); - } - bTimeOnly = false; - break; - case 'M': - // - // tokenLen == 1 : Month as digits with no leading zero. - // tokenLen == 2 : Month as digits with leading zero for single-digit months. - // tokenLen == 3 : Month as a three-letter abbreviation. - // tokenLen >= 4 : Month as its full name. - // - tokenLen = ParseRepeatPattern(format, i, ch); - int month = cal.GetMonth(dateTime); - if (tokenLen <= 2) - { - if (isHebrewCalendar) - { - // For Hebrew calendar, we need to convert numbers to Hebrew text for yyyy, MM, and dd values. - HebrewFormatDigits(result, month); - } - else - { - FormatDigits(result, month, tokenLen); - } - } - else - { - if (isHebrewCalendar) - { - result.Append(FormatHebrewMonthName(dateTime, month, tokenLen, dtfi)); - } - else - { - if ((dtfi.FormatFlags & DateTimeFormatFlags.UseGenitiveMonth) != 0) - { - result.Append( - dtfi.InternalGetMonthName( - month, - IsUseGenitiveForm(format, i, tokenLen, 'd') ? MonthNameStyles.Genitive : MonthNameStyles.Regular, - tokenLen == 3)); - } - else - { - result.Append(FormatMonth(month, tokenLen, dtfi)); - } - } - } - bTimeOnly = false; - break; - case 'y': - // Notes about OS behavior: - // y: Always print (year % 100). No leading zero. - // yy: Always print (year % 100) with leading zero. - // yyy/yyyy/yyyyy/... : Print year value. No leading zero. - - int year = cal.GetYear(dateTime); - tokenLen = ParseRepeatPattern(format, i, ch); - if (isJapaneseCalendar && - !LocalAppContextSwitches.FormatJapaneseFirstYearAsANumber && - year == 1 && - ((i + tokenLen < format.Length && format[i + tokenLen] == DateTimeFormatInfoScanner.CJKYearSuff[0]) || - (i + tokenLen < format.Length - 1 && format[i + tokenLen] == '\'' && format[i + tokenLen + 1] == DateTimeFormatInfoScanner.CJKYearSuff[0]))) - { - // We are formatting a Japanese date with year equals 1 and the year number is followed by the year sign \u5e74 - // In Japanese dates, the first year in the era is not formatted as a number 1 instead it is formatted as \u5143 which means - // first or beginning of the era. - result.Append(DateTimeFormatInfo.JapaneseEraStart[0]); - } - else if (dtfi.HasForceTwoDigitYears) - { - FormatDigits(result, year, tokenLen <= 2 ? tokenLen : 2); - } - else if (cal.ID == CalendarId.HEBREW) - { - HebrewFormatDigits(result, year); - } - else - { - if (tokenLen <= 2) - { - FormatDigits(result, year % 100, tokenLen); - } - else if (tokenLen <= 16) // FormatDigits has an implicit 16-digit limit - { - FormatDigits(result, year, tokenLen, overrideLengthLimit: true); - } - else - { - result.Append(year.ToString("D" + tokenLen.ToString(), CultureInfo.InvariantCulture)); - } - } - bTimeOnly = false; - break; - case 'z': - tokenLen = ParseRepeatPattern(format, i, ch); - FormatCustomizedTimeZone(dateTime, offset, tokenLen, bTimeOnly, result); - break; - case 'K': - tokenLen = 1; - FormatCustomizedRoundripTimeZone(dateTime, offset, result); - break; - case ':': - result.Append(dtfi.TimeSeparator); - tokenLen = 1; - break; - case '/': - result.Append(dtfi.DateSeparator); - tokenLen = 1; - break; - case '\'': - case '\"': - tokenLen = ParseQuoteString(format, i, result); - break; - case '%': - // Optional format character. - // For example, format string "%d" will print day of month - // without leading zero. Most of the cases, "%" can be ignored. - nextChar = ParseNextChar(format, i); - // nextChar will be -1 if we have already reached the end of the format string. - // Besides, we will not allow "%%" to appear in the pattern. - if (nextChar >= 0 && nextChar != '%') - { - char nextCharChar = (char)nextChar; - StringBuilder origStringBuilder = FormatCustomized(dateTime, MemoryMarshal.CreateReadOnlySpan<char>(ref nextCharChar, 1), dtfi, offset, result); - Debug.Assert(ReferenceEquals(origStringBuilder, result)); - tokenLen = 2; - } - else - { - // - // This means that '%' is at the end of the format string or - // "%%" appears in the format string. - // - if (resultBuilderIsPooled) - { - StringBuilderCache.Release(result); - } - throw new FormatException(SR.Format_InvalidString); - } - break; - case '\\': - // Escaped character. Can be used to insert a character into the format string. - // For exmple, "\d" will insert the character 'd' into the string. - // - // NOTENOTE : we can remove this format character if we enforce the enforced quote - // character rule. - // That is, we ask everyone to use single quote or double quote to insert characters, - // then we can remove this character. - // - nextChar = ParseNextChar(format, i); - if (nextChar >= 0) - { - result.Append((char)nextChar); - tokenLen = 2; - } - else - { - // - // This means that '\' is at the end of the formatting string. - // - if (resultBuilderIsPooled) - { - StringBuilderCache.Release(result); - } - throw new FormatException(SR.Format_InvalidString); - } - break; - default: - // NOTENOTE : we can remove this rule if we enforce the enforced quote - // character rule. - // That is, if we ask everyone to use single quote or double quote to insert characters, - // then we can remove this default block. - result.Append(ch); - tokenLen = 1; - break; - } - i += tokenLen; - } - return result; - } - - // output the 'z' family of formats, which output a the offset from UTC, e.g. "-07:30" - private static void FormatCustomizedTimeZone(DateTime dateTime, TimeSpan offset, int tokenLen, bool timeOnly, StringBuilder result) - { - // See if the instance already has an offset - bool dateTimeFormat = (offset == NullOffset); - if (dateTimeFormat) - { - // No offset. The instance is a DateTime and the output should be the local time zone - - if (timeOnly && dateTime.Ticks < Calendar.TicksPerDay) - { - // For time only format and a time only input, the time offset on 0001/01/01 is less - // accurate than the system's current offset because of daylight saving time. - offset = TimeZoneInfo.GetLocalUtcOffset(DateTime.Now, TimeZoneInfoOptions.NoThrowOnInvalidTime); - } - else if (dateTime.Kind == DateTimeKind.Utc) - { - offset = TimeSpan.Zero; - } - else - { - offset = TimeZoneInfo.GetLocalUtcOffset(dateTime, TimeZoneInfoOptions.NoThrowOnInvalidTime); - } - } - if (offset >= TimeSpan.Zero) - { - result.Append('+'); - } - else - { - result.Append('-'); - // get a positive offset, so that you don't need a separate code path for the negative numbers. - offset = offset.Negate(); - } - - if (tokenLen <= 1) - { - // 'z' format e.g "-7" - result.AppendFormat(CultureInfo.InvariantCulture, "{0:0}", offset.Hours); - } - else - { - // 'zz' or longer format e.g "-07" - result.AppendFormat(CultureInfo.InvariantCulture, "{0:00}", offset.Hours); - if (tokenLen >= 3) - { - // 'zzz*' or longer format e.g "-07:30" - result.AppendFormat(CultureInfo.InvariantCulture, ":{0:00}", offset.Minutes); - } - } - } - - // output the 'K' format, which is for round-tripping the data - private static void FormatCustomizedRoundripTimeZone(DateTime dateTime, TimeSpan offset, StringBuilder result) - { - // The objective of this format is to round trip the data in the type - // For DateTime it should round-trip the Kind value and preserve the time zone. - // DateTimeOffset instance, it should do so by using the internal time zone. - - if (offset == NullOffset) - { - // source is a date time, so behavior depends on the kind. - switch (dateTime.Kind) - { - case DateTimeKind.Local: - // This should output the local offset, e.g. "-07:30" - offset = TimeZoneInfo.GetLocalUtcOffset(dateTime, TimeZoneInfoOptions.NoThrowOnInvalidTime); - // fall through to shared time zone output code - break; - case DateTimeKind.Utc: - // The 'Z' constant is a marker for a UTC date - result.Append("Z"); - return; - default: - // If the kind is unspecified, we output nothing here - return; - } - } - if (offset >= TimeSpan.Zero) - { - result.Append('+'); - } - else - { - result.Append('-'); - // get a positive offset, so that you don't need a separate code path for the negative numbers. - offset = offset.Negate(); - } - - Append2DigitNumber(result, offset.Hours); - result.Append(':'); - Append2DigitNumber(result, offset.Minutes); - } - - private static void Append2DigitNumber(StringBuilder result, int val) - { - result.Append((char)('0' + (val / 10))); - result.Append((char)('0' + (val % 10))); - } - - internal static string GetRealFormat(ReadOnlySpan<char> format, DateTimeFormatInfo dtfi) - { - string realFormat; - - switch (format[0]) - { - case 'd': // Short Date - realFormat = dtfi.ShortDatePattern; - break; - case 'D': // Long Date - realFormat = dtfi.LongDatePattern; - break; - case 'f': // Full (long date + short time) - realFormat = dtfi.LongDatePattern + " " + dtfi.ShortTimePattern; - break; - case 'F': // Full (long date + long time) - realFormat = dtfi.FullDateTimePattern; - break; - case 'g': // General (short date + short time) - realFormat = dtfi.GeneralShortTimePattern; - break; - case 'G': // General (short date + long time) - realFormat = dtfi.GeneralLongTimePattern; - break; - case 'm': - case 'M': // Month/Day Date - realFormat = dtfi.MonthDayPattern; - break; - case 'o': - case 'O': - realFormat = RoundtripFormat; - break; - case 'r': - case 'R': // RFC 1123 Standard - realFormat = dtfi.RFC1123Pattern; - break; - case 's': // Sortable without Time Zone Info - realFormat = dtfi.SortableDateTimePattern; - break; - case 't': // Short Time - realFormat = dtfi.ShortTimePattern; - break; - case 'T': // Long Time - realFormat = dtfi.LongTimePattern; - break; - case 'u': // Universal with Sortable format - realFormat = dtfi.UniversalSortableDateTimePattern; - break; - case 'U': // Universal with Full (long date + long time) format - realFormat = dtfi.FullDateTimePattern; - break; - case 'y': - case 'Y': // Year/Month Date - realFormat = dtfi.YearMonthPattern; - break; - default: - throw new FormatException(SR.Format_InvalidString); - } - return realFormat; - } - - // Expand a pre-defined format string (like "D" for long date) to the real format that - // we are going to use in the date time parsing. - // This method also convert the dateTime if necessary (e.g. when the format is in Universal time), - // and change dtfi if necessary (e.g. when the format should use invariant culture). - // - private static string ExpandPredefinedFormat(ReadOnlySpan<char> format, ref DateTime dateTime, ref DateTimeFormatInfo dtfi, ref TimeSpan offset) - { - switch (format[0]) - { - case 'o': - case 'O': // Round trip format - dtfi = DateTimeFormatInfo.InvariantInfo; - break; - case 'r': - case 'R': // RFC 1123 Standard - case 'u': // Universal time in sortable format. - if (offset != NullOffset) - { - // Convert to UTC invariants mean this will be in range - dateTime -= offset; - } - dtfi = DateTimeFormatInfo.InvariantInfo; - break; - case 's': // Sortable without Time Zone Info - dtfi = DateTimeFormatInfo.InvariantInfo; - break; - case 'U': // Universal time in culture dependent format. - if (offset != NullOffset) - { - // This format is not supported by DateTimeOffset - throw new FormatException(SR.Format_InvalidString); - } - // Universal time is always in Greogrian calendar. - // - // Change the Calendar to be Gregorian Calendar. - // - dtfi = (DateTimeFormatInfo)dtfi.Clone(); - if (dtfi.Calendar.GetType() != typeof(GregorianCalendar)) - { - dtfi.Calendar = GregorianCalendar.GetDefaultInstance(); - } - dateTime = dateTime.ToUniversalTime(); - break; - } - return GetRealFormat(format, dtfi); - } - - internal static string Format(DateTime dateTime, string? format, IFormatProvider? provider) - { - return Format(dateTime, format, provider, NullOffset); - } - - internal static string Format(DateTime dateTime, string? format, IFormatProvider? provider, TimeSpan offset) - { - if (format != null && format.Length == 1) - { - // Optimize for these standard formats that are not affected by culture. - switch (format[0]) - { - // Round trip format - case 'o': - case 'O': - const int MinFormatOLength = 27, MaxFormatOLength = 33; - Span<char> span = stackalloc char[MaxFormatOLength]; - TryFormatO(dateTime, offset, span, out int ochars); - Debug.Assert(ochars >= MinFormatOLength && ochars <= MaxFormatOLength); - return span.Slice(0, ochars).ToString(); - - // RFC1123 - case 'r': - case 'R': - const int FormatRLength = 29; - string str = string.FastAllocateString(FormatRLength); - TryFormatR(dateTime, offset, new Span<char>(ref str.GetRawStringData(), str.Length), out int rchars); - Debug.Assert(rchars == str.Length); - return str; - } - } - - DateTimeFormatInfo dtfi = DateTimeFormatInfo.GetInstance(provider); - return StringBuilderCache.GetStringAndRelease(FormatStringBuilder(dateTime, format, dtfi, offset)); - } - - internal static bool TryFormat(DateTime dateTime, Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider? provider) => - TryFormat(dateTime, destination, out charsWritten, format, provider, NullOffset); - - internal static bool TryFormat(DateTime dateTime, Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider? provider, TimeSpan offset) - { - if (format.Length == 1) - { - // Optimize for these standard formats that are not affected by culture. - switch (format[0]) - { - // Round trip format - case 'o': - case 'O': - return TryFormatO(dateTime, offset, destination, out charsWritten); - - // RFC1123 - case 'r': - case 'R': - return TryFormatR(dateTime, offset, destination, out charsWritten); - } - } - - DateTimeFormatInfo dtfi = DateTimeFormatInfo.GetInstance(provider); - StringBuilder sb = FormatStringBuilder(dateTime, format, dtfi, offset); - - bool success = sb.Length <= destination.Length; - if (success) - { - sb.CopyTo(0, destination, sb.Length); - charsWritten = sb.Length; - } - else - { - charsWritten = 0; - } - - StringBuilderCache.Release(sb); - return success; - } - - private static StringBuilder FormatStringBuilder(DateTime dateTime, ReadOnlySpan<char> format, DateTimeFormatInfo dtfi, TimeSpan offset) - { - Debug.Assert(dtfi != null); - if (format.Length == 0) - { - bool timeOnlySpecialCase = false; - if (dateTime.Ticks < Calendar.TicksPerDay) - { - // If the time is less than 1 day, consider it as time of day. - // Just print out the short time format. - // - // This is a workaround for VB, since they use ticks less then one day to be - // time of day. In cultures which use calendar other than Gregorian calendar, these - // alternative calendar may not support ticks less than a day. - // For example, Japanese calendar only supports date after 1868/9/8. - // This will pose a problem when people in VB get the time of day, and use it - // to call ToString(), which will use the general format (short date + long time). - // Since Japanese calendar does not support Gregorian year 0001, an exception will be - // thrown when we try to get the Japanese year for Gregorian year 0001. - // Therefore, the workaround allows them to call ToString() for time of day from a DateTime by - // formatting as ISO 8601 format. - switch (dtfi.Calendar.ID) - { - case CalendarId.JAPAN: - case CalendarId.TAIWAN: - case CalendarId.HIJRI: - case CalendarId.HEBREW: - case CalendarId.JULIAN: - case CalendarId.UMALQURA: - case CalendarId.PERSIAN: - timeOnlySpecialCase = true; - dtfi = DateTimeFormatInfo.InvariantInfo; - break; - } - } - if (offset == NullOffset) - { - // Default DateTime.ToString case. - format = timeOnlySpecialCase ? "s" : "G"; - } - else - { - // Default DateTimeOffset.ToString case. - format = timeOnlySpecialCase ? RoundtripDateTimeUnfixed : dtfi.DateTimeOffsetPattern; - } - } - - if (format.Length == 1) - { - format = ExpandPredefinedFormat(format, ref dateTime, ref dtfi, ref offset); - } - - return FormatCustomized(dateTime, format, dtfi, offset, result: null); - } - - // Roundtrippable format. One of - // 012345678901234567890123456789012 - // --------------------------------- - // 2017-06-12T05:30:45.7680000-07:00 - // 2017-06-12T05:30:45.7680000Z (Z is short for "+00:00" but also distinguishes DateTimeKind.Utc from DateTimeKind.Local) - // 2017-06-12T05:30:45.7680000 (interpreted as local time wrt to current time zone) - private static bool TryFormatO(DateTime dateTime, TimeSpan offset, Span<char> destination, out int charsWritten) - { - const int MinimumBytesNeeded = 27; - - int charsRequired = MinimumBytesNeeded; - DateTimeKind kind = DateTimeKind.Local; - - if (offset == NullOffset) - { - kind = dateTime.Kind; - if (kind == DateTimeKind.Local) - { - offset = TimeZoneInfo.Local.GetUtcOffset(dateTime); - charsRequired += 6; - } - else if (kind == DateTimeKind.Utc) - { - charsRequired++; - } - } - else - { - charsRequired += 6; - } - - if (destination.Length < charsRequired) - { - charsWritten = 0; - return false; - } - charsWritten = charsRequired; - - // Hoist most of the bounds checks on destination. - { _ = destination[MinimumBytesNeeded - 1]; } - - WriteFourDecimalDigits((uint)dateTime.Year, destination, 0); - destination[4] = '-'; - WriteTwoDecimalDigits((uint)dateTime.Month, destination, 5); - destination[7] = '-'; - WriteTwoDecimalDigits((uint)dateTime.Day, destination, 8); - destination[10] = 'T'; - WriteTwoDecimalDigits((uint)dateTime.Hour, destination, 11); - destination[13] = ':'; - WriteTwoDecimalDigits((uint)dateTime.Minute, destination, 14); - destination[16] = ':'; - WriteTwoDecimalDigits((uint)dateTime.Second, destination, 17); - destination[19] = '.'; - WriteDigits((uint)((ulong)dateTime.Ticks % (ulong)TimeSpan.TicksPerSecond), destination.Slice(20, 7)); - - if (kind == DateTimeKind.Local) - { - char sign; - if (offset < default(TimeSpan) /* a "const" version of TimeSpan.Zero */) - { - sign = '-'; - offset = TimeSpan.FromTicks(-offset.Ticks); - } - else - { - sign = '+'; - } - - // Writing the value backward allows the JIT to optimize by - // performing a single bounds check against buffer. - WriteTwoDecimalDigits((uint)offset.Minutes, destination, 31); - destination[30] = ':'; - WriteTwoDecimalDigits((uint)offset.Hours, destination, 28); - destination[27] = sign; - } - else if (kind == DateTimeKind.Utc) - { - destination[27] = 'Z'; - } - - return true; - } - - // Rfc1123 - // 01234567890123456789012345678 - // ----------------------------- - // Tue, 03 Jan 2017 08:08:05 GMT - private static bool TryFormatR(DateTime dateTime, TimeSpan offset, Span<char> destination, out int charsWritten) - { - // Writing the check in this fashion elides all bounds checks on 'destination' - // for the remainder of the method. - if (28 >= (uint)destination.Length) - { - charsWritten = 0; - return false; - } - - if (offset != NullOffset) - { - // Convert to UTC invariants. - dateTime -= offset; - } - - dateTime.GetDatePart(out int year, out int month, out int day); - - string dayAbbrev = InvariantAbbreviatedDayNames[(int)dateTime.DayOfWeek]; - Debug.Assert(dayAbbrev.Length == 3); - - string monthAbbrev = InvariantAbbreviatedMonthNames[month - 1]; - Debug.Assert(monthAbbrev.Length == 3); - - destination[0] = dayAbbrev[0]; - destination[1] = dayAbbrev[1]; - destination[2] = dayAbbrev[2]; - destination[3] = ','; - destination[4] = ' '; - WriteTwoDecimalDigits((uint)day, destination, 5); - destination[7] = ' '; - destination[8] = monthAbbrev[0]; - destination[9] = monthAbbrev[1]; - destination[10] = monthAbbrev[2]; - destination[11] = ' '; - WriteFourDecimalDigits((uint)year, destination, 12); - destination[16] = ' '; - WriteTwoDecimalDigits((uint)dateTime.Hour, destination, 17); - destination[19] = ':'; - WriteTwoDecimalDigits((uint)dateTime.Minute, destination, 20); - destination[22] = ':'; - WriteTwoDecimalDigits((uint)dateTime.Second, destination, 23); - destination[25] = ' '; - destination[26] = 'G'; - destination[27] = 'M'; - destination[28] = 'T'; - - charsWritten = 29; - return true; - } - - /// <summary> - /// Writes a value [ 00 .. 99 ] to the buffer starting at the specified offset. - /// This method performs best when the starting index is a constant literal. - /// </summary> - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void WriteTwoDecimalDigits(uint value, Span<char> destination, int offset) - { - Debug.Assert(value <= 99); - - uint temp = '0' + value; - value /= 10; - destination[offset + 1] = (char)(temp - (value * 10)); - destination[offset] = (char)('0' + value); - } - - /// <summary> - /// Writes a value [ 0000 .. 9999 ] to the buffer starting at the specified offset. - /// This method performs best when the starting index is a constant literal. - /// </summary> - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void WriteFourDecimalDigits(uint value, Span<char> buffer, int startingIndex = 0) - { - Debug.Assert(value <= 9999); - - uint temp = '0' + value; - value /= 10; - buffer[startingIndex + 3] = (char)(temp - (value * 10)); - - temp = '0' + value; - value /= 10; - buffer[startingIndex + 2] = (char)(temp - (value * 10)); - - temp = '0' + value; - value /= 10; - buffer[startingIndex + 1] = (char)(temp - (value * 10)); - - buffer[startingIndex] = (char)('0' + value); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void WriteDigits(ulong value, Span<char> buffer) - { - // We can mutate the 'value' parameter since it's a copy-by-value local. - // It'll be used to represent the value left over after each division by 10. - - for (int i = buffer.Length - 1; i >= 1; i--) - { - ulong temp = '0' + value; - value /= 10; - buffer[i] = (char)(temp - (value * 10)); - } - - Debug.Assert(value < 10); - buffer[0] = (char)('0' + value); - } - - internal static string[] GetAllDateTimes(DateTime dateTime, char format, DateTimeFormatInfo dtfi) - { - Debug.Assert(dtfi != null); - string[] allFormats; - string[] results; - - switch (format) - { - case 'd': - case 'D': - case 'f': - case 'F': - case 'g': - case 'G': - case 'm': - case 'M': - case 't': - case 'T': - case 'y': - case 'Y': - allFormats = dtfi.GetAllDateTimePatterns(format); - results = new string[allFormats.Length]; - for (int i = 0; i < allFormats.Length; i++) - { - results[i] = Format(dateTime, allFormats[i], dtfi); - } - break; - case 'U': - DateTime universalTime = dateTime.ToUniversalTime(); - allFormats = dtfi.GetAllDateTimePatterns(format); - results = new string[allFormats.Length]; - for (int i = 0; i < allFormats.Length; i++) - { - results[i] = Format(universalTime, allFormats[i], dtfi); - } - break; - // - // The following ones are special cases because these patterns are read-only in - // DateTimeFormatInfo. - // - case 'r': - case 'R': - case 'o': - case 'O': - case 's': - case 'u': - results = new string[] { Format(dateTime, char.ToString(format), dtfi) }; - break; - default: - throw new FormatException(SR.Format_InvalidString); - } - return results; - } - - internal static string[] GetAllDateTimes(DateTime dateTime, DateTimeFormatInfo dtfi) - { - List<string> results = new List<string>(DEFAULT_ALL_DATETIMES_SIZE); - - for (int i = 0; i < allStandardFormats.Length; i++) - { - string[] strings = GetAllDateTimes(dateTime, allStandardFormats[i], dtfi); - for (int j = 0; j < strings.Length; j++) - { - results.Add(strings[j]); - } - } - - return results.ToArray(); - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/DateTimeFormatInfo.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/DateTimeFormatInfo.cs deleted file mode 100644 index 2989153d62f..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/DateTimeFormatInfo.cs +++ /dev/null @@ -1,2604 +0,0 @@ -// 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; -using System.Runtime.CompilerServices; - -namespace System.Globalization -{ - /// <summary> - /// 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). - /// </summary> - - [Flags] - internal enum MonthNameStyles - { - Regular = 0x00000000, - Genitive = 0x00000001, - LeapYear = 0x00000002, - } - - /// <summary> - /// 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 accommodate parsing behaviors like CJK month names - /// or alternative month names, etc. - /// </summary> - [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, - } - - public sealed 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. - private readonly CultureData _cultureData; - - // The culture name used to create this DTFI. - private string? _name = null; - - // The language name of the culture used to create this DTFI. - private string? _langName = null; - - // CompareInfo usually used by the parser. - private CompareInfo? _compareInfo = null; - - // Culture matches current DTFI. mainly used for string comparisons during parsing. - private CultureInfo? _cultureInfo = null; - - 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; - private string? dateTimeOffsetPattern = null; - - 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'"; - - private Calendar calendar = null!; // initialized in helper called by ctors - - 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; - - 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 => _name ??= _cultureData.CultureName; - - private CultureInfo Culture => _cultureInfo ??= CultureInfo.GetCultureInfo(CultureName); - - private string LanguageName => _langName ??= _cultureData.TwoLetterISOLanguageName; - - /// <summary> - /// Create an array of string which contains the abbreviated day names. - /// </summary> - private string[] InternalGetAbbreviatedDayOfWeekNames() => abbreviatedDayNames ?? InternalGetAbbreviatedDayOfWeekNamesCore(); - - [MethodImpl(MethodImplOptions.NoInlining)] - private string[] InternalGetAbbreviatedDayOfWeekNamesCore() - { - // Get the abbreviated day names for our current calendar - abbreviatedDayNames = _cultureData.AbbreviatedDayNames(Calendar.ID); - Debug.Assert(abbreviatedDayNames.Length == 7, "[DateTimeFormatInfo.GetAbbreviatedDayOfWeekNames] Expected 7 day names in a week"); - return abbreviatedDayNames; - } - - /// <summary> - /// Returns the string array of the one-letter day of week names. - /// </summary> - private string[] InternalGetSuperShortDayNames() => m_superShortDayNames ?? InternalGetSuperShortDayNamesCore(); - - [MethodImpl(MethodImplOptions.NoInlining)] - private string[] InternalGetSuperShortDayNamesCore() - { - // Get the super short day names for our current calendar - m_superShortDayNames = _cultureData.SuperShortDayNames(Calendar.ID); - Debug.Assert(m_superShortDayNames.Length == 7, "[DateTimeFormatInfo.InternalGetSuperShortDayNames] Expected 7 day names in a week"); - return m_superShortDayNames; - } - - /// <summary> - /// Create an array of string which contains the day names. - /// </summary> - private string[] InternalGetDayOfWeekNames() => dayNames ?? InternalGetDayOfWeekNamesCore(); - - [MethodImpl(MethodImplOptions.NoInlining)] - private string[] InternalGetDayOfWeekNamesCore() - { - // Get the day names for our current calendar - dayNames = _cultureData.DayNames(Calendar.ID); - Debug.Assert(dayNames.Length == 7, "[DateTimeFormatInfo.GetDayOfWeekNames] Expected 7 day names in a week"); - return dayNames; - } - - /// <summary> - /// Create an array of string which contains the abbreviated month names. - /// </summary> - private string[] InternalGetAbbreviatedMonthNames() => abbreviatedMonthNames ?? InternalGetAbbreviatedMonthNamesCore(); - - [MethodImpl(MethodImplOptions.NoInlining)] - private string[] InternalGetAbbreviatedMonthNamesCore() - { - // Get the month names for our current calendar - abbreviatedMonthNames = _cultureData.AbbreviatedMonthNames(Calendar.ID); - Debug.Assert(abbreviatedMonthNames.Length == 12 || abbreviatedMonthNames.Length == 13, - "[DateTimeFormatInfo.GetAbbreviatedMonthNames] Expected 12 or 13 month names in a year"); - return abbreviatedMonthNames; - } - - /// <summary> - /// Create an array of string which contains the month names. - /// </summary> - private string[] InternalGetMonthNames() => monthNames ?? internalGetMonthNamesCore(); - - [MethodImpl(MethodImplOptions.NoInlining)] - private string[] internalGetMonthNamesCore() - { - // Get the month names for our current calendar - monthNames = _cultureData.MonthNames(Calendar.ID); - Debug.Assert(monthNames.Length == 12 || monthNames.Length == 13, - "[DateTimeFormatInfo.GetMonthNames] Expected 12 or 13 month names in a year"); - return monthNames; - } - - // Invariant DateTimeFormatInfo doesn't have user-overriden values - // Default calendar is gregorian - public DateTimeFormatInfo() - : this(CultureInfo.InvariantCulture._cultureData, GregorianCalendar.GetDefaultInstance()) - { - } - - internal DateTimeFormatInfo(CultureData cultureData, Calendar cal) - { - Debug.Assert(cultureData != null); - Debug.Assert(cal != null); - - // Remember our culture - _cultureData = cultureData; - - Calendar = cal; - } - - private void InitializeOverridableProperties(CultureData cultureData, CalendarId calendarId) - { - Debug.Assert(cultureData != null); - Debug.Assert(calendarId != CalendarId.UNINITIALIZED_VALUE, "[DateTimeFormatInfo.Populate] Expected initalized calendarId"); - - if (firstDayOfWeek == -1) - { - firstDayOfWeek = cultureData.FirstDayOfWeek; - } - if (calendarWeekRule == -1) - { - calendarWeekRule = cultureData.CalendarWeekRule; - } - - if (amDesignator == null) - { - amDesignator = cultureData.AMDesignator; - } - if (pmDesignator == null) - { - pmDesignator = cultureData.PMDesignator; - } - if (timeSeparator == null) - { - timeSeparator = cultureData.TimeSeparator; - } - if (dateSeparator == null) - { - dateSeparator = cultureData.DateSeparator(calendarId); - } - - allLongTimePatterns = _cultureData.LongTimes; - Debug.Assert(allLongTimePatterns.Length > 0, "[DateTimeFormatInfo.Populate] Expected some long time patterns"); - - allShortTimePatterns = _cultureData.ShortTimes; - Debug.Assert(allShortTimePatterns.Length > 0, "[DateTimeFormatInfo.Populate] Expected some short time patterns"); - - allLongDatePatterns = cultureData.LongDates(calendarId); - Debug.Assert(allLongDatePatterns.Length > 0, "[DateTimeFormatInfo.Populate] Expected some long date patterns"); - - allShortDatePatterns = cultureData.ShortDates(calendarId); - Debug.Assert(allShortDatePatterns.Length > 0, "[DateTimeFormatInfo.Populate] Expected some short date patterns"); - - allYearMonthPatterns = cultureData.YearMonths(calendarId); - Debug.Assert(allYearMonthPatterns.Length > 0, "[DateTimeFormatInfo.Populate] Expected some year month patterns"); - } - - /// <summary> - /// Returns a default DateTimeFormatInfo that will be universally - /// supported and constant irrespective of the current culture. - /// </summary> - public static DateTimeFormatInfo InvariantInfo - { - get - { - if (s_invariantInfo == null) - { - DateTimeFormatInfo info = new DateTimeFormatInfo(); - info.Calendar.SetReadOnlyState(true); - info._isReadOnly = true; - s_invariantInfo = info; - } - return s_invariantInfo; - } - } - - /// <summary> - /// Returns the current culture's DateTimeFormatInfo. - /// </summary> - public static DateTimeFormatInfo CurrentInfo - { - get - { - System.Globalization.CultureInfo culture = System.Globalization.CultureInfo.CurrentCulture; - if (!culture._isInherited) - { - DateTimeFormatInfo? info = culture._dateTimeInfo; - if (info != null) - { - return info; - } - } - return (DateTimeFormatInfo)culture.GetFormat(typeof(DateTimeFormatInfo))!; - } - } - - public static DateTimeFormatInfo GetInstance(IFormatProvider? provider) => - provider == null ? CurrentInfo : - provider is CultureInfo cultureProvider && !cultureProvider._isInherited ? cultureProvider.DateTimeFormat : - provider is DateTimeFormatInfo info ? info : - provider.GetFormat(typeof(DateTimeFormatInfo)) is DateTimeFormatInfo info2 ? info2 : - CurrentInfo; // Couldn't get anything, just use currentInfo as fallback - - 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)Calendar.Clone(); - n._isReadOnly = false; - return n; - } - - public string AMDesignator - { - get - { - if (amDesignator == null) - { - amDesignator = _cultureData.AMDesignator; - } - - Debug.Assert(amDesignator != null, "DateTimeFormatInfo.AMDesignator, amDesignator != null"); - return amDesignator; - } - set - { - if (IsReadOnly) - { - throw new InvalidOperationException(SR.InvalidOperation_ReadOnly); - } - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - - ClearTokenHashTable(); - amDesignator = value; - } - } - - public Calendar Calendar - { - get - { - Debug.Assert(calendar != null, "DateTimeFormatInfo.Calendar: calendar != null"); - return calendar; - } - set - { - if (IsReadOnly) - { - throw new InvalidOperationException(SR.InvalidOperation_ReadOnly); - } - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - - if (value == calendar) - { - return; - } - - for (int i = 0; i < OptionalCalendars.Length; i++) - { - if (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(nameof(value), value, SR.Argument_InvalidCalendar); - } - } - - private CalendarId[] OptionalCalendars => optionalCalendars ??= _cultureData.CalendarIds; - - /// <summary> - /// Get the era value by parsing the name of the era. - /// </summary> - public int GetEra(string eraName) - { - if (eraName == null) - { - throw new ArgumentNullException(nameof(eraName)); - } - - // 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 (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 (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 (CompareInfo.Invariant.Compare(eraName, m_abbrevEnglishEraNames![i], CompareOptions.IgnoreCase) == 0) - { - return i + 1; - } - } - return -1; - } - - internal string[] EraNames => m_eraNames ??= _cultureData.EraNames(Calendar.ID); - - /// <summary> - /// Get the name of the era for the specified era value. - /// Era names are 1 indexed - /// </summary> - 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(nameof(era), era, SR.ArgumentOutOfRange_InvalidEraValue); - } - - internal string[] AbbreviatedEraNames => m_abbrevEraNames ??= _cultureData.AbbrevEraNames(Calendar.ID); - - /// <remarks> - /// Era names are 1 indexed - /// </remarks> - 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(nameof(era), era, SR.ArgumentOutOfRange_InvalidEraValue); - } - - internal string[] AbbreviatedEnglishEraNames - { - get - { - if (m_abbrevEnglishEraNames == null) - { - Debug.Assert(Calendar.ID > 0, "[DateTimeFormatInfo.AbbreviatedEnglishEraNames] Expected Calendar.ID > 0"); - m_abbrevEnglishEraNames = _cultureData.AbbreviatedEnglishEraNames(Calendar.ID); - } - return m_abbrevEnglishEraNames; - } - } - - /// <remarks> - /// Note that cultureData derives this from the short date format (unless someone's set this previously) - /// Note that this property is quite undesirable. - /// </remarks> - public string DateSeparator - { - get - { - if (dateSeparator == null) - { - dateSeparator = _cultureData.DateSeparator(Calendar.ID); - } - Debug.Assert(dateSeparator != null, "DateTimeFormatInfo.DateSeparator, dateSeparator != null"); - return dateSeparator; - } - set - { - if (IsReadOnly) - { - throw new InvalidOperationException(SR.InvalidOperation_ReadOnly); - } - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - - ClearTokenHashTable(); - dateSeparator = value; - } - } - - public DayOfWeek FirstDayOfWeek - { - get - { - if (firstDayOfWeek == -1) - { - firstDayOfWeek = _cultureData.FirstDayOfWeek; - } - Debug.Assert(firstDayOfWeek != -1, "DateTimeFormatInfo.FirstDayOfWeek, firstDayOfWeek != -1"); - - return (DayOfWeek)firstDayOfWeek; - } - set - { - if (IsReadOnly) - { - throw new InvalidOperationException(SR.InvalidOperation_ReadOnly); - } - - if (value < DayOfWeek.Sunday || value > DayOfWeek.Saturday) - { - throw new ArgumentOutOfRangeException( - nameof(value), - value, - SR.Format(SR.ArgumentOutOfRange_Range, DayOfWeek.Sunday, DayOfWeek.Saturday)); - } - - firstDayOfWeek = (int)value; - } - } - - public CalendarWeekRule CalendarWeekRule - { - get - { - if (calendarWeekRule == -1) - { - calendarWeekRule = _cultureData.CalendarWeekRule; - } - - Debug.Assert(calendarWeekRule != -1, "DateTimeFormatInfo.CalendarWeekRule, calendarWeekRule != -1"); - return (CalendarWeekRule)calendarWeekRule; - } - set - { - if (IsReadOnly) - { - throw new InvalidOperationException(SR.InvalidOperation_ReadOnly); - } - if (value < CalendarWeekRule.FirstDay || value > CalendarWeekRule.FirstFourDayWeek) - { - throw new ArgumentOutOfRangeException( - nameof(value), - value, - SR.Format(SR.ArgumentOutOfRange_Range, CalendarWeekRule.FirstDay, CalendarWeekRule.FirstFourDayWeek)); - } - - calendarWeekRule = (int)value; - } - } - - public string FullDateTimePattern - { - get => fullDateTimePattern ??= LongDatePattern + " " + LongTimePattern; - set - { - if (IsReadOnly) - { - throw new InvalidOperationException(SR.InvalidOperation_ReadOnly); - } - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - - fullDateTimePattern = value; - } - } - - /// <summary> - /// 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] - /// </summary> - public string LongDatePattern - { - get => longDatePattern ??= UnclonedLongDatePatterns[0]; // initialize from the 1st array value if not set - set - { - if (IsReadOnly) - { - throw new InvalidOperationException(SR.InvalidOperation_ReadOnly); - } - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - - // Remember the new string - longDatePattern = value; - - // Clear the token hash table - ClearTokenHashTable(); - - // Clean up cached values that will be affected by this property. - fullDateTimePattern = null; - } - } - - /// <summary> - /// 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] - /// </summary> - public string LongTimePattern - { - get => longTimePattern ??= UnclonedLongTimePatterns[0]; // initialize from the 1st array value if not set - set - { - if (IsReadOnly) - { - throw new InvalidOperationException(SR.InvalidOperation_ReadOnly); - } - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - - // Remember the new string - longTimePattern = value; - - // Clear the token hash table - ClearTokenHashTable(); - - // Clean up cached values that will be affected by this property. - fullDateTimePattern = null; // Full date = long date + long Time - generalLongTimePattern = null; // General long date = short date + long Time - dateTimeOffsetPattern = null; - } - } - - /// <remarks> - /// Just to be confusing there's only 1 month day pattern, not a whole list - /// </remarks> - public string MonthDayPattern - { - get - { - if (monthDayPattern == null) - { - Debug.Assert(Calendar.ID > 0, "[DateTimeFormatInfo.MonthDayPattern] Expected calID > 0"); - monthDayPattern = _cultureData.MonthDay(Calendar.ID); - } - - Debug.Assert(monthDayPattern != null, "DateTimeFormatInfo.MonthDayPattern, monthDayPattern != null"); - return monthDayPattern; - } - set - { - if (IsReadOnly) - { - throw new InvalidOperationException(SR.InvalidOperation_ReadOnly); - } - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - - monthDayPattern = value; - } - } - - public string PMDesignator - { - get - { - if (pmDesignator == null) - { - pmDesignator = _cultureData.PMDesignator; - } - - Debug.Assert(pmDesignator != null, "DateTimeFormatInfo.PMDesignator, pmDesignator != null"); - return pmDesignator; - } - set - { - if (IsReadOnly) - { - throw new InvalidOperationException(SR.InvalidOperation_ReadOnly); - } - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - - ClearTokenHashTable(); - pmDesignator = value; - } - } - - public string RFC1123Pattern => rfc1123Pattern; - - /// <summary> - /// 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] - /// </summary> - public string ShortDatePattern - { - get - { - return shortDatePattern ??= UnclonedShortDatePatterns[0]; // initialize from the 1st array value if not set - } - set - { - if (IsReadOnly) - { - throw new InvalidOperationException(SR.InvalidOperation_ReadOnly); - } - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - - // Remember the new string - 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; - } - } - - /// <summary> - /// 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] - /// </summary> - public string ShortTimePattern - { - get => shortTimePattern ??= UnclonedShortTimePatterns[0]; // initialize from the 1st array value if not set - set - { - if (IsReadOnly) - { - throw new InvalidOperationException(SR.InvalidOperation_ReadOnly); - } - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - - // Remember the new string - 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 => sortableDateTimePattern; - - /// <summary> - /// Return the pattern for 'g' general format: shortDate + short time - /// 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. - /// </summary> - internal string GeneralShortTimePattern => generalShortTimePattern ??= ShortDatePattern + " " + ShortTimePattern; - - /// <summary> - /// Return the pattern for 'g' general format: shortDate + Long time. - /// We put this internal property here so that we can avoid doing the - /// concatation every time somebody asks for the general format. - /// </summary> - internal string GeneralLongTimePattern => generalLongTimePattern ??= ShortDatePattern + " " + LongTimePattern; - - /// Return the default pattern DateTimeOffset : shortDate + long time + time zone offset. - /// 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) - { - /* 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; - } - } - - dateTimeOffsetPattern = foundZ ? - ShortDatePattern + " " + LongTimePattern : - ShortDatePattern + " " + LongTimePattern + " zzz"; - } - return dateTimeOffsetPattern; - } - } - - /// <remarks> - /// Note that cultureData derives this from the long time format (unless someone's set this previously) - /// Note that this property is quite undesirable. - /// </remarks> - public string TimeSeparator - { - get - { - if (timeSeparator == null) - { - timeSeparator = _cultureData.TimeSeparator; - } - Debug.Assert(timeSeparator != null, "DateTimeFormatInfo.TimeSeparator, timeSeparator != null"); - return timeSeparator; - } - set - { - if (IsReadOnly) - { - throw new InvalidOperationException(SR.InvalidOperation_ReadOnly); - } - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - - ClearTokenHashTable(); - timeSeparator = value; - } - } - - public string UniversalSortableDateTimePattern => universalSortableDateTimePattern; - - /// <summary> - /// 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] - /// </summary> - public string YearMonthPattern - { - get => yearMonthPattern ??= UnclonedYearMonthPatterns[0]; // initialize from the 1st array value if not set - set - { - if (IsReadOnly) - { - throw new InvalidOperationException(SR.InvalidOperation_ReadOnly); - } - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - - // Remember the new string - yearMonthPattern = value; - - // Clear the token hash table, note that even short times could require this - ClearTokenHashTable(); - } - } - - /// <summary> - /// Check if a string array contains a null value, and throw ArgumentNullException with parameter name "value" - /// </summary> - private static void CheckNullValue(string[] values, int length) - { - Debug.Assert(values != null, "value != null"); - Debug.Assert(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 => (string[])InternalGetAbbreviatedDayOfWeekNames().Clone(); - set - { - if (IsReadOnly) - { - throw new InvalidOperationException(SR.InvalidOperation_ReadOnly); - } - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - if (value.Length != 7) - { - throw new ArgumentException(SR.Format(SR.Argument_InvalidArrayLength, 7), nameof(value)); - } - - CheckNullValue(value, value.Length); - ClearTokenHashTable(); - - abbreviatedDayNames = value; - } - } - - /// <summary> - /// Returns the string array of the one-letter day of week names. - /// </summary> - public string[] ShortestDayNames - { - get => (string[])InternalGetSuperShortDayNames().Clone(); - set - { - if (IsReadOnly) - { - throw new InvalidOperationException(SR.InvalidOperation_ReadOnly); - } - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - if (value.Length != 7) - { - throw new ArgumentException(SR.Format(SR.Argument_InvalidArrayLength, 7), nameof(value)); - } - - CheckNullValue(value, value.Length); - m_superShortDayNames = value; - } - } - - public string[] DayNames - { - get => (string[])InternalGetDayOfWeekNames().Clone(); - set - { - if (IsReadOnly) - { - throw new InvalidOperationException(SR.InvalidOperation_ReadOnly); - } - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - if (value.Length != 7) - { - throw new ArgumentException(SR.Format(SR.Argument_InvalidArrayLength, 7), nameof(value)); - } - - CheckNullValue(value, value.Length); - ClearTokenHashTable(); - - dayNames = value; - } - } - - public string[] AbbreviatedMonthNames - { - get => (string[])InternalGetAbbreviatedMonthNames().Clone(); - set - { - if (IsReadOnly) - { - throw new InvalidOperationException(SR.InvalidOperation_ReadOnly); - } - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - if (value.Length != 13) - { - throw new ArgumentException(SR.Format(SR.Argument_InvalidArrayLength, 13), nameof(value)); - } - - CheckNullValue(value, value.Length - 1); - ClearTokenHashTable(); - abbreviatedMonthNames = value; - } - } - - public string[] MonthNames - { - get => (string[])InternalGetMonthNames().Clone(); - set - { - if (IsReadOnly) - { - throw new InvalidOperationException(SR.InvalidOperation_ReadOnly); - } - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - if (value.Length != 13) - { - throw new ArgumentException(SR.Format(SR.Argument_InvalidArrayLength, 13), nameof(value)); - } - - CheckNullValue(value, value.Length - 1); - monthNames = value; - ClearTokenHashTable(); - } - } - - internal bool HasSpacesInMonthNames => (FormatFlags & DateTimeFormatFlags.UseSpacesInMonthNames) != 0; - - internal bool HasSpacesInDayNames => (FormatFlags & DateTimeFormatFlags.UseSpacesInDayNames) != 0; - - /// <summary> - /// Return the month name using the specified MonthNameStyles in either abbreviated form - /// or full form. - /// </summary> - internal string InternalGetMonthName(int month, MonthNameStyles style, bool abbreviated) - { - string[] monthNamesArray = style switch - { - MonthNameStyles.Genitive => InternalGetGenitiveMonthNames(abbreviated), - MonthNameStyles.LeapYear => InternalGetLeapYearMonthNames(), - _ => (abbreviated ? InternalGetAbbreviatedMonthNames() : InternalGetMonthNames()), - }; - - // The month range is from 1 ~ m_monthNames.Length - // (actually is 13 right now for all cases) - if ((month < 1) || (month > monthNamesArray.Length)) - { - throw new ArgumentOutOfRangeException( - nameof(month), - month, - SR.Format(SR.ArgumentOutOfRange_Range, 1, monthNamesArray.Length)); - } - - return monthNamesArray[month - 1]; - } - - /// <summary> - /// Retrieve the array which contains the month names in genitive form. - /// If this culture does not use the genitive form, the normal month name is returned. - /// </summary> - private string[] InternalGetGenitiveMonthNames(bool abbreviated) - { - if (abbreviated) - { - if (m_genitiveAbbreviatedMonthNames == null) - { - m_genitiveAbbreviatedMonthNames = _cultureData.AbbreviatedGenitiveMonthNames(Calendar.ID); - Debug.Assert(m_genitiveAbbreviatedMonthNames.Length == 13, - "[DateTimeFormatInfo.GetGenitiveMonthNames] Expected 13 abbreviated genitive month names in a year"); - } - - return m_genitiveAbbreviatedMonthNames; - } - - if (genitiveMonthNames == null) - { - genitiveMonthNames = _cultureData.GenitiveMonthNames(Calendar.ID); - Debug.Assert(genitiveMonthNames.Length == 13, - "[DateTimeFormatInfo.GetGenitiveMonthNames] Expected 13 genitive month names in a year"); - } - - return genitiveMonthNames; - } - - /// <summary> - /// 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. - /// </summary> - internal string[] InternalGetLeapYearMonthNames() - { - if (leapYearMonthNames == null) - { - Debug.Assert(Calendar.ID > 0, "[DateTimeFormatInfo.InternalGetLeapYearMonthNames] Expected Calendar.ID > 0"); - leapYearMonthNames = _cultureData.LeapYearMonthNames(Calendar.ID); - Debug.Assert(leapYearMonthNames.Length == 13, - "[DateTimeFormatInfo.InternalGetLeapYearMonthNames] Expepcted 13 leap year month names"); - } - - return leapYearMonthNames; - } - - public string GetAbbreviatedDayName(DayOfWeek dayofweek) - { - if (dayofweek < DayOfWeek.Sunday || dayofweek > DayOfWeek.Saturday) - { - throw new ArgumentOutOfRangeException( - nameof(dayofweek), - dayofweek, - SR.Format(SR.ArgumentOutOfRange_Range, DayOfWeek.Sunday, DayOfWeek.Saturday)); - } - - // 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]; - } - - /// <summary> - /// Returns the super short day of week names for the specified day of week. - /// </summary> - public string GetShortestDayName(DayOfWeek dayOfWeek) - { - if (dayOfWeek < DayOfWeek.Sunday || dayOfWeek > DayOfWeek.Saturday) - { - throw new ArgumentOutOfRangeException( - nameof(dayOfWeek), - dayOfWeek, - SR.Format(SR.ArgumentOutOfRange_Range, DayOfWeek.Sunday, DayOfWeek.Saturday)); - } - - // Don't call the public property SuperShortDayNames here since a clone is needed in that - // property, so it will be slower. Instead, use internalGetSuperShortDayNames() directly. - return InternalGetSuperShortDayNames()[(int)dayOfWeek]; - } - - /// <summary> - /// Get all possible combination of inputs - /// </summary> - private static string[] GetCombinedPatterns(string[] patterns1, string[] patterns2, string connectString) - { - Debug.Assert(patterns1 != null); - Debug.Assert(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; - } - - public string[] GetAllDateTimePatterns() - { - List<string> results = new List<string>(DEFAULT_ALL_DATETIMES_SIZE); - - for (int i = 0; i < DateTimeFormat.allStandardFormats.Length; i++) - { - string[] strings = GetAllDateTimePatterns(DateTimeFormat.allStandardFormats[i]); - for (int j = 0; j < strings.Length; j++) - { - results.Add(strings[j]); - } - } - return results.ToArray(); - } - - public string[] GetAllDateTimePatterns(char format) - { - string[] result; - - switch (format) - { - case 'd': - result = AllShortDatePatterns; - break; - case 'D': - result = 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 = AllShortTimePatterns; - break; - case 'T': - result = AllLongTimePatterns; - break; - case 'u': - result = new string[] { UniversalSortableDateTimePattern }; - break; - case 'y': - case 'Y': - result = AllYearMonthPatterns; - break; - default: - throw new ArgumentException(SR.Format(SR.Format_BadFormatSpecifier, format), nameof(format)); - } - return result; - } - - public string GetDayName(DayOfWeek dayofweek) - { - if ((int)dayofweek < 0 || (int)dayofweek > 6) - { - throw new ArgumentOutOfRangeException( - nameof(dayofweek), - dayofweek, - SR.Format(SR.ArgumentOutOfRange_Range, DayOfWeek.Sunday, DayOfWeek.Saturday)); - } - - // 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( - nameof(month), - month, - SR.Format(SR.ArgumentOutOfRange_Range, 1, 13)); - } - - // 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( - nameof(month), - month, - SR.Format(SR.ArgumentOutOfRange_Range, 1, 13)); - } - - // Use the internal one so we don't clone the array unnecessarily - return InternalGetMonthNames()[month - 1]; - } - - /// <summary> - /// 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. - /// </summary> - private static string[] GetMergedPatterns(string[] patterns, string defaultPattern) - { - Debug.Assert(patterns != null && patterns.Length > 0, - "[DateTimeFormatInfo.GetMergedPatterns]Expected array of at least one pattern"); - Debug.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"; - - /// <summary> - /// Default string isn't necessarily in our string array, so get the - /// merged patterns of both - /// </summary> - private string[] AllYearMonthPatterns => GetMergedPatterns(UnclonedYearMonthPatterns, YearMonthPattern); - - private string[] AllShortDatePatterns => GetMergedPatterns(UnclonedShortDatePatterns, ShortDatePattern); - - private string[] AllShortTimePatterns => GetMergedPatterns(UnclonedShortTimePatterns, ShortTimePattern); - - private string[] AllLongDatePatterns => GetMergedPatterns(UnclonedLongDatePatterns, LongDatePattern); - - private string[] AllLongTimePatterns => GetMergedPatterns(UnclonedLongTimePatterns, LongTimePattern); - - /// <remarks> - /// 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 - /// </remarks> - private string[] UnclonedYearMonthPatterns - { - get - { - if (allYearMonthPatterns == null) - { - Debug.Assert(Calendar.ID > 0, "[DateTimeFormatInfo.UnclonedYearMonthPatterns] Expected Calendar.ID > 0"); - allYearMonthPatterns = _cultureData.YearMonths(Calendar.ID); - Debug.Assert(allYearMonthPatterns.Length > 0, - "[DateTimeFormatInfo.UnclonedYearMonthPatterns] Expected some year month patterns"); - } - - return allYearMonthPatterns; - } - } - - /// <remarks> - /// 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 - /// </remarks> - private string[] UnclonedShortDatePatterns - { - get - { - if (allShortDatePatterns == null) - { - Debug.Assert(Calendar.ID > 0, "[DateTimeFormatInfo.UnclonedShortDatePatterns] Expected Calendar.ID > 0"); - allShortDatePatterns = _cultureData.ShortDates(Calendar.ID); - Debug.Assert(allShortDatePatterns.Length > 0, - "[DateTimeFormatInfo.UnclonedShortDatePatterns] Expected some short date patterns"); - } - - return allShortDatePatterns; - } - } - - /// <remarks> - /// 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 - /// </remarks> - private string[] UnclonedLongDatePatterns - { - get - { - if (allLongDatePatterns == null) - { - Debug.Assert(Calendar.ID > 0, "[DateTimeFormatInfo.UnclonedLongDatePatterns] Expected Calendar.ID > 0"); - allLongDatePatterns = _cultureData.LongDates(Calendar.ID); - Debug.Assert(allLongDatePatterns.Length > 0, - "[DateTimeFormatInfo.UnclonedLongDatePatterns] Expected some long date patterns"); - } - - return allLongDatePatterns; - } - } - - /// <remarks> - /// 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 - /// </remarks> - private string[] UnclonedShortTimePatterns - { - get - { - if (allShortTimePatterns == null) - { - allShortTimePatterns = _cultureData.ShortTimes; - Debug.Assert(allShortTimePatterns.Length > 0, - "[DateTimeFormatInfo.UnclonedShortTimePatterns] Expected some short time patterns"); - } - - return allShortTimePatterns; - } - } - - /// <remarks> - /// 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 - /// </remarks> - private string[] UnclonedLongTimePatterns - { - get - { - if (allLongTimePatterns == null) - { - allLongTimePatterns = _cultureData.LongTimes; - Debug.Assert(allLongTimePatterns.Length > 0, - "[DateTimeFormatInfo.UnclonedLongTimePatterns] Expected some long time patterns"); - } - - return allLongTimePatterns; - } - } - - public static DateTimeFormatInfo ReadOnly(DateTimeFormatInfo dtfi) - { - if (dtfi == null) - { - throw new ArgumentNullException(nameof(dtfi)); - } - - 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 => _isReadOnly; - - /// <summary> - /// Return the native name for the calendar in DTFI.Calendar. The native name is referred to - /// the culture used to create the DTFI. E.g. in the following example, the native language is Japanese. - /// DateTimeFormatInfo dtfi = new CultureInfo("ja-JP", false).DateTimeFormat.Calendar = new JapaneseCalendar(); - /// String nativeName = dtfi.NativeCalendarName; // Get the Japanese name for the Japanese calendar. - /// DateTimeFormatInfo dtfi = new CultureInfo("ja-JP", false).DateTimeFormat.Calendar = new GregorianCalendar(GregorianCalendarTypes.Localized); - /// String nativeName = dtfi.NativeCalendarName; // Get the Japanese name for the Gregorian calendar. - /// </summary> - public string NativeCalendarName => _cultureData.CalendarName(Calendar.ID); - - /// <summary> - /// Used by custom cultures and others to set the list of available formats. Note that none of them are - /// explicitly used unless someone calls GetAllDateTimePatterns and subsequently uses one of the items - /// from the list. - /// - /// Most of the format characters that can be used in GetAllDateTimePatterns are - /// not really needed since they are one of the following: - /// - /// r/R/s/u locale-independent constants -- cannot be changed! - /// m/M/y/Y fields with a single string in them -- that can be set through props directly - /// f/F/g/G/U derived fields based on combinations of various of the below formats - /// - /// NOTE: No special validation is done here beyond what is done when the actual respective fields - /// are used (what would be the point of disallowing here what we allow in the appropriate property?) - /// - /// WARNING: If more validation is ever done in one place, it should be done in the other. - /// </summary> - public void SetAllDateTimePatterns(string[] patterns, char format) - { - if (IsReadOnly) - { - throw new InvalidOperationException(SR.InvalidOperation_ReadOnly); - } - if (patterns == null) - { - throw new ArgumentNullException(nameof(patterns)); - } - - if (patterns.Length == 0) - { - throw new ArgumentException(SR.Arg_ArrayZeroError, nameof(patterns)); - } - - for (int i = 0; i < patterns.Length; i++) - { - if (patterns[i] == null) - { - throw new ArgumentNullException("patterns[" + i + "]", SR.ArgumentNull_ArrayValue); - } - } - - // Remember the patterns, and use the 1st as default - switch (format) - { - case 'd': - allShortDatePatterns = patterns; - shortDatePattern = allShortDatePatterns[0]; - break; - - case 'D': - allLongDatePatterns = patterns; - longDatePattern = allLongDatePatterns[0]; - break; - - case 't': - allShortTimePatterns = patterns; - shortTimePattern = allShortTimePatterns[0]; - break; - - case 'T': - allLongTimePatterns = patterns; - longTimePattern = allLongTimePatterns[0]; - break; - - case 'y': - case 'Y': - allYearMonthPatterns = patterns; - yearMonthPattern = allYearMonthPatterns[0]; - break; - - default: - throw new ArgumentException(SR.Format(SR.Format_BadFormatSpecifier, format), nameof(format)); - } - - // Clear the token hash table, note that even short dates could require this - ClearTokenHashTable(); - } - - public string[] AbbreviatedMonthGenitiveNames - { - get => (string[])InternalGetGenitiveMonthNames(true).Clone(); - set - { - if (IsReadOnly) - { - throw new InvalidOperationException(SR.InvalidOperation_ReadOnly); - } - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - if (value.Length != 13) - { - throw new ArgumentException(SR.Format(SR.Argument_InvalidArrayLength, 13), nameof(value)); - } - - CheckNullValue(value, value.Length - 1); - ClearTokenHashTable(); - m_genitiveAbbreviatedMonthNames = value; - } - } - - public string[] MonthGenitiveNames - { - get => (string[])InternalGetGenitiveMonthNames(false).Clone(); - set - { - if (IsReadOnly) - { - throw new InvalidOperationException(SR.InvalidOperation_ReadOnly); - } - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - if (value.Length != 13) - { - throw new ArgumentException(SR.Format(SR.Argument_InvalidArrayLength, 13), nameof(value)); - } - - CheckNullValue(value, value.Length - 1); - genitiveMonthNames = value; - ClearTokenHashTable(); - } - } - - // Decimal separator used by positive TimeSpan pattern - private string? _decimalSeparator; - internal string DecimalSeparator => - _decimalSeparator ??= - new NumberFormatInfo(_cultureData.UseUserOverride ? CultureData.GetCultureData(_cultureData.CultureName, false) : _cultureData).NumberDecimalSeparator; - - // Positive TimeSpan Pattern - private string? _fullTimeSpanPositivePattern; - internal string FullTimeSpanPositivePattern => - _fullTimeSpanPositivePattern ??= "d':'h':'mm':'ss'" + DecimalSeparator + "'FFFFFFF"; - - // Negative TimeSpan Pattern - private string? _fullTimeSpanNegativePattern; - internal string FullTimeSpanNegativePattern => - _fullTimeSpanNegativePattern ??= "'-'" + FullTimeSpanPositivePattern; - - // Get suitable CompareInfo from current DTFI object. - internal CompareInfo CompareInfo => - // 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.SortName); - - 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); - } - if (((style & DateTimeStyles.RoundtripKind) != 0) - && ((style & (DateTimeStyles.AssumeLocal | DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal)) != 0)) - { - throw new ArgumentException(SR.Argument_ConflictingDateTimeRoundtripStyles, parameterName); - } - } - - /// <summary> - /// 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. - /// </summary> - internal DateTimeFormatFlags FormatFlags => formatFlags != DateTimeFormatFlags.NotInitialized ? formatFlags : InitializeFormatFlags(); - - [MethodImpl(MethodImplOptions.NoInlining)] - private DateTimeFormatFlags InitializeFormatFlags() - { - // Build the format flags from the data in this DTFI - formatFlags = - (DateTimeFormatFlags)DateTimeFormatInfoScanner.GetFormatFlagGenitiveMonth( - MonthNames, InternalGetGenitiveMonthNames(false), AbbreviatedMonthNames, InternalGetGenitiveMonthNames(true)) | - (DateTimeFormatFlags)DateTimeFormatInfoScanner.GetFormatFlagUseSpaceInMonthNames( - MonthNames, InternalGetGenitiveMonthNames(false), AbbreviatedMonthNames, InternalGetGenitiveMonthNames(true)) | - (DateTimeFormatFlags)DateTimeFormatInfoScanner.GetFormatFlagUseSpaceInDayNames(DayNames, AbbreviatedDayNames) | - (DateTimeFormatFlags)DateTimeFormatInfoScanner.GetFormatFlagUseHebrewCalendar((int)Calendar.ID); - return formatFlags; - } - - internal bool 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; - } - } - - /// <summary> - /// Returns whether the YearMonthAdjustment function has any fix-up work to do for this culture/calendar. - /// </summary> - internal bool HasYearMonthAdjustment => (FormatFlags & DateTimeFormatFlags.UseHebrewRule) != 0; - - /// <summary> - /// 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. - /// </summary> - internal bool YearMonthAdjustment(ref int year, ref int month, bool 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 JapaneseEraStart = "\u5143"; - - 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; - - /// <summary> - /// 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. - /// </summary> - 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; - } - - /// <summary> - /// 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. - /// </summary> - 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; - } - - /// <summary> - /// DTFI properties should call this when the setter are called. - /// </summary> - 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 = 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, TimeSeparator, TokenType.SEP_Time, 0); - } - - InsertHash(temp, AMDesignator, TokenType.SEP_Am | TokenType.Am, 0); - InsertHash(temp, PMDesignator, TokenType.SEP_Pm | TokenType.Pm, 1); - - if (LanguageName.Equals("sq")) - { - // Albanian allows time formats like "12:00.PD" - InsertHash(temp, IgnorablePeriod + AMDesignator, TokenType.SEP_Am | TokenType.Am, 0); - InsertHash(temp, IgnorablePeriod + 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); - - if (!LocalAppContextSwitches.EnforceLegacyJapaneseDateParsing && Calendar.ID == CalendarId.JAPAN) - { - // We need to support parsing the dates has the start of era symbol which means it is year 1 in the era. - // The start of era symbol has to be followed by the year symbol suffix, otherwise it would be invalid date. - InsertHash(temp, JapaneseEraStart, TokenType.YearNumberToken, 1); - InsertHash(temp, "(", TokenType.IgnorableSymbol, 0); - InsertHash(temp, ")", TokenType.IgnorableSymbol, 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); - } - - // We need to rescan the date words since we're always synthetic - DateTimeFormatInfoScanner scanner = new DateTimeFormatInfoScanner(); - string[]? dateWords = scanner.GetDateWordsOfDTFI(this); - - // Ensure the formatflags is initialized. - _ = 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; - - 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. - ReadOnlySpan<char> monthPostfix = dateWords[i].AsSpan(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 (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, DateSeparator, TokenType.SEP_Date, 0); - } - // Add the regular month names. - AddMonthNames(temp); - - // Add the abbreviated month names. - for (int i = 1; i <= 13; i++) - { - InsertHash(temp, GetAbbreviatedMonthName(i), TokenType.MonthToken, i); - } - - if ((FormatFlags & DateTimeFormatFlags.UseGenitiveMonth) != 0) - { - string [] genitiveMonthNames = InternalGetGenitiveMonthNames(abbreviated: false); - string [] abbreviatedGenitiveMonthNames = InternalGetGenitiveMonthNames(abbreviated: true); - - for (int i = 1; i <= 13; i++) - { - InsertHash(temp, genitiveMonthNames[i - 1], TokenType.MonthToken, i); - InsertHash(temp, abbreviatedGenitiveMonthNames[i - 1], TokenType.MonthToken, i); - } - } - - if ((FormatFlags & DateTimeFormatFlags.UseLeapYearMonth) != 0) - { - for (int i = 1; i <= 13; i++) - { - string str = InternalGetMonthName(i, MonthNameStyles.LeapYear, false); - InsertHash(temp, str, TokenType.MonthToken, i); - } - } - - for (int i = 0; i < 7; i++) - { - // We have to call public methods here to work with inherited DTFI. - string str = GetDayName((DayOfWeek)i); - InsertHash(temp, str, TokenType.DayOfWeekToken, i); - - str = GetAbbreviatedDayName((DayOfWeek)i); - InsertHash(temp, str, TokenType.DayOfWeekToken, i); - } - - int[] eras = calendar.Eras; - for (int i = 1; i <= eras.Length; i++) - { - InsertHash(temp, GetEraName(i), TokenType.EraToken, i); - InsertHash(temp, GetAbbreviatedEraName(i), TokenType.EraToken, i); - } - - if (LanguageName.Equals(JapaneseLangName)) - { - // Japanese allows day of week forms like: "(Tue)" - for (int i = 0; i < 7; i++) - { - string specialDayOfWeek = "(" + GetAbbreviatedDayName((DayOfWeek)i) + ")"; - InsertHash(temp, specialDayOfWeek, TokenType.DayOfWeekToken, i); - } - if (Calendar.GetType() != typeof(JapaneseCalendar)) - { - // Special case for Japanese. If this is a Japanese DTFI, and the calendar is not Japanese calendar, - // we will check Japanese Era name as well when the calendar is Gregorian. - DateTimeFormatInfo jaDtfi = GetJapaneseCalendarDTFI(); - for (int i = 1; i <= jaDtfi.Calendar.Eras.Length; i++) - { - InsertHash(temp, jaDtfi.GetEraName(i), TokenType.JapaneseEraToken, i); - InsertHash(temp, jaDtfi.GetAbbreviatedEraName(i), TokenType.JapaneseEraToken, i); - // m_abbrevEnglishEraNames[0] contains the name for era 1, so the token value is i+1. - InsertHash(temp, jaDtfi.AbbreviatedEnglishEraNames[i - 1], TokenType.JapaneseEraToken, i); - } - } - } - // TODO: This prohibits similar custom cultures, but we hard coded the name - else if (CultureName.Equals("zh-TW")) - { - DateTimeFormatInfo twDtfi = GetTaiwanCalendarDTFI(); - for (int i = 1; i <= twDtfi.Calendar.Eras.Length; i++) - { - if (twDtfi.GetEraName(i).Length > 0) - { - InsertHash(temp, twDtfi.GetEraName(i), TokenType.TEraToken, i); - } - } - } - - InsertHash(temp, InvariantInfo.AMDesignator, TokenType.SEP_Am | TokenType.Am, 0); - InsertHash(temp, InvariantInfo.PMDesignator, TokenType.SEP_Pm | TokenType.Pm, 1); - - // Add invariant month names and day names. - for (int i = 1; i <= 12; i++) - { - // We have to call public methods here to work with inherited DTFI. - // Insert the month name first, so that they are at the front of abbreviated - // month names. - string str = InvariantInfo.GetMonthName(i); - InsertHash(temp, str, TokenType.MonthToken, i); - str = InvariantInfo.GetAbbreviatedMonthName(i); - InsertHash(temp, str, TokenType.MonthToken, i); - } - - for (int i = 0; i < 7; i++) - { - // We have to call public methods here to work with inherited DTFI. - string str = InvariantInfo.GetDayName((DayOfWeek)i); - InsertHash(temp, str, TokenType.DayOfWeekToken, i); - - str = InvariantInfo.GetAbbreviatedDayName((DayOfWeek)i); - InsertHash(temp, str, TokenType.DayOfWeekToken, i); - } - - for (int i = 0; i < AbbreviatedEnglishEraNames.Length; i++) - { - // m_abbrevEnglishEraNames[0] contains the name for era 1, so the token value is i+1. - InsertHash(temp, AbbreviatedEnglishEraNames[i], TokenType.EraToken, i + 1); - } - - InsertHash(temp, LocalTimeMark, TokenType.SEP_LocalTimeMark, 0); - InsertHash(temp, GMTName, TokenType.TimeZoneToken, 0); - InsertHash(temp, ZuluName, TokenType.TimeZoneToken, 0); - - InsertHash(temp, invariantDateSeparator, TokenType.SEP_Date, 0); - InsertHash(temp, invariantTimeSeparator, TokenType.SEP_Time, 0); - - _dtfiTokenHash = temp; - } - return temp; - } - - private void AddMonthNames(TokenHashValue[] temp, ReadOnlySpan<char> monthPostfix = default) - { - for (int i = 1; i <= 13; i++) - { - // We have to call public methods here to work with inherited DTFI. - // Insert the month name first, so that they are at the front of abbreviated - // month names. - string str = GetMonthName(i); - if (str.Length > 0) - { - if (!monthPostfix.IsEmpty) - { - // Insert the month name with the postfix first, so it can be matched first. - InsertHash(temp, string.Concat(str, monthPostfix), TokenType.MonthToken, i); - } - else - { - InsertHash(temp, str, TokenType.MonthToken, i); - } - } - str = GetAbbreviatedMonthName(i); - InsertHash(temp, str, TokenType.MonthToken, i); - } - } - - /// <summary> - /// Try to parse the current word to see if it is a Hebrew number. - /// Tokens will be updated accordingly. - /// This is called by the Lexer of DateTime.Parse(). - /// - /// Unlike most of the functions in this class, the return value indicates - /// whether or not it started to parse. The badFormat parameter indicates - /// if parsing began, but the format was bad. - /// </summary> - private static bool TryParseHebrewNumber( - ref __DTString str, - out bool badFormat, - out int number) - { - number = -1; - badFormat = false; - - int i = str.Index; - if (!HebrewNumber.IsDigit(str.Value[i])) - { - // If the current character is not a Hebrew digit, just return false. - // There is no chance that we can parse a valid Hebrew number from here. - return false; - } - // The current character is a Hebrew digit. Try to parse this word as a Hebrew number. - HebrewNumberParsingContext context = new HebrewNumberParsingContext(0); - HebrewNumberParsingState state; - - do - { - state = HebrewNumber.ParseByChar(str.Value[i++], ref context); - switch (state) - { - case HebrewNumberParsingState.InvalidHebrewNumber: // Not a valid Hebrew number. - case HebrewNumberParsingState.NotHebrewDigit: // The current character is not a Hebrew digit character. - // Break out so that we don't continue to try parse this as a Hebrew number. - return false; - } - } while (i < str.Value.Length && (state != HebrewNumberParsingState.FoundEndOfHebrewNumber)); - - // When we are here, we are either at the end of the string, or we find a valid Hebrew number. - Debug.Assert(state == HebrewNumberParsingState.ContinueParsing || state == HebrewNumberParsingState.FoundEndOfHebrewNumber, - "Invalid returned state from HebrewNumber.ParseByChar()"); - - if (state != HebrewNumberParsingState.FoundEndOfHebrewNumber) - { - // We reach end of the string but we can't find a terminal state in parsing Hebrew number. - return false; - } - - // We have found a valid Hebrew number. Update the index. - str.Advance(i - str.Index); - - // Get the final Hebrew number value from the HebrewNumberParsingContext. - number = context.result; - - return true; - } - - private static bool IsHebrewChar(char ch) - { - return ch >= '\x0590' && ch <= '\x05ff'; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private bool IsAllowedJapaneseTokenFollowedByNonSpaceLetter(string tokenString, char nextCh) - { - // Allow the parser to recognize the case when having some date part followed by JapaneseEraStart "\u5143" - // without spaces in between. e.g. Era name followed by \u5143 in the date formats ggy. - // Also, allow recognizing the year suffix symbol "\u5e74" followed the JapaneseEraStart "\u5143" - if (!LocalAppContextSwitches.EnforceLegacyJapaneseDateParsing && Calendar.ID == CalendarId.JAPAN && - ( - // something like ggy, era followed by year and the year is specified using the JapaneseEraStart "\u5143" - nextCh == JapaneseEraStart[0] || - // JapaneseEraStart followed by year suffix "\u5143" - (tokenString == JapaneseEraStart && nextCh == CJKYearSuff[0]) - )) - { - return true; - } - return false; - } - - internal bool Tokenize(TokenType TokenMask, out TokenType tokenType, out int tokenValue, - ref __DTString str) - { - tokenType = TokenType.UnknownToken; - tokenValue = 0; - - TokenHashValue value; - Debug.Assert(str.Index < str.Value.Length, "DateTimeFormatInfo.Tokenize(): start < value.Length"); - - char ch = str.m_current; - bool isLetter = char.IsLetter(ch); - if (isLetter) - { - ch = Culture.TextInfo.ToLower(ch); - if (IsHebrewChar(ch) && TokenMask == TokenType.RegularTokenMask) - { - bool badFormat; - if (TryParseHebrewNumber(ref str, out badFormat, out tokenValue)) - { - if (badFormat) - { - tokenType = TokenType.UnknownToken; - return false; - } - // This is a Hebrew number. - // Do nothing here. TryParseHebrewNumber() will update token accordingly. - tokenType = TokenType.HebrewNumber; - return true; - } - } - } - - int hashcode = ch % TOKEN_HASH_SIZE; - int hashProbe = 1 + ch % SECOND_PRIME; - int remaining = str.Length - str.Index; - int i = 0; - - TokenHashValue[] hashTable = _dtfiTokenHash ?? CreateTokenHashTable(); - do - { - value = hashTable[hashcode]; - if (value == null) - { - // Not found. - break; - } - // Check this value has the right category (regular token or separator token) that we are looking for. - if (((int)value.tokenType & (int)TokenMask) > 0 && value.tokenString.Length <= remaining) - { - bool compareStrings = true; - if (isLetter) - { - // If this token starts with a letter, make sure that we won't allow partial match. So you can't tokenize "MarchWed" separately. - // Also an optimization to avoid string comparison - int nextCharIndex = str.Index + value.tokenString.Length; - if (nextCharIndex > str.Length) - { - compareStrings = false; - } - else if (nextCharIndex < str.Length) - { - // Check word boundary. The next character should NOT be a letter. - char nextCh = str.Value[nextCharIndex]; - compareStrings = !char.IsLetter(nextCh) || IsAllowedJapaneseTokenFollowedByNonSpaceLetter(value.tokenString, nextCh); - } - } - - if (compareStrings && - ((value.tokenString.Length == 1 && str.Value[str.Index] == value.tokenString[0]) || - Culture.CompareInfo.Compare(str.Value.Slice(str.Index, value.tokenString.Length), value.tokenString, CompareOptions.IgnoreCase) == 0)) - { - tokenType = value.tokenType & TokenMask; - tokenValue = value.tokenValue; - str.Advance(value.tokenString.Length); - return true; - } - else if ((value.tokenType == TokenType.MonthToken && HasSpacesInMonthNames) || - (value.tokenType == TokenType.DayOfWeekToken && HasSpacesInDayNames)) - { - // For month or day token, we will match the names which have spaces. - int matchStrLen = 0; - if (str.MatchSpecifiedWords(value.tokenString, true, ref matchStrLen)) - { - tokenType = value.tokenType & TokenMask; - tokenValue = value.tokenValue; - str.Advance(matchStrLen); - return true; - } - } - } - i++; - hashcode += hashProbe; - if (hashcode >= TOKEN_HASH_SIZE) hashcode -= TOKEN_HASH_SIZE; - } while (i < TOKEN_HASH_SIZE); - - return false; - } - - private void InsertAtCurrentHashNode(TokenHashValue[] hashTable, string str, char ch, TokenType tokenType, int tokenValue, int pos, int hashcode, int hashProbe) - { - // Remember the current slot. - TokenHashValue previousNode = hashTable[hashcode]; - - // Insert the new node into the current slot. - hashTable[hashcode] = new TokenHashValue(str, tokenType, tokenValue); - - while (++pos < TOKEN_HASH_SIZE) - { - hashcode += hashProbe; - if (hashcode >= TOKEN_HASH_SIZE) hashcode -= TOKEN_HASH_SIZE; - // Remember this slot - TokenHashValue temp = hashTable[hashcode]; - - if (temp != null && Culture.TextInfo.ToLower(temp.tokenString[0]) != ch) - { - continue; - } - // Put the previous slot into this slot. - hashTable[hashcode] = previousNode; - if (temp == null) - { - // Done - return; - } - previousNode = temp; - } - Debug.Fail("The hashtable is full. This should not happen."); - } - - private void InsertHash(TokenHashValue[] hashTable, string str, TokenType tokenType, int tokenValue) - { - // The month of the 13th month is allowed to be null, so make sure that we ignore null value here. - if (string.IsNullOrEmpty(str)) - { - return; - } - - TokenHashValue value; - int i = 0; - // If there is whitespace characters in the beginning and end of the string, trim them since whitespaces are skipped by - // DateTime.Parse(). - if (char.IsWhiteSpace(str[0]) || char.IsWhiteSpace(str[^1])) - { - str = str.Trim(null); // Trim white space characters. - // Could have space for separators - if (str.Length == 0) - { - return; - } - } - - char ch = Culture.TextInfo.ToLower(str[0]); - int hashcode = ch % TOKEN_HASH_SIZE; - int hashProbe = 1 + ch % SECOND_PRIME; - do - { - value = hashTable[hashcode]; - if (value == null) - { - hashTable[hashcode] = new TokenHashValue(str, tokenType, tokenValue); - return; - } - else - { - // Collision happens. Find another slot. - if (str.Length >= value.tokenString.Length) - { - // If there are two tokens with the same prefix, we have to make sure that the longer token should be at the front of - // the shorter ones. - if (CompareStringIgnoreCaseOptimized(str, 0, value.tokenString.Length, value.tokenString, 0, value.tokenString.Length)) - { - if (str.Length > value.tokenString.Length) - { - // The str to be inserted has the same prefix as the current token, and str is longer. - // Insert str into this node, and shift every node behind it. - InsertAtCurrentHashNode(hashTable, str, ch, tokenType, tokenValue, i, hashcode, hashProbe); - return; - } - else - { - // Same token. If they have different types (regular token vs separator token). Add them. - // If we have the same regular token or separator token in the hash already, do NOT update the hash. - // Therefore, the order of inserting token is significant here regarding what tokenType will be kept in the hash. - - // Check the current value of RegularToken (stored in the lower 8-bit of tokenType) , and insert the tokenType into the hash ONLY when we don't have a RegularToken yet. - // Also check the current value of SeparatorToken (stored in the upper 8-bit of token), and insert the tokenType into the hash ONLY when we don't have the SeparatorToken yet. - - int nTokenType = (int)tokenType; - int nCurrentTokenTypeInHash = (int)value.tokenType; - - // The folowing is the fix for the issue of throwing FormatException when "mar" is passed in string of the short date format dd/MMM/yyyy for es-MX - if (((nCurrentTokenTypeInHash & (int)TokenType.RegularTokenMask) == 0) && ((nTokenType & (int)TokenType.RegularTokenMask) != 0) || - ((nCurrentTokenTypeInHash & (int)TokenType.SeparatorTokenMask) == 0) && ((nTokenType & (int)TokenType.SeparatorTokenMask) != 0)) - { - value.tokenType |= tokenType; - if (tokenValue != 0) - { - value.tokenValue = tokenValue; - } - } - // The token to be inserted is already in the table. Skip it. - return; - } - } - } - } - i++; - hashcode += hashProbe; - if (hashcode >= TOKEN_HASH_SIZE) hashcode -= TOKEN_HASH_SIZE; - } while (i < TOKEN_HASH_SIZE); - Debug.Fail("The hashtable is full. This should not happen."); - } - - private bool CompareStringIgnoreCaseOptimized(string string1, int offset1, int length1, string string2, int offset2, int length2) - { - // Optimize for one character cases which are common due to date and time separators (/ and :) - if (length1 == 1 && length2 == 1 && string1[offset1] == string2[offset2]) - { - return true; - } - - return Culture.CompareInfo.Compare(string1, offset1, length1, string2, offset2, length2, CompareOptions.IgnoreCase) == 0; - } - - internal class TokenHashValue - { - internal string tokenString; - internal TokenType tokenType; - internal int tokenValue; - - internal TokenHashValue(string tokenString, TokenType tokenType, int tokenValue) - { - this.tokenString = tokenString; - this.tokenType = tokenType; - this.tokenValue = tokenValue; - } - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/DateTimeFormatInfoScanner.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/DateTimeFormatInfoScanner.cs deleted file mode 100644 index 1ecdc35eac9..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/DateTimeFormatInfoScanner.cs +++ /dev/null @@ -1,712 +0,0 @@ -// 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. - -//////////////////////////////////////////////////////////////////////////// -// -// DateTimeFormatInfoScanner -// -// Scan a specified DateTimeFormatInfo to search for data used in DateTime.Parse() -// -// The data includes: -// -// DateWords: such as "de" used in es-ES (Spanish) LongDatePattern. -// Postfix: such as "ta" used in fi-FI after the month name. -// -// This class is shared among mscorlib.dll and sysglobl.dll. -// Use conditional CULTURE_AND_REGIONINFO_BUILDER_ONLY to differentiate between -// methods for mscorlib.dll and sysglobl.dll. -// -//////////////////////////////////////////////////////////////////////////// - -using System.Collections.Generic; -using System.Text; - -namespace System.Globalization -{ - // from LocaleEx.txt header - // IFORMATFLAGS - internal enum FORMATFLAGS - { - None = 0x00000000, - UseGenitiveMonth = 0x00000001, - UseLeapYearMonth = 0x00000002, - UseSpacesInMonthNames = 0x00000004, - UseHebrewParsing = 0x00000008, - UseSpacesInDayNames = 0x00000010, // Has spaces or non-breaking space in the day names. - UseDigitPrefixInTokens = 0x00000020, // Has token starting with numbers. - } - - internal enum CalendarId : ushort - { - UNINITIALIZED_VALUE = 0, - GREGORIAN = 1, // Gregorian (localized) calendar - GREGORIAN_US = 2, // Gregorian (U.S.) calendar - JAPAN = 3, // Japanese Emperor Era calendar - /* SSS_WARNINGS_OFF */ - TAIWAN = 4, // Taiwan Era calendar /* SSS_WARNINGS_ON */ - KOREA = 5, // Korean Tangun Era calendar - HIJRI = 6, // Hijri (Arabic Lunar) calendar - THAI = 7, // Thai calendar - HEBREW = 8, // Hebrew (Lunar) calendar - GREGORIAN_ME_FRENCH = 9, // Gregorian Middle East French calendar - GREGORIAN_ARABIC = 10, // Gregorian Arabic calendar - GREGORIAN_XLIT_ENGLISH = 11, // Gregorian Transliterated English calendar - GREGORIAN_XLIT_FRENCH = 12, - // Note that all calendars after this point are MANAGED ONLY for now. - JULIAN = 13, - JAPANESELUNISOLAR = 14, - CHINESELUNISOLAR = 15, - SAKA = 16, // reserved to match Office but not implemented in our code - LUNAR_ETO_CHN = 17, // reserved to match Office but not implemented in our code - LUNAR_ETO_KOR = 18, // reserved to match Office but not implemented in our code - LUNAR_ETO_ROKUYOU = 19, // reserved to match Office but not implemented in our code - KOREANLUNISOLAR = 20, - TAIWANLUNISOLAR = 21, - PERSIAN = 22, - UMALQURA = 23, - LAST_CALENDAR = 23 // Last calendar ID - } - - internal class DateTimeFormatInfoScanner - { - // Special prefix-like flag char in DateWord array. - - // Use char in PUA area since we won't be using them in real data. - // The char used to tell a read date word or a month postfix. A month postfix - // is "ta" in the long date pattern like "d. MMMM'ta 'yyyy" for fi-FI. - // In this case, it will be stored as "\xfffeta" in the date word array. - internal const char MonthPostfixChar = '\xe000'; - - // Add ignorable symbol in a DateWord array. - - // hu-HU has: - // shrot date pattern: yyyy. MM. dd.;yyyy-MM-dd;yy-MM-dd - // long date pattern: yyyy. MMMM d. - // Here, "." is the date separator (derived from short date pattern). However, - // "." also appear at the end of long date pattern. In this case, we just - // "." as ignorable symbol so that the DateTime.Parse() state machine will not - // treat the additional date separator at the end of y,m,d pattern as an error - // condition. - internal const char IgnorableSymbolChar = '\xe001'; - - // Known CJK suffix - 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"; - - // The collection fo date words & postfix. - internal List<string> m_dateWords = new List<string>(); - // Hashtable for the known words. - private static volatile Dictionary<string, string>? s_knownWords; - - private static Dictionary<string, string> KnownWords => - s_knownWords ??= - new Dictionary<string, string>(16) - { - // Add known words into the hash table. - - // Skip these special symbols. - { "/", string.Empty }, - { "-", string.Empty }, - { ".", string.Empty }, - - // Skip known CJK suffixes. - { CJKYearSuff, string.Empty }, - { CJKMonthSuff, string.Empty }, - { CJKDaySuff, string.Empty }, - { KoreanYearSuff, string.Empty }, - { KoreanMonthSuff, string.Empty }, - { KoreanDaySuff, string.Empty }, - { KoreanHourSuff, string.Empty }, - { KoreanMinuteSuff, string.Empty }, - { KoreanSecondSuff, string.Empty }, - { CJKHourSuff, string.Empty }, - { ChineseHourSuff, string.Empty }, - { CJKMinuteSuff, string.Empty }, - { CJKSecondSuff, string.Empty } - }; - - //////////////////////////////////////////////////////////////////////////// - // - // Parameters: - // pattern: The pattern to be scanned. - // currentIndex: the current index to start the scan. - // - // Returns: - // Return the index with the first character that is a letter, which will - // be the start of a date word. - // Note that the index can be pattern.Length if we reach the end of the string. - // - //////////////////////////////////////////////////////////////////////////// - internal static int SkipWhiteSpacesAndNonLetter(string pattern, int currentIndex) - { - while (currentIndex < pattern.Length) - { - char ch = pattern[currentIndex]; - if (ch == '\\') - { - // Escaped character. Look ahead one character. - currentIndex++; - if (currentIndex < pattern.Length) - { - ch = pattern[currentIndex]; - if (ch == '\'') - { - // Skip the leading single quote. We will - // stop at the first letter. - continue; - } - // Fall thru to check if this is a letter. - } - else - { - // End of string - break; - } - } - if (char.IsLetter(ch) || ch == '\'' || ch == '.') - { - break; - } - // Skip the current char since it is not a letter. - currentIndex++; - } - return currentIndex; - } - - //////////////////////////////////////////////////////////////////////////// - // - // A helper to add the found date word or month postfix into ArrayList for date words. - // - // Parameters: - // formatPostfix: What kind of postfix this is. - // Possible values: - // null: This is a regular date word - // "MMMM": month postfix - // word: The date word or postfix to be added. - // - //////////////////////////////////////////////////////////////////////////// - internal void AddDateWordOrPostfix(string? formatPostfix, string str) - { - if (str.Length > 0) - { - // Some cultures use . like an abbreviation - if (str.Equals(".")) - { - AddIgnorableSymbols("."); - return; - } - - if (!KnownWords.TryGetValue(str, out _)) - { - m_dateWords ??= new List<string>(); - - if (formatPostfix == "MMMM") - { - // Add the word into the ArrayList as "\xfffe" + real month postfix. - string temp = MonthPostfixChar + str; - if (!m_dateWords.Contains(temp)) - { - m_dateWords.Add(temp); - } - } - else - { - if (!m_dateWords.Contains(str)) - { - m_dateWords.Add(str); - } - if (str[^1] == '.') - { - // Old version ignore the trailing dot in the date words. Support this as well. - string strWithoutDot = str[0..^1]; - if (!m_dateWords.Contains(strWithoutDot)) - { - m_dateWords.Add(strWithoutDot); - } - } - } - } - } - } - - //////////////////////////////////////////////////////////////////////////// - // - // Scan the pattern from the specified index and add the date word/postfix - // when appropriate. - // - // Parameters: - // pattern: The pattern to be scanned. - // index: The starting index to be scanned. - // formatPostfix: The kind of postfix to be scanned. - // Possible values: - // null: This is a regular date word - // "MMMM": month postfix - // - // - //////////////////////////////////////////////////////////////////////////// - internal int AddDateWords(string pattern, int index, string? formatPostfix) - { - // Skip any whitespaces so we will start from a letter. - int newIndex = SkipWhiteSpacesAndNonLetter(pattern, index); - if (newIndex != index && formatPostfix != null) - { - // There are whitespaces. This will not be a postfix. - formatPostfix = null; - } - index = newIndex; - - // This is the first char added into dateWord. - // Skip all non-letter character. We will add the first letter into DateWord. - StringBuilder dateWord = new StringBuilder(); - // We assume that date words should start with a letter. - // Skip anything until we see a letter. - - while (index < pattern.Length) - { - char ch = pattern[index]; - if (ch == '\'') - { - // We have seen the end of quote. Add the word if we do not see it before, - // and break the while loop. - AddDateWordOrPostfix(formatPostfix, dateWord.ToString()); - index++; - break; - } - else if (ch == '\\') - { - // - // Escaped character. Look ahead one character - // - - // Skip escaped backslash. - index++; - if (index < pattern.Length) - { - dateWord.Append(pattern[index]); - index++; - } - } - else if (char.IsWhiteSpace(ch)) - { - // Found a whitespace. We have to add the current date word/postfix. - AddDateWordOrPostfix(formatPostfix, dateWord.ToString()); - if (formatPostfix != null) - { - // Done with postfix. The rest will be regular date word. - formatPostfix = null; - } - // Reset the dateWord. - dateWord.Length = 0; - index++; - } - else - { - dateWord.Append(ch); - index++; - } - } - return index; - } - - //////////////////////////////////////////////////////////////////////////// - // - // A simple helper to find the repeat count for a specified char. - // - //////////////////////////////////////////////////////////////////////////// - internal static int ScanRepeatChar(string pattern, char ch, int index, out int count) - { - count = 1; - while (++index < pattern.Length && pattern[index] == ch) - { - count++; - } - // Return the updated position. - return index; - } - - //////////////////////////////////////////////////////////////////////////// - // - // Add the text that is a date separator but is treated like ignorable symbol. - // E.g. - // hu-HU has: - // short date pattern: yyyy. MM. dd.;yyyy-MM-dd;yy-MM-dd - // long date pattern: yyyy. MMMM d. - // Here, "." is the date separator (derived from short date pattern). However, - // "." also appear at the end of long date pattern. In this case, we just - // "." as ignorable symbol so that the DateTime.Parse() state machine will not - // treat the additional date separator at the end of y,m,d pattern as an error - // condition. - // - //////////////////////////////////////////////////////////////////////////// - - internal void AddIgnorableSymbols(string? text) - { - if (m_dateWords == null) - { - // Create the date word array. - m_dateWords = new List<string>(); - } - // Add the ignorable symbol into the ArrayList. - string temp = IgnorableSymbolChar + text; - if (!m_dateWords.Contains(temp)) - { - m_dateWords.Add(temp); - } - } - - // - // Flag used to trace the date patterns (yy/yyyyy/M/MM/MMM/MMM/d/dd) that we have seen. - // - private enum FoundDatePattern - { - None = 0x0000, - FoundYearPatternFlag = 0x0001, - FoundMonthPatternFlag = 0x0002, - FoundDayPatternFlag = 0x0004, - FoundYMDPatternFlag = 0x0007, // FoundYearPatternFlag | FoundMonthPatternFlag | FoundDayPatternFlag; - } - - // Check if we have found all of the year/month/day pattern. - private FoundDatePattern _ymdFlags = FoundDatePattern.None; - - //////////////////////////////////////////////////////////////////////////// - // - // Given a date format pattern, scan for date word or postfix. - // - // A date word should be always put in a single quoted string. And it will - // start from a letter, so whitespace and symbols will be ignored before - // the first letter. - // - // Examples of date word: - // 'de' in es-SP: dddd, dd' de 'MMMM' de 'yyyy - // "\x0443." in bg-BG: dd.M.yyyy '\x0433.' - // - // Example of postfix: - // month postfix: - // "ta" in fi-FI: d. MMMM'ta 'yyyy - // Currently, only month postfix is supported. - // - // Usage: - // Always call this with Framework-style pattern, instead of Windows style pattern. - // Windows style pattern uses '' for single quote, while .NET uses \' - // - //////////////////////////////////////////////////////////////////////////// - internal void ScanDateWord(string pattern) - { - // Check if we have found all of the year/month/day pattern. - _ymdFlags = FoundDatePattern.None; - - int i = 0; - while (i < pattern.Length) - { - char ch = pattern[i]; - int chCount; - - switch (ch) - { - case '\'': - // Find a beginning quote. Search until the end quote. - i = AddDateWords(pattern, i + 1, null); - break; - case 'M': - i = ScanRepeatChar(pattern, 'M', i, out chCount); - if (chCount >= 4) - { - if (i < pattern.Length && pattern[i] == '\'') - { - i = AddDateWords(pattern, i + 1, "MMMM"); - } - } - _ymdFlags |= FoundDatePattern.FoundMonthPatternFlag; - break; - case 'y': - i = ScanRepeatChar(pattern, 'y', i, out chCount); - _ymdFlags |= FoundDatePattern.FoundYearPatternFlag; - break; - case 'd': - i = ScanRepeatChar(pattern, 'd', i, out chCount); - if (chCount <= 2) - { - // Only count "d" & "dd". - // ddd, dddd are day names. Do not count them. - _ymdFlags |= FoundDatePattern.FoundDayPatternFlag; - } - break; - case '\\': - // Found a escaped char not in a quoted string. Skip the current backslash - // and its next character. - i += 2; - break; - case '.': - if (_ymdFlags == FoundDatePattern.FoundYMDPatternFlag) - { - // If we find a dot immediately after the we have seen all of the y, m, d pattern. - // treat it as a ignroable symbol. Check for comments in AddIgnorableSymbols for - // more details. - AddIgnorableSymbols("."); - _ymdFlags = FoundDatePattern.None; - } - i++; - break; - default: - if (_ymdFlags == FoundDatePattern.FoundYMDPatternFlag && !char.IsWhiteSpace(ch)) - { - // We are not seeing "." after YMD. Clear the flag. - _ymdFlags = FoundDatePattern.None; - } - // We are not in quote. Skip the current character. - i++; - break; - } - } - } - - //////////////////////////////////////////////////////////////////////////// - // - // Given a DTFI, get all of the date words from date patterns and time patterns. - // - //////////////////////////////////////////////////////////////////////////// - - internal string[]? GetDateWordsOfDTFI(DateTimeFormatInfo dtfi) - { - // Enumarate all LongDatePatterns, and get the DateWords and scan for month postfix. - string[] datePatterns = dtfi.GetAllDateTimePatterns('D'); - int i; - - // Scan the long date patterns - for (i = 0; i < datePatterns.Length; i++) - { - ScanDateWord(datePatterns[i]); - } - - // Scan the short date patterns - datePatterns = dtfi.GetAllDateTimePatterns('d'); - for (i = 0; i < datePatterns.Length; i++) - { - ScanDateWord(datePatterns[i]); - } - // Scan the YearMonth patterns. - datePatterns = dtfi.GetAllDateTimePatterns('y'); - for (i = 0; i < datePatterns.Length; i++) - { - ScanDateWord(datePatterns[i]); - } - - // Scan the month/day pattern - ScanDateWord(dtfi.MonthDayPattern); - - // Scan the long time patterns. - datePatterns = dtfi.GetAllDateTimePatterns('T'); - for (i = 0; i < datePatterns.Length; i++) - { - ScanDateWord(datePatterns[i]); - } - - // Scan the short time patterns. - datePatterns = dtfi.GetAllDateTimePatterns('t'); - for (i = 0; i < datePatterns.Length; i++) - { - ScanDateWord(datePatterns[i]); - } - - string[]? result = null; - if (m_dateWords != null && m_dateWords.Count > 0) - { - result = new string[m_dateWords.Count]; - for (i = 0; i < m_dateWords.Count; i++) - { - result[i] = m_dateWords[i]; - } - } - return result; - } - - //////////////////////////////////////////////////////////////////////////// - // - // Scan the month names to see if genitive month names are used, and return - // the format flag. - // - //////////////////////////////////////////////////////////////////////////// - internal static FORMATFLAGS GetFormatFlagGenitiveMonth(string[] monthNames, string[] genitveMonthNames, string[] abbrevMonthNames, string[] genetiveAbbrevMonthNames) - { - // If we have different names in regular and genitive month names, use genitive month flag. - return (!EqualStringArrays(monthNames, genitveMonthNames) || !EqualStringArrays(abbrevMonthNames, genetiveAbbrevMonthNames)) - ? FORMATFLAGS.UseGenitiveMonth : 0; - } - - //////////////////////////////////////////////////////////////////////////// - // - // Scan the month names to see if spaces are used or start with a digit, and return the format flag - // - //////////////////////////////////////////////////////////////////////////// - internal static FORMATFLAGS GetFormatFlagUseSpaceInMonthNames(string[] monthNames, string[] genitveMonthNames, string[] abbrevMonthNames, string[] genetiveAbbrevMonthNames) - { - FORMATFLAGS formatFlags = 0; - formatFlags |= (ArrayElementsBeginWithDigit(monthNames) || - ArrayElementsBeginWithDigit(genitveMonthNames) || - ArrayElementsBeginWithDigit(abbrevMonthNames) || - ArrayElementsBeginWithDigit(genetiveAbbrevMonthNames) - ? FORMATFLAGS.UseDigitPrefixInTokens : 0); - - formatFlags |= (ArrayElementsHaveSpace(monthNames) || - ArrayElementsHaveSpace(genitveMonthNames) || - ArrayElementsHaveSpace(abbrevMonthNames) || - ArrayElementsHaveSpace(genetiveAbbrevMonthNames) - ? FORMATFLAGS.UseSpacesInMonthNames : 0); - return formatFlags; - } - - //////////////////////////////////////////////////////////////////////////// - // - // Scan the day names and set the correct format flag. - // - //////////////////////////////////////////////////////////////////////////// - internal static FORMATFLAGS GetFormatFlagUseSpaceInDayNames(string[] dayNames, string[] abbrevDayNames) - { - return (ArrayElementsHaveSpace(dayNames) || - ArrayElementsHaveSpace(abbrevDayNames)) - ? FORMATFLAGS.UseSpacesInDayNames : 0; - } - - //////////////////////////////////////////////////////////////////////////// - // - // Check the calendar to see if it is HebrewCalendar and set the Hebrew format flag if necessary. - // - //////////////////////////////////////////////////////////////////////////// - internal static FORMATFLAGS GetFormatFlagUseHebrewCalendar(int calID) - { - return calID == (int)CalendarId.HEBREW ? - FORMATFLAGS.UseHebrewParsing | FORMATFLAGS.UseLeapYearMonth : 0; - } - - //----------------------------------------------------------------------------- - // EqualStringArrays - // compares two string arrays and return true if all elements of the first - // array equals to all elements of the second array. - // otherwise it returns false. - //----------------------------------------------------------------------------- - - private static bool EqualStringArrays(string[] array1, string[] array2) - { - // Shortcut if they're the same array - if (array1 == array2) - { - return true; - } - - // This is effectively impossible - if (array1.Length != array2.Length) - { - return false; - } - - // Check each string - for (int i = 0; i < array1.Length; i++) - { - if (array1[i] != array2[i]) - { - return false; - } - } - - return true; - } - - //----------------------------------------------------------------------------- - // ArrayElementsHaveSpace - // It checks all input array elements if any of them has space character - // returns true if found space character in one of the array elements. - // otherwise returns false. - //----------------------------------------------------------------------------- - - private static bool ArrayElementsHaveSpace(string[] array) - { - for (int i = 0; i < array.Length; i++) - { - // it is faster to check for space character manually instead of calling IndexOf - // so we don't have to go to native code side. - for (int j = 0; j < array[i].Length; j++) - { - if (char.IsWhiteSpace(array[i][j])) - { - return true; - } - } - } - - return false; - } - - //////////////////////////////////////////////////////////////////////////// - // - // Check if any element of the array start with a digit. - // - //////////////////////////////////////////////////////////////////////////// - private static bool ArrayElementsBeginWithDigit(string[] array) - { - for (int i = 0; i < array.Length; i++) - { - // it is faster to check for space character manually instead of calling IndexOf - // so we don't have to go to native code side. - if (array[i].Length > 0 && - array[i][0] >= '0' && array[i][0] <= '9') - { - int index = 1; - while (index < array[i].Length && array[i][index] >= '0' && array[i][index] <= '9') - { - // Skip other digits. - index++; - } - if (index == array[i].Length) - { - return false; - } - - if (index == array[i].Length - 1) - { - // Skip known CJK month suffix. - // CJK uses month name like "1\x6708", since \x6708 is a known month suffix, - // we don't need the UseDigitPrefixInTokens since it is slower. - switch (array[i][index]) - { - case '\x6708': // CJKMonthSuff - case '\xc6d4': // KoreanMonthSuff - return false; - } - } - - if (index == array[i].Length - 4) - { - // Skip known CJK month suffix. - // Starting with Windows 8, the CJK months for some cultures looks like: "1' \x6708'" - // instead of just "1\x6708" - if (array[i][index] == '\'' && array[i][index + 1] == ' ' && - array[i][index + 2] == '\x6708' && array[i][index + 3] == '\'') - { - return false; - } - } - return true; - } - } - - return false; - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/DateTimeParse.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/DateTimeParse.cs deleted file mode 100644 index 50002e6e04e..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/DateTimeParse.cs +++ /dev/null @@ -1,6106 +0,0 @@ -// 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; -using System.Globalization; -using System.Runtime.CompilerServices; -using System.Text; - -namespace System -{ - internal static class DateTimeParse - { - internal const int MaxDateTimeNumberDigits = 8; - - internal delegate bool MatchNumberDelegate(ref __DTString str, int digitLen, out int result); - - internal static MatchNumberDelegate m_hebrewNumberParser = new MatchNumberDelegate(DateTimeParse.MatchHebrewDigits); - - internal static DateTime ParseExact(ReadOnlySpan<char> s, ReadOnlySpan<char> format, DateTimeFormatInfo dtfi, DateTimeStyles style) - { - DateTimeResult result = default; // The buffer to store the parsing result. - result.Init(s); - if (TryParseExact(s, format, dtfi, style, ref result)) - { - return result.parsedDate; - } - else - { - throw GetDateTimeParseException(ref result); - } - } - - internal static DateTime ParseExact(ReadOnlySpan<char> s, ReadOnlySpan<char> format, DateTimeFormatInfo dtfi, DateTimeStyles style, out TimeSpan offset) - { - DateTimeResult result = default; // The buffer to store the parsing result. - result.Init(s); - result.flags |= ParseFlags.CaptureOffset; - if (TryParseExact(s, format, dtfi, style, ref result)) - { - offset = result.timeZoneOffset; - return result.parsedDate; - } - else - { - throw GetDateTimeParseException(ref result); - } - } - - internal static bool TryParseExact(ReadOnlySpan<char> s, ReadOnlySpan<char> format, DateTimeFormatInfo dtfi, DateTimeStyles style, out DateTime result) - { - DateTimeResult resultData = default; // The buffer to store the parsing result. - resultData.Init(s); - - if (TryParseExact(s, format, dtfi, style, ref resultData)) - { - result = resultData.parsedDate; - return true; - } - - result = DateTime.MinValue; - return false; - } - - internal static bool TryParseExact(ReadOnlySpan<char> s, ReadOnlySpan<char> format, DateTimeFormatInfo dtfi, DateTimeStyles style, out DateTime result, out TimeSpan offset) - { - DateTimeResult resultData = default; // The buffer to store the parsing result. - resultData.Init(s); - resultData.flags |= ParseFlags.CaptureOffset; - - if (TryParseExact(s, format, dtfi, style, ref resultData)) - { - result = resultData.parsedDate; - offset = resultData.timeZoneOffset; - return true; - } - - result = DateTime.MinValue; - offset = TimeSpan.Zero; - return false; - } - - internal static bool TryParseExact(ReadOnlySpan<char> s, ReadOnlySpan<char> format, DateTimeFormatInfo dtfi, DateTimeStyles style, ref DateTimeResult result) - { - if (s.Length == 0) - { - result.SetFailure(ParseFailureKind.FormatWithParameter, nameof(SR.Format_BadDateTime)); - return false; - } - - if (format.Length == 0) - { - result.SetBadFormatSpecifierFailure(); - return false; - } - - Debug.Assert(dtfi != null, "dtfi == null"); - - return DoStrictParse(s, format, style, dtfi, ref result); - } - - internal static DateTime ParseExactMultiple(ReadOnlySpan<char> s, string[] formats, - DateTimeFormatInfo dtfi, DateTimeStyles style) - { - DateTimeResult result = default; // The buffer to store the parsing result. - result.Init(s); - if (TryParseExactMultiple(s, formats, dtfi, style, ref result)) - { - return result.parsedDate; - } - else - { - throw GetDateTimeParseException(ref result); - } - } - - internal static DateTime ParseExactMultiple(ReadOnlySpan<char> s, string[] formats, - DateTimeFormatInfo dtfi, DateTimeStyles style, out TimeSpan offset) - { - DateTimeResult result = default; // The buffer to store the parsing result. - result.Init(s); - result.flags |= ParseFlags.CaptureOffset; - if (TryParseExactMultiple(s, formats, dtfi, style, ref result)) - { - offset = result.timeZoneOffset; - return result.parsedDate; - } - else - { - throw GetDateTimeParseException(ref result); - } - } - - internal static bool TryParseExactMultiple(ReadOnlySpan<char> s, string?[]? formats, - DateTimeFormatInfo dtfi, DateTimeStyles style, out DateTime result, out TimeSpan offset) - { - DateTimeResult resultData = default; // The buffer to store the parsing result. - resultData.Init(s); - resultData.flags |= ParseFlags.CaptureOffset; - - if (TryParseExactMultiple(s, formats, dtfi, style, ref resultData)) - { - result = resultData.parsedDate; - offset = resultData.timeZoneOffset; - return true; - } - - result = DateTime.MinValue; - offset = TimeSpan.Zero; - return false; - } - - internal static bool TryParseExactMultiple(ReadOnlySpan<char> s, string?[]? formats, - DateTimeFormatInfo dtfi, DateTimeStyles style, out DateTime result) - { - DateTimeResult resultData = default; // The buffer to store the parsing result. - resultData.Init(s); - - if (TryParseExactMultiple(s, formats, dtfi, style, ref resultData)) - { - result = resultData.parsedDate; - return true; - } - - result = DateTime.MinValue; - return false; - } - - internal static bool TryParseExactMultiple(ReadOnlySpan<char> s, string?[]? formats, - DateTimeFormatInfo dtfi, DateTimeStyles style, ref DateTimeResult result) - { - if (formats == null) - { - result.SetFailure(ParseFailureKind.ArgumentNull, nameof(SR.ArgumentNull_String), null, nameof(formats)); - return false; - } - - if (s.Length == 0) - { - result.SetFailure(ParseFailureKind.FormatWithParameter, nameof(SR.Format_BadDateTime)); - return false; - } - - if (formats.Length == 0) - { - result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_NoFormatSpecifier)); - return false; - } - - Debug.Assert(dtfi != null, "dtfi == null"); - - // - // Do a loop through the provided formats and see if we can parse successfully in - // one of the formats. - // - for (int i = 0; i < formats.Length; i++) - { - if (formats[i] == null || formats[i]!.Length == 0) // TODO-NULLABLE: Indexer nullability tracked (https://github.com/dotnet/roslyn/issues/34644) - { - result.SetBadFormatSpecifierFailure(); - return false; - } - // Create a new result each time to ensure the runs are independent. Carry through - // flags from the caller and return the result. - DateTimeResult innerResult = default; // The buffer to store the parsing result. - innerResult.Init(s); - innerResult.flags = result.flags; - if (TryParseExact(s, formats[i], dtfi, style, ref innerResult)) - { - result.parsedDate = innerResult.parsedDate; - result.timeZoneOffset = innerResult.timeZoneOffset; - return true; - } - } - result.SetBadDateTimeFailure(); - return false; - } - - //////////////////////////////////////////////////////////////////////////// - // Date Token Types - // - // Following is the set of tokens that can be generated from a date - // string. Notice that the legal set of trailing separators have been - // folded in with the date number, and month name tokens. This set - // of tokens is chosen to reduce the number of date parse states. - // - //////////////////////////////////////////////////////////////////////////// - - internal enum DTT : int - { - End = 0, // '\0' - NumEnd = 1, // Num[ ]*[\0] - NumAmpm = 2, // Num[ ]+AmPm - NumSpace = 3, // Num[ ]+^[Dsep|Tsep|'0\'] - NumDatesep = 4, // Num[ ]*Dsep - NumTimesep = 5, // Num[ ]*Tsep - MonthEnd = 6, // Month[ ]*'\0' - MonthSpace = 7, // Month[ ]+^[Dsep|Tsep|'\0'] - MonthDatesep = 8, // Month[ ]*Dsep - NumDatesuff = 9, // Month[ ]*DSuff - NumTimesuff = 10, // Month[ ]*TSuff - DayOfWeek = 11, // Day of week name - YearSpace = 12, // Year+^[Dsep|Tsep|'0\'] - YearDateSep = 13, // Year+Dsep - YearEnd = 14, // Year+['\0'] - TimeZone = 15, // timezone name - Era = 16, // era name - NumUTCTimeMark = 17, // Num + 'Z' - // When you add a new token which will be in the - // state table, add it after NumLocalTimeMark. - Unk = 18, // unknown - NumLocalTimeMark = 19, // Num + 'T' - Max = 20, // marker - } - - internal enum TM - { - NotSet = -1, - AM = 0, - PM = 1, - } - - //////////////////////////////////////////////////////////////////////////// - // - // DateTime parsing state enumeration (DS.*) - // - //////////////////////////////////////////////////////////////////////////// - - internal enum DS - { - BEGIN = 0, - N = 1, // have one number - NN = 2, // have two numbers - - // The following are known to be part of a date - - D_Nd = 3, // date string: have number followed by date separator - D_NN = 4, // date string: have two numbers - D_NNd = 5, // date string: have two numbers followed by date separator - - D_M = 6, // date string: have a month - D_MN = 7, // date string: have a month and a number - D_NM = 8, // date string: have a number and a month - D_MNd = 9, // date string: have a month and number followed by date separator - D_NDS = 10, // date string: have one number followed a date suffix. - - D_Y = 11, // date string: have a year. - D_YN = 12, // date string: have a year and a number - D_YNd = 13, // date string: have a year and a number and a date separator - D_YM = 14, // date string: have a year and a month - D_YMd = 15, // date string: have a year and a month and a date separator - D_S = 16, // have numbers followed by a date suffix. - T_S = 17, // have numbers followed by a time suffix. - - // The following are known to be part of a time - - T_Nt = 18, // have num followed by time separator - T_NNt = 19, // have two numbers followed by time separator - - ERROR = 20, - - // The following are terminal states. These all have an action - // associated with them; and transition back to BEGIN. - - DX_NN = 21, // day from two numbers - DX_NNN = 22, // day from three numbers - DX_MN = 23, // day from month and one number - DX_NM = 24, // day from month and one number - DX_MNN = 25, // day from month and two numbers - DX_DS = 26, // a set of date suffixed numbers. - DX_DSN = 27, // day from date suffixes and one number. - DX_NDS = 28, // day from one number and date suffixes . - DX_NNDS = 29, // day from one number and date suffixes . - - DX_YNN = 30, // date string: have a year and two number - DX_YMN = 31, // date string: have a year, a month, and a number. - DX_YN = 32, // date string: have a year and one number - DX_YM = 33, // date string: have a year, a month. - TX_N = 34, // time from one number (must have ampm) - TX_NN = 35, // time from two numbers - TX_NNN = 36, // time from three numbers - TX_TS = 37, // a set of time suffixed numbers. - DX_NNY = 38, - } - - //////////////////////////////////////////////////////////////////////////// - // - // NOTE: The following state machine table is dependent on the order of the - // DS and DTT enumerations. - // - // For each non terminal state, the following table defines the next state - // for each given date token type. - // - //////////////////////////////////////////////////////////////////////////// - - // End NumEnd NumAmPm NumSpace NumDaySep NumTimesep MonthEnd MonthSpace MonthDSep NumDateSuff NumTimeSuff DayOfWeek YearSpace YearDateSep YearEnd TimeZone Era UTCTimeMark - private static readonly DS[][] dateParsingStates = { -// DS.BEGIN // DS.BEGIN -new DS[] { DS.BEGIN, DS.ERROR, DS.TX_N, DS.N, DS.D_Nd, DS.T_Nt, DS.ERROR, DS.D_M, DS.D_M, DS.D_S, DS.T_S, DS.BEGIN, DS.D_Y, DS.D_Y, DS.ERROR, DS.BEGIN, DS.BEGIN, DS.ERROR }, - -// DS.N // DS.N -new DS[] { DS.ERROR, DS.DX_NN, DS.ERROR, DS.NN, DS.D_NNd, DS.ERROR, DS.DX_NM, DS.D_NM, DS.D_MNd, DS.D_NDS, DS.ERROR, DS.N, DS.D_YN, DS.D_YNd, DS.DX_YN, DS.N, DS.N, DS.ERROR }, - -// DS.NN // DS.NN -new DS[] { DS.DX_NN, DS.DX_NNN, DS.TX_N, DS.DX_NNN, DS.ERROR, DS.T_Nt, DS.DX_MNN, DS.DX_MNN, DS.ERROR, DS.ERROR, DS.T_S, DS.NN, DS.DX_NNY, DS.ERROR, DS.DX_NNY, DS.NN, DS.NN, DS.ERROR }, - -// DS.D_Nd // DS.D_Nd -new DS[] { DS.ERROR, DS.DX_NN, DS.ERROR, DS.D_NN, DS.D_NNd, DS.ERROR, DS.DX_NM, DS.D_MN, DS.D_MNd, DS.ERROR, DS.ERROR, DS.D_Nd, DS.D_YN, DS.D_YNd, DS.DX_YN, DS.ERROR, DS.D_Nd, DS.ERROR }, - -// DS.D_NN // DS.D_NN -new DS[] { DS.DX_NN, DS.DX_NNN, DS.TX_N, DS.DX_NNN, DS.ERROR, DS.T_Nt, DS.DX_MNN, DS.DX_MNN, DS.ERROR, DS.DX_DS, DS.T_S, DS.D_NN, DS.DX_NNY, DS.ERROR, DS.DX_NNY, DS.ERROR, DS.D_NN, DS.ERROR }, - -// DS.D_NNd // DS.D_NNd -new DS[] { DS.ERROR, DS.DX_NNN, DS.DX_NNN, DS.DX_NNN, DS.ERROR, DS.ERROR, DS.DX_MNN, DS.DX_MNN, DS.ERROR, DS.DX_DS, DS.ERROR, DS.D_NNd, DS.DX_NNY, DS.ERROR, DS.DX_NNY, DS.ERROR, DS.D_NNd, DS.ERROR }, - -// DS.D_M // DS.D_M -new DS[] { DS.ERROR, DS.DX_MN, DS.ERROR, DS.D_MN, DS.D_MNd, DS.ERROR, DS.ERROR, DS.ERROR, DS.ERROR, DS.ERROR, DS.ERROR, DS.D_M, DS.D_YM, DS.D_YMd, DS.DX_YM, DS.ERROR, DS.D_M, DS.ERROR }, - -// DS.D_MN // DS.D_MN -new DS[] { DS.DX_MN, DS.DX_MNN, DS.DX_MNN, DS.DX_MNN, DS.ERROR, DS.T_Nt, DS.ERROR, DS.ERROR, DS.ERROR, DS.DX_DS, DS.T_S, DS.D_MN, DS.DX_YMN, DS.ERROR, DS.DX_YMN, DS.ERROR, DS.D_MN, DS.ERROR }, - -// DS.D_NM // DS.D_NM -new DS[] { DS.DX_NM, DS.DX_MNN, DS.DX_MNN, DS.DX_MNN, DS.ERROR, DS.T_Nt, DS.ERROR, DS.ERROR, DS.ERROR, DS.DX_DS, DS.T_S, DS.D_NM, DS.DX_YMN, DS.ERROR, DS.DX_YMN, DS.ERROR, DS.D_NM, DS.ERROR }, - -// DS.D_MNd // DS.D_MNd -new DS[] { DS.ERROR, DS.DX_MNN, DS.ERROR, DS.DX_MNN, DS.ERROR, DS.ERROR, DS.ERROR, DS.ERROR, DS.ERROR, DS.ERROR, DS.ERROR, DS.D_MNd, DS.DX_YMN, DS.ERROR, DS.DX_YMN, DS.ERROR, DS.D_MNd, DS.ERROR }, - -// DS.D_NDS, // DS.D_NDS, -new DS[] { DS.DX_NDS, DS.DX_NNDS, DS.DX_NNDS, DS.DX_NNDS, DS.ERROR, DS.T_Nt, DS.ERROR, DS.ERROR, DS.ERROR, DS.D_NDS, DS.T_S, DS.D_NDS, DS.ERROR, DS.ERROR, DS.ERROR, DS.ERROR, DS.D_NDS, DS.ERROR }, - -// DS.D_Y // DS.D_Y -new DS[] { DS.ERROR, DS.DX_YN, DS.ERROR, DS.D_YN, DS.D_YNd, DS.ERROR, DS.DX_YM, DS.D_YM, DS.D_YMd, DS.D_YM, DS.ERROR, DS.D_Y, DS.ERROR, DS.ERROR, DS.ERROR, DS.ERROR, DS.D_Y, DS.ERROR }, - -// DS.D_YN // DS.D_YN -new DS[] { DS.DX_YN, DS.DX_YNN, DS.DX_YNN, DS.DX_YNN, DS.ERROR, DS.ERROR, DS.DX_YMN, DS.DX_YMN, DS.ERROR, DS.ERROR, DS.ERROR, DS.D_YN, DS.ERROR, DS.ERROR, DS.ERROR, DS.ERROR, DS.D_YN, DS.ERROR }, - -// DS.D_YNd // DS.D_YNd -new DS[] { DS.ERROR, DS.DX_YNN, DS.DX_YNN, DS.DX_YNN, DS.ERROR, DS.ERROR, DS.DX_YMN, DS.DX_YMN, DS.ERROR, DS.ERROR, DS.ERROR, DS.D_YN, DS.ERROR, DS.ERROR, DS.ERROR, DS.ERROR, DS.D_YN, DS.ERROR }, - -// DS.D_YM // DS.D_YM -new DS[] { DS.DX_YM, DS.DX_YMN, DS.DX_YMN, DS.DX_YMN, DS.ERROR, DS.ERROR, DS.ERROR, DS.ERROR, DS.ERROR, DS.ERROR, DS.ERROR, DS.D_YM, DS.ERROR, DS.ERROR, DS.ERROR, DS.ERROR, DS.D_YM, DS.ERROR }, - -// DS.D_YMd // DS.D_YMd -new DS[] { DS.ERROR, DS.DX_YMN, DS.DX_YMN, DS.DX_YMN, DS.ERROR, DS.ERROR, DS.ERROR, DS.ERROR, DS.ERROR, DS.ERROR, DS.ERROR, DS.D_YM, DS.ERROR, DS.ERROR, DS.ERROR, DS.ERROR, DS.D_YM, DS.ERROR }, - -// DS.D_S // DS.D_S -new DS[] { DS.DX_DS, DS.DX_DSN, DS.TX_N, DS.T_Nt, DS.ERROR, DS.T_Nt, DS.ERROR, DS.ERROR, DS.ERROR, DS.D_S, DS.T_S, DS.D_S, DS.ERROR, DS.ERROR, DS.ERROR, DS.ERROR, DS.D_S, DS.ERROR }, - -// DS.T_S // DS.T_S -new DS[] { DS.TX_TS, DS.TX_TS, DS.TX_TS, DS.T_Nt, DS.D_Nd, DS.ERROR, DS.ERROR, DS.ERROR, DS.ERROR, DS.D_S, DS.T_S, DS.T_S, DS.ERROR, DS.ERROR, DS.ERROR, DS.T_S, DS.T_S, DS.ERROR }, - -// DS.T_Nt // DS.T_Nt -new DS[] { DS.ERROR, DS.TX_NN, DS.TX_NN, DS.TX_NN, DS.ERROR, DS.T_NNt, DS.DX_NM, DS.D_NM, DS.ERROR, DS.ERROR, DS.T_S, DS.ERROR, DS.ERROR, DS.ERROR, DS.ERROR, DS.T_Nt, DS.T_Nt, DS.TX_NN }, - -// DS.T_NNt // DS.T_NNt -new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR, DS.ERROR, DS.ERROR, DS.ERROR, DS.ERROR, DS.T_S, DS.T_NNt, DS.ERROR, DS.ERROR, DS.ERROR, DS.T_NNt, DS.T_NNt, DS.TX_NNN }, -}; - // End NumEnd NumAmPm NumSpace NumDaySep NumTimesep MonthEnd MonthSpace MonthDSep NumDateSuff NumTimeSuff DayOfWeek YearSpace YearDateSep YearEnd TimeZone Era UTCMark - - internal const string GMTName = "GMT"; - internal const string ZuluName = "Z"; - - // - // Search from the index of str at str.Index to see if the target string exists in the str. - // - private static bool MatchWord(ref __DTString str, string target) - { - if (target.Length > (str.Value.Length - str.Index)) - { - return false; - } - - if (str.CompareInfo.Compare(str.Value.Slice(str.Index, target.Length), target, CompareOptions.IgnoreCase) != 0) - { - return false; - } - - int nextCharIndex = str.Index + target.Length; - - if (nextCharIndex < str.Value.Length) - { - char nextCh = str.Value[nextCharIndex]; - if (char.IsLetter(nextCh)) - { - return false; - } - } - str.Index = nextCharIndex; - if (str.Index < str.Length) - { - str.m_current = str.Value[str.Index]; - } - - return true; - } - - // - // Check the word at the current index to see if it matches GMT name or Zulu name. - // - private static bool GetTimeZoneName(ref __DTString str) - { - if (MatchWord(ref str, GMTName)) - { - return true; - } - - if (MatchWord(ref str, ZuluName)) - { - return true; - } - - return false; - } - - internal static bool IsDigit(char ch) => (uint)(ch - '0') <= 9; - - /*=================================ParseFraction========================== - **Action: Starting at the str.Index, which should be a decimal symbol. - ** if the current character is a digit, parse the remaining - ** numbers as fraction. For example, if the sub-string starting at str.Index is "123", then - ** the method will return 0.123 - **Returns: The fraction number. - **Arguments: - ** str the parsing string - **Exceptions: - ============================================================================*/ - - private static bool ParseFraction(ref __DTString str, out double result) - { - result = 0; - double decimalBase = 0.1; - int digits = 0; - char ch; - while (str.GetNext() - && IsDigit(ch = str.m_current)) - { - result += (ch - '0') * decimalBase; - decimalBase *= 0.1; - digits++; - } - return digits > 0; - } - - /*=================================ParseTimeZone========================== - **Action: Parse the timezone offset in the following format: - ** "+8", "+08", "+0800", "+0800" - ** This method is used by DateTime.Parse(). - **Returns: The TimeZone offset. - **Arguments: - ** str the parsing string - **Exceptions: - ** FormatException if invalid timezone format is found. - ============================================================================*/ - - private static bool ParseTimeZone(ref __DTString str, ref TimeSpan result) - { - // The hour/minute offset for timezone. - int hourOffset; - int minuteOffset = 0; - - // Consume the +/- character that has already been read - DTSubString sub = str.GetSubString(); - if (sub.length != 1) - { - return false; - } - char offsetChar = sub[0]; - if (offsetChar != '+' && offsetChar != '-') - { - return false; - } - str.ConsumeSubString(sub); - - sub = str.GetSubString(); - if (sub.type != DTSubStringType.Number) - { - return false; - } - int value = sub.value; - int length = sub.length; - if (length == 1 || length == 2) - { - // Parsing "+8" or "+08" - hourOffset = value; - str.ConsumeSubString(sub); - // See if we have minutes - sub = str.GetSubString(); - if (sub.length == 1 && sub[0] == ':') - { - // Parsing "+8:00" or "+08:00" - str.ConsumeSubString(sub); - sub = str.GetSubString(); - if (sub.type != DTSubStringType.Number || sub.length < 1 || sub.length > 2) - { - return false; - } - minuteOffset = sub.value; - str.ConsumeSubString(sub); - } - } - else if (length == 3 || length == 4) - { - // Parsing "+800" or "+0800" - hourOffset = value / 100; - minuteOffset = value % 100; - str.ConsumeSubString(sub); - } - else - { - // Wrong number of digits - return false; - } - Debug.Assert(hourOffset >= 0 && hourOffset <= 99, "hourOffset >= 0 && hourOffset <= 99"); - Debug.Assert(minuteOffset >= 0 && minuteOffset <= 99, "minuteOffset >= 0 && minuteOffset <= 99"); - if (minuteOffset < 0 || minuteOffset >= 60) - { - return false; - } - - result = new TimeSpan(hourOffset, minuteOffset, 0); - if (offsetChar == '-') - { - result = result.Negate(); - } - return true; - } - - // This is the helper function to handle timezone in string in the format like +/-0800 - private static bool HandleTimeZone(ref __DTString str, ref DateTimeResult result) - { - if (str.Index < str.Length - 1) - { - char nextCh = str.Value[str.Index]; - // Skip whitespace, but don't update the index unless we find a time zone marker - int whitespaceCount = 0; - while (char.IsWhiteSpace(nextCh) && str.Index + whitespaceCount < str.Length - 1) - { - whitespaceCount++; - nextCh = str.Value[str.Index + whitespaceCount]; - } - if (nextCh == '+' || nextCh == '-') - { - str.Index += whitespaceCount; - if ((result.flags & ParseFlags.TimeZoneUsed) != 0) - { - // Should not have two timezone offsets. - result.SetBadDateTimeFailure(); - return false; - } - result.flags |= ParseFlags.TimeZoneUsed; - if (!ParseTimeZone(ref str, ref result.timeZoneOffset)) - { - result.SetBadDateTimeFailure(); - return false; - } - } - } - return true; - } - - // - // This is the lexer. Check the character at the current index, and put the found token in dtok and - // some raw date/time information in raw. - // - private static bool Lex(DS dps, ref __DTString str, ref DateTimeToken dtok, ref DateTimeRawInfo raw, ref DateTimeResult result, ref DateTimeFormatInfo dtfi, DateTimeStyles styles) - { - TokenType tokenType; - int tokenValue; - int indexBeforeSeparator; - char charBeforeSeparator; - - TokenType sep; - dtok.dtt = DTT.Unk; // Assume the token is unkown. - - str.GetRegularToken(out tokenType, out tokenValue, dtfi); - -#if _LOGGING - if (_tracingEnabled) - { - Trace($"Lex({Hex(str.Value)})\tpos:{str.Index}({Hex(str.m_current)}), {tokenType}, DS.{dps}"); - } -#endif // _LOGGING - - // Look at the regular token. - switch (tokenType) - { - case TokenType.NumberToken: - case TokenType.YearNumberToken: - if (raw.numCount == 3 || tokenValue == -1) - { - result.SetBadDateTimeFailure(); - LexTraceExit("0010", dps); - return false; - } - // - // This is a digit. - // - // If the previous parsing state is DS.T_NNt (like 12:01), and we got another number, - // so we will have a terminal state DS.TX_NNN (like 12:01:02). - // If the previous parsing state is DS.T_Nt (like 12:), and we got another number, - // so we will have a terminal state DS.TX_NN (like 12:01). - // - // Look ahead to see if the following character is a decimal point or timezone offset. - // This enables us to parse time in the forms of: - // "11:22:33.1234" or "11:22:33-08". - if (dps == DS.T_NNt) - { - if (str.Index < str.Length - 1) - { - char nextCh = str.Value[str.Index]; - if (nextCh == '.') - { - // While ParseFraction can fail, it just means that there were no digits after - // the dot. In this case ParseFraction just removes the dot. This is actually - // valid for cultures like Albanian, that join the time marker to the time with - // with a dot: e.g. "9:03.MD" - ParseFraction(ref str, out raw.fraction); - } - } - } - if (dps == DS.T_NNt || dps == DS.T_Nt) - { - if (str.Index < str.Length - 1) - { - if (!HandleTimeZone(ref str, ref result)) - { - LexTraceExit("0020 (value like \"12:01\" or \"12:\" followed by a non-TZ number", dps); - return false; - } - } - } - - dtok.num = tokenValue; - if (tokenType == TokenType.YearNumberToken) - { - if (raw.year == -1) - { - raw.year = tokenValue; - // - // If we have number which has 3 or more digits (like "001" or "0001"), - // we assume this number is a year. Save the current raw.numCount in - // raw.year. - // - switch (sep = str.GetSeparatorToken(dtfi, out indexBeforeSeparator, out charBeforeSeparator)) - { - case TokenType.SEP_End: - dtok.dtt = DTT.YearEnd; - break; - case TokenType.SEP_Am: - case TokenType.SEP_Pm: - if (raw.timeMark == TM.NotSet) - { - raw.timeMark = (sep == TokenType.SEP_Am ? TM.AM : TM.PM); - dtok.dtt = DTT.YearSpace; - } - else - { - result.SetBadDateTimeFailure(); - LexTraceExit("0030 (TM.AM/TM.PM Happened more than 1x)", dps); - } - break; - case TokenType.SEP_Space: - dtok.dtt = DTT.YearSpace; - break; - case TokenType.SEP_Date: - dtok.dtt = DTT.YearDateSep; - break; - case TokenType.SEP_Time: - if (!raw.hasSameDateAndTimeSeparators) - { - result.SetBadDateTimeFailure(); - LexTraceExit("0040 (Invalid separator after number)", dps); - return false; - } - - // we have the date and time separators are same and getting a year number, then change the token to YearDateSep as - // we are sure we are not parsing time. - dtok.dtt = DTT.YearDateSep; - break; - case TokenType.SEP_DateOrOffset: - // The separator is either a date separator or the start of a time zone offset. If the token will complete the date then - // process just the number and roll back the index so that the outer loop can attempt to parse the time zone offset. - if ((dateParsingStates[(int)dps][(int)DTT.YearDateSep] == DS.ERROR) - && (dateParsingStates[(int)dps][(int)DTT.YearSpace] > DS.ERROR)) - { - str.Index = indexBeforeSeparator; - str.m_current = charBeforeSeparator; - dtok.dtt = DTT.YearSpace; - } - else - { - dtok.dtt = DTT.YearDateSep; - } - break; - case TokenType.SEP_YearSuff: - case TokenType.SEP_MonthSuff: - case TokenType.SEP_DaySuff: - dtok.dtt = DTT.NumDatesuff; - dtok.suffix = sep; - break; - case TokenType.SEP_HourSuff: - case TokenType.SEP_MinuteSuff: - case TokenType.SEP_SecondSuff: - dtok.dtt = DTT.NumTimesuff; - dtok.suffix = sep; - break; - default: - // Invalid separator after number number. - result.SetBadDateTimeFailure(); - LexTraceExit("0040 (Invalid separator after number)", dps); - return false; - } - // - // Found the token already. Return now. - // - LexTraceExit("0050 (success)", dps); - return true; - } - result.SetBadDateTimeFailure(); - LexTraceExit("0060", dps); - return false; - } - switch (sep = str.GetSeparatorToken(dtfi, out indexBeforeSeparator, out charBeforeSeparator)) - { - // - // Note here we check if the numCount is less than three. - // When we have more than three numbers, it will be caught as error in the state machine. - // - case TokenType.SEP_End: - dtok.dtt = DTT.NumEnd; - raw.AddNumber(dtok.num); - break; - case TokenType.SEP_Am: - case TokenType.SEP_Pm: - if (raw.timeMark == TM.NotSet) - { - raw.timeMark = (sep == TokenType.SEP_Am ? TM.AM : TM.PM); - dtok.dtt = DTT.NumAmpm; - // Fix AM/PM parsing case, e.g. "1/10 5 AM" - if (dps == DS.D_NN) - { - if (!ProcessTerminalState(DS.DX_NN, ref str, ref result, ref styles, ref raw, dtfi)) - { - return false; - } - } - - raw.AddNumber(dtok.num); - } - else - { - result.SetBadDateTimeFailure(); - break; - } - if (dps == DS.T_NNt || dps == DS.T_Nt) - { - if (!HandleTimeZone(ref str, ref result)) - { - LexTraceExit("0070 (HandleTimeZone returned false)", dps); - return false; - } - } - break; - case TokenType.SEP_Space: - dtok.dtt = DTT.NumSpace; - raw.AddNumber(dtok.num); - break; - case TokenType.SEP_Date: - dtok.dtt = DTT.NumDatesep; - raw.AddNumber(dtok.num); - break; - case TokenType.SEP_DateOrOffset: - // The separator is either a date separator or the start of a time zone offset. If the token will complete the date then - // process just the number and roll back the index so that the outer loop can attempt to parse the time zone offset. - if ((dateParsingStates[(int)dps][(int)DTT.NumDatesep] == DS.ERROR) - && (dateParsingStates[(int)dps][(int)DTT.NumSpace] > DS.ERROR)) - { - str.Index = indexBeforeSeparator; - str.m_current = charBeforeSeparator; - dtok.dtt = DTT.NumSpace; - } - else - { - dtok.dtt = DTT.NumDatesep; - } - raw.AddNumber(dtok.num); - break; - case TokenType.SEP_Time: - if (raw.hasSameDateAndTimeSeparators && - (dps == DS.D_Y || dps == DS.D_YN || dps == DS.D_YNd || dps == DS.D_YM || dps == DS.D_YMd)) - { - // we are parsing a date and we have the time separator same as date separator, so we mark the token as date separator - dtok.dtt = DTT.NumDatesep; - raw.AddNumber(dtok.num); - break; - } - dtok.dtt = DTT.NumTimesep; - raw.AddNumber(dtok.num); - break; - case TokenType.SEP_YearSuff: - try - { - dtok.num = dtfi.Calendar.ToFourDigitYear(tokenValue); - } - catch (ArgumentOutOfRangeException) - { - result.SetBadDateTimeFailure(); - LexTraceExit("0075 (Calendar.ToFourDigitYear failed)", dps); - return false; - } - dtok.dtt = DTT.NumDatesuff; - dtok.suffix = sep; - break; - case TokenType.SEP_MonthSuff: - case TokenType.SEP_DaySuff: - dtok.dtt = DTT.NumDatesuff; - dtok.suffix = sep; - break; - case TokenType.SEP_HourSuff: - case TokenType.SEP_MinuteSuff: - case TokenType.SEP_SecondSuff: - dtok.dtt = DTT.NumTimesuff; - dtok.suffix = sep; - break; - case TokenType.SEP_LocalTimeMark: - dtok.dtt = DTT.NumLocalTimeMark; - raw.AddNumber(dtok.num); - break; - default: - // Invalid separator after number number. - result.SetBadDateTimeFailure(); - LexTraceExit("0080", dps); - return false; - } - break; - case TokenType.HebrewNumber: - if (tokenValue >= 100) - { - // This is a year number - if (raw.year == -1) - { - raw.year = tokenValue; - // - // If we have number which has 3 or more digits (like "001" or "0001"), - // we assume this number is a year. Save the current raw.numCount in - // raw.year. - // - switch (sep = str.GetSeparatorToken(dtfi, out indexBeforeSeparator, out charBeforeSeparator)) - { - case TokenType.SEP_End: - dtok.dtt = DTT.YearEnd; - break; - case TokenType.SEP_Space: - dtok.dtt = DTT.YearSpace; - break; - case TokenType.SEP_DateOrOffset: - // The separator is either a date separator or the start of a time zone offset. If the token will complete the date then - // process just the number and roll back the index so that the outer loop can attempt to parse the time zone offset. - if (dateParsingStates[(int)dps][(int)DTT.YearSpace] > DS.ERROR) - { - str.Index = indexBeforeSeparator; - str.m_current = charBeforeSeparator; - dtok.dtt = DTT.YearSpace; - break; - } - goto default; - default: - // Invalid separator after number number. - result.SetBadDateTimeFailure(); - LexTraceExit("0090", dps); - return false; - } - } - else - { - // Invalid separator after number number. - result.SetBadDateTimeFailure(); - LexTraceExit("0100", dps); - return false; - } - } - else - { - // This is a day number - dtok.num = tokenValue; - raw.AddNumber(dtok.num); - - switch (sep = str.GetSeparatorToken(dtfi, out indexBeforeSeparator, out charBeforeSeparator)) - { - // - // Note here we check if the numCount is less than three. - // When we have more than three numbers, it will be caught as error in the state machine. - // - case TokenType.SEP_End: - dtok.dtt = DTT.NumEnd; - break; - case TokenType.SEP_Space: - case TokenType.SEP_Date: - dtok.dtt = DTT.NumDatesep; - break; - case TokenType.SEP_DateOrOffset: - // The separator is either a date separator or the start of a time zone offset. If the token will complete the date then - // process just the number and roll back the index so that the outer loop can attempt to parse the time zone offset. - if ((dateParsingStates[(int)dps][(int)DTT.NumDatesep] == DS.ERROR) - && (dateParsingStates[(int)dps][(int)DTT.NumSpace] > DS.ERROR)) - { - str.Index = indexBeforeSeparator; - str.m_current = charBeforeSeparator; - dtok.dtt = DTT.NumSpace; - } - else - { - dtok.dtt = DTT.NumDatesep; - } - break; - default: - // Invalid separator after number number. - result.SetBadDateTimeFailure(); - LexTraceExit("0110", dps); - return false; - } - } - break; - case TokenType.DayOfWeekToken: - if (raw.dayOfWeek == -1) - { - // - // This is a day of week name. - // - raw.dayOfWeek = tokenValue; - dtok.dtt = DTT.DayOfWeek; - } - else - { - result.SetBadDateTimeFailure(); - LexTraceExit("0120 (DayOfWeek seen more than 1x)", dps); - return false; - } - break; - case TokenType.MonthToken: - if (raw.month == -1) - { - // - // This is a month name - // - switch (sep = str.GetSeparatorToken(dtfi, out indexBeforeSeparator, out charBeforeSeparator)) - { - case TokenType.SEP_End: - dtok.dtt = DTT.MonthEnd; - break; - case TokenType.SEP_Space: - dtok.dtt = DTT.MonthSpace; - break; - case TokenType.SEP_Date: - dtok.dtt = DTT.MonthDatesep; - break; - case TokenType.SEP_Time: - if (!raw.hasSameDateAndTimeSeparators) - { - result.SetBadDateTimeFailure(); - LexTraceExit("0130 (Invalid separator after month name)", dps); - return false; - } - - // we have the date and time separators are same and getting a Month name, then change the token to MonthDatesep as - // we are sure we are not parsing time. - dtok.dtt = DTT.MonthDatesep; - break; - case TokenType.SEP_DateOrOffset: - // The separator is either a date separator or the start of a time zone offset. If the token will complete the date then - // process just the number and roll back the index so that the outer loop can attempt to parse the time zone offset. - if ((dateParsingStates[(int)dps][(int)DTT.MonthDatesep] == DS.ERROR) - && (dateParsingStates[(int)dps][(int)DTT.MonthSpace] > DS.ERROR)) - { - str.Index = indexBeforeSeparator; - str.m_current = charBeforeSeparator; - dtok.dtt = DTT.MonthSpace; - } - else - { - dtok.dtt = DTT.MonthDatesep; - } - break; - default: - // Invalid separator after month name - result.SetBadDateTimeFailure(); - LexTraceExit("0130 (Invalid separator after month name)", dps); - return false; - } - raw.month = tokenValue; - } - else - { - result.SetBadDateTimeFailure(); - LexTraceExit("0140 (MonthToken seen more than 1x)", dps); - return false; - } - break; - case TokenType.EraToken: - if (result.era != -1) - { - result.era = tokenValue; - dtok.dtt = DTT.Era; - } - else - { - result.SetBadDateTimeFailure(); - LexTraceExit("0150 (EraToken seen when result.era already set)", dps); - return false; - } - break; - case TokenType.JapaneseEraToken: - // Special case for Japanese. We allow Japanese era name to be used even if the calendar is not Japanese Calendar. - result.calendar = JapaneseCalendar.GetDefaultInstance(); - dtfi = DateTimeFormatInfo.GetJapaneseCalendarDTFI(); - if (result.era != -1) - { - result.era = tokenValue; - dtok.dtt = DTT.Era; - } - else - { - result.SetBadDateTimeFailure(); - LexTraceExit("0160 (JapaneseEraToken seen when result.era already set)", dps); - return false; - } - break; - case TokenType.TEraToken: - result.calendar = TaiwanCalendar.GetDefaultInstance(); - dtfi = DateTimeFormatInfo.GetTaiwanCalendarDTFI(); - if (result.era != -1) - { - result.era = tokenValue; - dtok.dtt = DTT.Era; - } - else - { - result.SetBadDateTimeFailure(); - LexTraceExit("0170 (TEraToken seen when result.era already set)", dps); - return false; - } - break; - case TokenType.TimeZoneToken: - // - // This is a timezone designator - // - // NOTENOTE : for now, we only support "GMT" and "Z" (for Zulu time). - // - if ((result.flags & ParseFlags.TimeZoneUsed) != 0) - { - // Should not have two timezone offsets. - result.SetBadDateTimeFailure(); - LexTraceExit("0180 (seen GMT or Z more than 1x)", dps); - return false; - } - dtok.dtt = DTT.TimeZone; - result.flags |= ParseFlags.TimeZoneUsed; - result.timeZoneOffset = new TimeSpan(0); - result.flags |= ParseFlags.TimeZoneUtc; - break; - case TokenType.EndOfString: - dtok.dtt = DTT.End; - break; - case TokenType.DateWordToken: - case TokenType.IgnorableSymbol: - // Date words and ignorable symbols can just be skipped over - break; - case TokenType.Am: - case TokenType.Pm: - if (raw.timeMark == TM.NotSet) - { - raw.timeMark = (TM)tokenValue; - } - else - { - result.SetBadDateTimeFailure(); - LexTraceExit("0190 (AM/PM timeMark already set)", dps); - return false; - } - break; - case TokenType.UnknownToken: - if (char.IsLetter(str.m_current)) - { - result.SetFailure(ParseFailureKind.FormatWithOriginalDateTimeAndParameter, nameof(SR.Format_UnknownDateTimeWord), str.Index); - LexTraceExit("0200", dps); - return false; - } - - if ((str.m_current == '-' || str.m_current == '+') && ((result.flags & ParseFlags.TimeZoneUsed) == 0)) - { - int originalIndex = str.Index; - if (ParseTimeZone(ref str, ref result.timeZoneOffset)) - { - result.flags |= ParseFlags.TimeZoneUsed; - LexTraceExit("0220 (success)", dps); - return true; - } - else - { - // Time zone parse attempt failed. Fall through to punctuation handling. - str.Index = originalIndex; - } - } - - // Visual Basic implements string to date conversions on top of DateTime.Parse: - // CDate("#10/10/95#") - // - if (VerifyValidPunctuation(ref str)) - { - LexTraceExit("0230 (success)", dps); - return true; - } - - result.SetBadDateTimeFailure(); - LexTraceExit("0240", dps); - return false; - } - - LexTraceExit("0250 (success)", dps); - return true; - } - - private static bool VerifyValidPunctuation(ref __DTString str) - { - // Compatability Behavior. Allow trailing nulls and surrounding hashes - char ch = str.Value[str.Index]; - if (ch == '#') - { - bool foundStart = false; - bool foundEnd = false; - for (int i = 0; i < str.Length; i++) - { - ch = str.Value[i]; - if (ch == '#') - { - if (foundStart) - { - if (foundEnd) - { - // Having more than two hashes is invalid - return false; - } - else - { - foundEnd = true; - } - } - else - { - foundStart = true; - } - } - else if (ch == '\0') - { - // Allow nulls only at the end - if (!foundEnd) - { - return false; - } - } - else if (!char.IsWhiteSpace(ch)) - { - // Anything other than whitespace outside hashes is invalid - if (!foundStart || foundEnd) - { - return false; - } - } - } - if (!foundEnd) - { - // The has was un-paired - return false; - } - // Valid Hash usage: eat the hash and continue. - str.GetNext(); - return true; - } - else if (ch == '\0') - { - for (int i = str.Index; i < str.Length; i++) - { - if (str.Value[i] != '\0') - { - // Nulls are only valid if they are the only trailing character - return false; - } - } - // Move to the end of the string - str.Index = str.Length; - return true; - } - return false; - } - - private const int ORDER_YMD = 0; // The order of date is Year/Month/Day. - private const int ORDER_MDY = 1; // The order of date is Month/Day/Year. - private const int ORDER_DMY = 2; // The order of date is Day/Month/Year. - private const int ORDER_YDM = 3; // The order of date is Year/Day/Month - private const int ORDER_YM = 4; // Year/Month order. - private const int ORDER_MY = 5; // Month/Year order. - private const int ORDER_MD = 6; // Month/Day order. - private const int ORDER_DM = 7; // Day/Month order. - - // - // Decide the year/month/day order from the datePattern. - // - // Return 0 for YMD, 1 for MDY, 2 for DMY, otherwise -1. - // - private static bool GetYearMonthDayOrder(string datePattern, out int order) - { - int yearOrder = -1; - int monthOrder = -1; - int dayOrder = -1; - int orderCount = 0; - - bool inQuote = false; - - for (int i = 0; i < datePattern.Length && orderCount < 3; i++) - { - char ch = datePattern[i]; - if (ch == '\\' || ch == '%') - { - i++; - continue; // Skip next character that is escaped by this backslash - } - - if (ch == '\'' || ch == '"') - { - inQuote = !inQuote; - } - - if (!inQuote) - { - if (ch == 'y') - { - yearOrder = orderCount++; - - // - // Skip all year pattern charaters. - // - for (; i + 1 < datePattern.Length && datePattern[i + 1] == 'y'; i++) - { - // Do nothing here. - } - } - else if (ch == 'M') - { - monthOrder = orderCount++; - // - // Skip all month pattern characters. - // - for (; i + 1 < datePattern.Length && datePattern[i + 1] == 'M'; i++) - { - // Do nothing here. - } - } - else if (ch == 'd') - { - int patternCount = 1; - // - // Skip all day pattern characters. - // - for (; i + 1 < datePattern.Length && datePattern[i + 1] == 'd'; i++) - { - patternCount++; - } - // - // Make sure this is not "ddd" or "dddd", which means day of week. - // - if (patternCount <= 2) - { - dayOrder = orderCount++; - } - } - } - } - - if (yearOrder == 0 && monthOrder == 1 && dayOrder == 2) - { - order = ORDER_YMD; - return true; - } - if (monthOrder == 0 && dayOrder == 1 && yearOrder == 2) - { - order = ORDER_MDY; - return true; - } - if (dayOrder == 0 && monthOrder == 1 && yearOrder == 2) - { - order = ORDER_DMY; - return true; - } - if (yearOrder == 0 && dayOrder == 1 && monthOrder == 2) - { - order = ORDER_YDM; - return true; - } - order = -1; - return false; - } - - // - // Decide the year/month order from the pattern. - // - // Return 0 for YM, 1 for MY, otherwise -1. - // - private static bool GetYearMonthOrder(string pattern, out int order) - { - int yearOrder = -1; - int monthOrder = -1; - int orderCount = 0; - - bool inQuote = false; - for (int i = 0; i < pattern.Length && orderCount < 2; i++) - { - char ch = pattern[i]; - if (ch == '\\' || ch == '%') - { - i++; - continue; // Skip next character that is escaped by this backslash - } - - if (ch == '\'' || ch == '"') - { - inQuote = !inQuote; - } - - if (!inQuote) - { - if (ch == 'y') - { - yearOrder = orderCount++; - - // - // Skip all year pattern charaters. - // - for (; i + 1 < pattern.Length && pattern[i + 1] == 'y'; i++) - { - } - } - else if (ch == 'M') - { - monthOrder = orderCount++; - // - // Skip all month pattern characters. - // - for (; i + 1 < pattern.Length && pattern[i + 1] == 'M'; i++) - { - } - } - } - } - - if (yearOrder == 0 && monthOrder == 1) - { - order = ORDER_YM; - return true; - } - if (monthOrder == 0 && yearOrder == 1) - { - order = ORDER_MY; - return true; - } - order = -1; - return false; - } - - // - // Decide the month/day order from the pattern. - // - // Return 0 for MD, 1 for DM, otherwise -1. - // - private static bool GetMonthDayOrder(string pattern, out int order) - { - int monthOrder = -1; - int dayOrder = -1; - int orderCount = 0; - - bool inQuote = false; - for (int i = 0; i < pattern.Length && orderCount < 2; i++) - { - char ch = pattern[i]; - if (ch == '\\' || ch == '%') - { - i++; - continue; // Skip next character that is escaped by this backslash - } - - if (ch == '\'' || ch == '"') - { - inQuote = !inQuote; - } - - if (!inQuote) - { - if (ch == 'd') - { - int patternCount = 1; - // - // Skip all day pattern charaters. - // - for (; i + 1 < pattern.Length && pattern[i + 1] == 'd'; i++) - { - patternCount++; - } - - // - // Make sure this is not "ddd" or "dddd", which means day of week. - // - if (patternCount <= 2) - { - dayOrder = orderCount++; - } - } - else if (ch == 'M') - { - monthOrder = orderCount++; - // - // Skip all month pattern characters. - // - for (; i + 1 < pattern.Length && pattern[i + 1] == 'M'; i++) - { - } - } - } - } - - if (monthOrder == 0 && dayOrder == 1) - { - order = ORDER_MD; - return true; - } - if (dayOrder == 0 && monthOrder == 1) - { - order = ORDER_DM; - return true; - } - order = -1; - return false; - } - - // - // Adjust the two-digit year if necessary. - // - private static bool TryAdjustYear(ref DateTimeResult result, int year, out int adjustedYear) - { - if (year < 100) - { - try - { - // the Calendar classes need some real work. Many of the calendars that throw - // don't implement a fast/non-allocating (and non-throwing) IsValid{Year|Day|Month} method. - // we are making a targeted try/catch fix in the in-place release but will revisit this code - // in the next side-by-side release. - year = result.calendar.ToFourDigitYear(year); - } - catch (ArgumentOutOfRangeException) - { - adjustedYear = -1; - return false; - } - } - adjustedYear = year; - return true; - } - - private static bool SetDateYMD(ref DateTimeResult result, int year, int month, int day) - { - // Note, longer term these checks should be done at the end of the parse. This current - // way of checking creates order dependence with parsing the era name. - if (result.calendar.IsValidDay(year, month, day, result.era)) - { - result.SetDate(year, month, day); // YMD - return true; - } - return false; - } - - private static bool SetDateMDY(ref DateTimeResult result, int month, int day, int year) - { - return SetDateYMD(ref result, year, month, day); - } - - private static bool SetDateDMY(ref DateTimeResult result, int day, int month, int year) - { - return SetDateYMD(ref result, year, month, day); - } - - private static bool SetDateYDM(ref DateTimeResult result, int year, int day, int month) - { - return SetDateYMD(ref result, year, month, day); - } - - private static void GetDefaultYear(ref DateTimeResult result, ref DateTimeStyles styles) - { - result.Year = result.calendar.GetYear(GetDateTimeNow(ref result, ref styles)); - result.flags |= ParseFlags.YearDefault; - } - - // Processing teriminal case: DS.DX_NN - private static bool GetDayOfNN(ref DateTimeResult result, ref DateTimeStyles styles, ref DateTimeRawInfo raw, DateTimeFormatInfo dtfi) - { - if ((result.flags & ParseFlags.HaveDate) != 0) - { - // Multiple dates in the input string - result.SetBadDateTimeFailure(); - return false; - } - - int n1 = raw.GetNumber(0); - int n2 = raw.GetNumber(1); - - GetDefaultYear(ref result, ref styles); - - int order; - if (!GetMonthDayOrder(dtfi.MonthDayPattern, out order)) - { - result.SetFailure(ParseFailureKind.FormatWithParameter, nameof(SR.Format_BadDatePattern), dtfi.MonthDayPattern); - return false; - } - - if (order == ORDER_MD) - { - if (SetDateYMD(ref result, result.Year, n1, n2)) // MD - { - result.flags |= ParseFlags.HaveDate; - return true; - } - } - else - { - // ORDER_DM - if (SetDateYMD(ref result, result.Year, n2, n1)) // DM - { - result.flags |= ParseFlags.HaveDate; - return true; - } - } - result.SetBadDateTimeFailure(); - return false; - } - - // Processing teriminal case: DS.DX_NNN - private static bool GetDayOfNNN(ref DateTimeResult result, ref DateTimeRawInfo raw, DateTimeFormatInfo dtfi) - { - if ((result.flags & ParseFlags.HaveDate) != 0) - { - // Multiple dates in the input string - result.SetBadDateTimeFailure(); - return false; - } - - int n1 = raw.GetNumber(0); - int n2 = raw.GetNumber(1); - int n3 = raw.GetNumber(2); - - int order; - if (!GetYearMonthDayOrder(dtfi.ShortDatePattern, out order)) - { - result.SetFailure(ParseFailureKind.FormatWithParameter, nameof(SR.Format_BadDatePattern), dtfi.ShortDatePattern); - return false; - } - int year; - - if (order == ORDER_YMD) - { - if (TryAdjustYear(ref result, n1, out year) && SetDateYMD(ref result, year, n2, n3)) // YMD - { - result.flags |= ParseFlags.HaveDate; - return true; - } - } - else if (order == ORDER_MDY) - { - if (TryAdjustYear(ref result, n3, out year) && SetDateMDY(ref result, n1, n2, year)) // MDY - { - result.flags |= ParseFlags.HaveDate; - return true; - } - } - else if (order == ORDER_DMY) - { - if (TryAdjustYear(ref result, n3, out year) && SetDateDMY(ref result, n1, n2, year)) // DMY - { - result.flags |= ParseFlags.HaveDate; - return true; - } - } - else if (order == ORDER_YDM) - { - if (TryAdjustYear(ref result, n1, out year) && SetDateYDM(ref result, year, n2, n3)) // YDM - { - result.flags |= ParseFlags.HaveDate; - return true; - } - } - result.SetBadDateTimeFailure(); - return false; - } - - private static bool GetDayOfMN(ref DateTimeResult result, ref DateTimeStyles styles, ref DateTimeRawInfo raw, DateTimeFormatInfo dtfi) - { - if ((result.flags & ParseFlags.HaveDate) != 0) - { - // Multiple dates in the input string - result.SetBadDateTimeFailure(); - return false; - } - - // The interpretation is based on the MonthDayPattern and YearMonthPattern - // - // MonthDayPattern YearMonthPattern Interpretation - // --------------- ---------------- --------------- - // MMMM dd MMMM yyyy Day - // MMMM dd yyyy MMMM Day - // dd MMMM MMMM yyyy Year - // dd MMMM yyyy MMMM Day - // - // In the first and last cases, it could be either or neither, but a day is a better default interpretation - // than a 2 digit year. - - int monthDayOrder; - if (!GetMonthDayOrder(dtfi.MonthDayPattern, out monthDayOrder)) - { - result.SetFailure(ParseFailureKind.FormatWithParameter, nameof(SR.Format_BadDatePattern), dtfi.MonthDayPattern); - return false; - } - if (monthDayOrder == ORDER_DM) - { - int yearMonthOrder; - if (!GetYearMonthOrder(dtfi.YearMonthPattern, out yearMonthOrder)) - { - result.SetFailure(ParseFailureKind.FormatWithParameter, nameof(SR.Format_BadDatePattern), dtfi.YearMonthPattern); - return false; - } - if (yearMonthOrder == ORDER_MY) - { - int year; - if (!TryAdjustYear(ref result, raw.GetNumber(0), out year) || !SetDateYMD(ref result, year, raw.month, 1)) - { - result.SetBadDateTimeFailure(); - return false; - } - return true; - } - } - - GetDefaultYear(ref result, ref styles); - if (!SetDateYMD(ref result, result.Year, raw.month, raw.GetNumber(0))) - { - result.SetBadDateTimeFailure(); - return false; - } - return true; - } - - //////////////////////////////////////////////////////////////////////// - // Actions: - // Deal with the terminal state for Hebrew Month/Day pattern - // - //////////////////////////////////////////////////////////////////////// - - private static bool GetHebrewDayOfNM(ref DateTimeResult result, ref DateTimeRawInfo raw, DateTimeFormatInfo dtfi) - { - int monthDayOrder; - if (!GetMonthDayOrder(dtfi.MonthDayPattern, out monthDayOrder)) - { - result.SetFailure(ParseFailureKind.FormatWithParameter, nameof(SR.Format_BadDatePattern), dtfi.MonthDayPattern); - return false; - } - result.Month = raw.month; - if (monthDayOrder == ORDER_DM || monthDayOrder == ORDER_MD) - { - if (result.calendar.IsValidDay(result.Year, result.Month, raw.GetNumber(0), result.era)) - { - result.Day = raw.GetNumber(0); - return true; - } - } - result.SetBadDateTimeFailure(); - return false; - } - - private static bool GetDayOfNM(ref DateTimeResult result, ref DateTimeStyles styles, ref DateTimeRawInfo raw, DateTimeFormatInfo dtfi) - { - if ((result.flags & ParseFlags.HaveDate) != 0) - { - // Multiple dates in the input string - result.SetBadDateTimeFailure(); - return false; - } - - // The interpretation is based on the MonthDayPattern and YearMonthPattern - // - // MonthDayPattern YearMonthPattern Interpretation - // --------------- ---------------- --------------- - // MMMM dd MMMM yyyy Day - // MMMM dd yyyy MMMM Year - // dd MMMM MMMM yyyy Day - // dd MMMM yyyy MMMM Day - // - // In the first and last cases, it could be either or neither, but a day is a better default interpretation - // than a 2 digit year. - - int monthDayOrder; - if (!GetMonthDayOrder(dtfi.MonthDayPattern, out monthDayOrder)) - { - result.SetFailure(ParseFailureKind.FormatWithParameter, nameof(SR.Format_BadDatePattern), dtfi.MonthDayPattern); - return false; - } - if (monthDayOrder == ORDER_MD) - { - int yearMonthOrder; - if (!GetYearMonthOrder(dtfi.YearMonthPattern, out yearMonthOrder)) - { - result.SetFailure(ParseFailureKind.FormatWithParameter, nameof(SR.Format_BadDatePattern), dtfi.YearMonthPattern); - return false; - } - if (yearMonthOrder == ORDER_YM) - { - int year; - if (!TryAdjustYear(ref result, raw.GetNumber(0), out year) || !SetDateYMD(ref result, year, raw.month, 1)) - { - result.SetBadDateTimeFailure(); - return false; - } - return true; - } - } - - GetDefaultYear(ref result, ref styles); - if (!SetDateYMD(ref result, result.Year, raw.month, raw.GetNumber(0))) - { - result.SetBadDateTimeFailure(); - return false; - } - return true; - } - - private static bool GetDayOfMNN(ref DateTimeResult result, ref DateTimeRawInfo raw, DateTimeFormatInfo dtfi) - { - if ((result.flags & ParseFlags.HaveDate) != 0) - { - // Multiple dates in the input string - result.SetBadDateTimeFailure(); - return false; - } - - int n1 = raw.GetNumber(0); - int n2 = raw.GetNumber(1); - - int order; - if (!GetYearMonthDayOrder(dtfi.ShortDatePattern, out order)) - { - result.SetFailure(ParseFailureKind.FormatWithParameter, nameof(SR.Format_BadDatePattern), dtfi.ShortDatePattern); - return false; - } - int year; - - if (order == ORDER_MDY) - { - if (TryAdjustYear(ref result, n2, out year) && result.calendar.IsValidDay(year, raw.month, n1, result.era)) - { - result.SetDate(year, raw.month, n1); // MDY - result.flags |= ParseFlags.HaveDate; - return true; - } - else if (TryAdjustYear(ref result, n1, out year) && result.calendar.IsValidDay(year, raw.month, n2, result.era)) - { - result.SetDate(year, raw.month, n2); // YMD - result.flags |= ParseFlags.HaveDate; - return true; - } - } - else if (order == ORDER_YMD) - { - if (TryAdjustYear(ref result, n1, out year) && result.calendar.IsValidDay(year, raw.month, n2, result.era)) - { - result.SetDate(year, raw.month, n2); // YMD - result.flags |= ParseFlags.HaveDate; - return true; - } - else if (TryAdjustYear(ref result, n2, out year) && result.calendar.IsValidDay(year, raw.month, n1, result.era)) - { - result.SetDate(year, raw.month, n1); // DMY - result.flags |= ParseFlags.HaveDate; - return true; - } - } - else if (order == ORDER_DMY) - { - if (TryAdjustYear(ref result, n2, out year) && result.calendar.IsValidDay(year, raw.month, n1, result.era)) - { - result.SetDate(year, raw.month, n1); // DMY - result.flags |= ParseFlags.HaveDate; - return true; - } - else if (TryAdjustYear(ref result, n1, out year) && result.calendar.IsValidDay(year, raw.month, n2, result.era)) - { - result.SetDate(year, raw.month, n2); // YMD - result.flags |= ParseFlags.HaveDate; - return true; - } - } - - result.SetBadDateTimeFailure(); - return false; - } - - private static bool GetDayOfYNN(ref DateTimeResult result, ref DateTimeRawInfo raw, DateTimeFormatInfo dtfi) - { - if ((result.flags & ParseFlags.HaveDate) != 0) - { - // Multiple dates in the input string - result.SetBadDateTimeFailure(); - return false; - } - - int n1 = raw.GetNumber(0); - int n2 = raw.GetNumber(1); - string pattern = dtfi.ShortDatePattern; - - // For compatibility, don't throw if we can't determine the order, but default to YMD instead - int order; - if (GetYearMonthDayOrder(pattern, out order) && order == ORDER_YDM) - { - if (SetDateYMD(ref result, raw.year, n2, n1)) - { - result.flags |= ParseFlags.HaveDate; - return true; // Year + DM - } - } - else - { - if (SetDateYMD(ref result, raw.year, n1, n2)) - { - result.flags |= ParseFlags.HaveDate; - return true; // Year + MD - } - } - result.SetBadDateTimeFailure(); - return false; - } - - private static bool GetDayOfNNY(ref DateTimeResult result, ref DateTimeRawInfo raw, DateTimeFormatInfo dtfi) - { - if ((result.flags & ParseFlags.HaveDate) != 0) - { - // Multiple dates in the input string - result.SetBadDateTimeFailure(); - return false; - } - - int n1 = raw.GetNumber(0); - int n2 = raw.GetNumber(1); - - int order; - if (!GetYearMonthDayOrder(dtfi.ShortDatePattern, out order)) - { - result.SetFailure(ParseFailureKind.FormatWithParameter, nameof(SR.Format_BadDatePattern), dtfi.ShortDatePattern); - return false; - } - - if (order == ORDER_MDY || order == ORDER_YMD) - { - if (SetDateYMD(ref result, raw.year, n1, n2)) - { - result.flags |= ParseFlags.HaveDate; - return true; // MD + Year - } - } - else - { - if (SetDateYMD(ref result, raw.year, n2, n1)) - { - result.flags |= ParseFlags.HaveDate; - return true; // DM + Year - } - } - result.SetBadDateTimeFailure(); - return false; - } - - private static bool GetDayOfYMN(ref DateTimeResult result, ref DateTimeRawInfo raw) - { - if ((result.flags & ParseFlags.HaveDate) != 0) - { - // Multiple dates in the input string - result.SetBadDateTimeFailure(); - return false; - } - - if (SetDateYMD(ref result, raw.year, raw.month, raw.GetNumber(0))) - { - result.flags |= ParseFlags.HaveDate; - return true; - } - result.SetBadDateTimeFailure(); - return false; - } - - private static bool GetDayOfYN(ref DateTimeResult result, ref DateTimeRawInfo raw) - { - if ((result.flags & ParseFlags.HaveDate) != 0) - { - // Multiple dates in the input string - result.SetBadDateTimeFailure(); - return false; - } - - if (SetDateYMD(ref result, raw.year, raw.GetNumber(0), 1)) - { - result.flags |= ParseFlags.HaveDate; - return true; - } - result.SetBadDateTimeFailure(); - return false; - } - - private static bool GetDayOfYM(ref DateTimeResult result, ref DateTimeRawInfo raw) - { - if ((result.flags & ParseFlags.HaveDate) != 0) - { - // Multiple dates in the input string - result.SetBadDateTimeFailure(); - return false; - } - - if (SetDateYMD(ref result, raw.year, raw.month, 1)) - { - result.flags |= ParseFlags.HaveDate; - return true; - } - result.SetBadDateTimeFailure(); - return false; - } - - private static void AdjustTimeMark(DateTimeFormatInfo dtfi, ref DateTimeRawInfo raw) - { - // Specail case for culture which uses AM as empty string. - // E.g. af-ZA (0x0436) - // S1159 \x0000 - // S2359 nm - // In this case, if we are parsing a string like "2005/09/14 12:23", we will assume this is in AM. - - if (raw.timeMark == TM.NotSet) - { - if (dtfi.AMDesignator != null && dtfi.PMDesignator != null) - { - if (dtfi.AMDesignator.Length == 0 && dtfi.PMDesignator.Length != 0) - { - raw.timeMark = TM.AM; - } - if (dtfi.PMDesignator.Length == 0 && dtfi.AMDesignator.Length != 0) - { - raw.timeMark = TM.PM; - } - } - } - } - - // - // Adjust hour according to the time mark. - // - private static bool AdjustHour(ref int hour, TM timeMark) - { - if (timeMark != TM.NotSet) - { - if (timeMark == TM.AM) - { - if (hour < 0 || hour > 12) - { - return false; - } - hour = (hour == 12) ? 0 : hour; - } - else - { - if (hour < 0 || hour > 23) - { - return false; - } - if (hour < 12) - { - hour += 12; - } - } - } - return true; - } - - private static bool GetTimeOfN(ref DateTimeResult result, ref DateTimeRawInfo raw) - { - if ((result.flags & ParseFlags.HaveTime) != 0) - { - // Multiple times in the input string - result.SetBadDateTimeFailure(); - return false; - } - // - // In this case, we need a time mark. Check if so. - // - if (raw.timeMark == TM.NotSet) - { - result.SetBadDateTimeFailure(); - return false; - } - result.Hour = raw.GetNumber(0); - result.flags |= ParseFlags.HaveTime; - return true; - } - - private static bool GetTimeOfNN(ref DateTimeResult result, ref DateTimeRawInfo raw) - { - Debug.Assert(raw.numCount >= 2, "raw.numCount >= 2"); - if ((result.flags & ParseFlags.HaveTime) != 0) - { - // Multiple times in the input string - result.SetBadDateTimeFailure(); - return false; - } - - result.Hour = raw.GetNumber(0); - result.Minute = raw.GetNumber(1); - result.flags |= ParseFlags.HaveTime; - return true; - } - - private static bool GetTimeOfNNN(ref DateTimeResult result, ref DateTimeRawInfo raw) - { - if ((result.flags & ParseFlags.HaveTime) != 0) - { - // Multiple times in the input string - result.SetBadDateTimeFailure(); - return false; - } - Debug.Assert(raw.numCount >= 3, "raw.numCount >= 3"); - result.Hour = raw.GetNumber(0); - result.Minute = raw.GetNumber(1); - result.Second = raw.GetNumber(2); - result.flags |= ParseFlags.HaveTime; - return true; - } - - // - // Processing terminal state: A Date suffix followed by one number. - // - private static bool GetDateOfDSN(ref DateTimeResult result, ref DateTimeRawInfo raw) - { - if (raw.numCount != 1 || result.Day != -1) - { - result.SetBadDateTimeFailure(); - return false; - } - result.Day = raw.GetNumber(0); - return true; - } - - private static bool GetDateOfNDS(ref DateTimeResult result, ref DateTimeRawInfo raw) - { - if (result.Month == -1) - { - // Should have a month suffix - result.SetBadDateTimeFailure(); - return false; - } - if (result.Year != -1) - { - // Already has a year suffix - result.SetBadDateTimeFailure(); - return false; - } - if (!TryAdjustYear(ref result, raw.GetNumber(0), out result.Year)) - { - // the year value is out of range - result.SetBadDateTimeFailure(); - return false; - } - result.Day = 1; - return true; - } - - private static bool GetDateOfNNDS(ref DateTimeResult result, ref DateTimeRawInfo raw, DateTimeFormatInfo dtfi) - { - // For partial CJK Dates, the only valid formats are with a specified year, followed by two numbers, which - // will be the Month and Day, and with a specified Month, when the numbers are either the year and day or - // day and year, depending on the short date pattern. - - if ((result.flags & ParseFlags.HaveYear) != 0) - { - if (((result.flags & ParseFlags.HaveMonth) == 0) && ((result.flags & ParseFlags.HaveDay) == 0)) - { - if (TryAdjustYear(ref result, raw.year, out result.Year) && SetDateYMD(ref result, result.Year, raw.GetNumber(0), raw.GetNumber(1))) - { - return true; - } - } - } - else if ((result.flags & ParseFlags.HaveMonth) != 0) - { - if (((result.flags & ParseFlags.HaveYear) == 0) && ((result.flags & ParseFlags.HaveDay) == 0)) - { - int order; - if (!GetYearMonthDayOrder(dtfi.ShortDatePattern, out order)) - { - result.SetFailure(ParseFailureKind.FormatWithParameter, nameof(SR.Format_BadDatePattern), dtfi.ShortDatePattern); - return false; - } - int year; - if (order == ORDER_YMD) - { - if (TryAdjustYear(ref result, raw.GetNumber(0), out year) && SetDateYMD(ref result, year, result.Month, raw.GetNumber(1))) - { - return true; - } - } - else - { - if (TryAdjustYear(ref result, raw.GetNumber(1), out year) && SetDateYMD(ref result, year, result.Month, raw.GetNumber(0))) - { - return true; - } - } - } - } - result.SetBadDateTimeFailure(); - return false; - } - - // - // A date suffix is found, use this method to put the number into the result. - // - private static bool ProcessDateTimeSuffix(ref DateTimeResult result, ref DateTimeRawInfo raw, ref DateTimeToken dtok) - { - switch (dtok.suffix) - { - case TokenType.SEP_YearSuff: - if ((result.flags & ParseFlags.HaveYear) != 0) - { - return false; - } - result.flags |= ParseFlags.HaveYear; - result.Year = raw.year = dtok.num; - break; - case TokenType.SEP_MonthSuff: - if ((result.flags & ParseFlags.HaveMonth) != 0) - { - return false; - } - result.flags |= ParseFlags.HaveMonth; - result.Month = raw.month = dtok.num; - break; - case TokenType.SEP_DaySuff: - if ((result.flags & ParseFlags.HaveDay) != 0) - { - return false; - } - result.flags |= ParseFlags.HaveDay; - result.Day = dtok.num; - break; - case TokenType.SEP_HourSuff: - if ((result.flags & ParseFlags.HaveHour) != 0) - { - return false; - } - result.flags |= ParseFlags.HaveHour; - result.Hour = dtok.num; - break; - case TokenType.SEP_MinuteSuff: - if ((result.flags & ParseFlags.HaveMinute) != 0) - { - return false; - } - result.flags |= ParseFlags.HaveMinute; - result.Minute = dtok.num; - break; - case TokenType.SEP_SecondSuff: - if ((result.flags & ParseFlags.HaveSecond) != 0) - { - return false; - } - result.flags |= ParseFlags.HaveSecond; - result.Second = dtok.num; - break; - } - return true; - } - - //////////////////////////////////////////////////////////////////////// - // - // Actions: - // This is used by DateTime.Parse(). - // Process the terminal state for the Hebrew calendar parsing. - // - //////////////////////////////////////////////////////////////////////// - - internal static bool ProcessHebrewTerminalState(DS dps, ref DateTimeResult result, ref DateTimeStyles styles, ref DateTimeRawInfo raw, DateTimeFormatInfo dtfi) - { - // The following are accepted terminal state for Hebrew date. - switch (dps) - { - case DS.DX_MNN: - // Deal with the default long/short date format when the year number is ambigous (i.e. year < 100). - raw.year = raw.GetNumber(1); - if (!dtfi.YearMonthAdjustment(ref raw.year, ref raw.month, true)) - { - result.SetFailure(ParseFailureKind.FormatBadDateTimeCalendar, nameof(SR.Format_BadDateTimeCalendar)); - return false; - } - if (!GetDayOfMNN(ref result, ref raw, dtfi)) - { - return false; - } - break; - case DS.DX_YMN: - // Deal with the default long/short date format when the year number is NOT ambigous (i.e. year >= 100). - if (!dtfi.YearMonthAdjustment(ref raw.year, ref raw.month, true)) - { - result.SetFailure(ParseFailureKind.FormatBadDateTimeCalendar, nameof(SR.Format_BadDateTimeCalendar)); - return false; - } - if (!GetDayOfYMN(ref result, ref raw)) - { - return false; - } - break; - case DS.DX_NNY: - // 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. so we do the reverse when parsing. - if (raw.year < 1000) - { - raw.year += 5000; - } - if (!GetDayOfNNY(ref result, ref raw, dtfi)) - { - return false; - } - if (!dtfi.YearMonthAdjustment(ref result.Year, ref raw.month, true)) - { - result.SetFailure(ParseFailureKind.FormatBadDateTimeCalendar, nameof(SR.Format_BadDateTimeCalendar)); - return false; - } - break; - case DS.DX_NM: - case DS.DX_MN: - // Deal with Month/Day pattern. - GetDefaultYear(ref result, ref styles); - if (!dtfi.YearMonthAdjustment(ref result.Year, ref raw.month, true)) - { - result.SetFailure(ParseFailureKind.FormatBadDateTimeCalendar, nameof(SR.Format_BadDateTimeCalendar)); - return false; - } - if (!GetHebrewDayOfNM(ref result, ref raw, dtfi)) - { - return false; - } - break; - case DS.DX_YM: - // Deal with Year/Month pattern. - if (!dtfi.YearMonthAdjustment(ref raw.year, ref raw.month, true)) - { - result.SetFailure(ParseFailureKind.FormatBadDateTimeCalendar, nameof(SR.Format_BadDateTimeCalendar)); - return false; - } - if (!GetDayOfYM(ref result, ref raw)) - { - return false; - } - break; - case DS.TX_N: - // Deal hour + AM/PM - if (!GetTimeOfN(ref result, ref raw)) - { - return false; - } - break; - case DS.TX_NN: - if (!GetTimeOfNN(ref result, ref raw)) - { - return false; - } - break; - case DS.TX_NNN: - if (!GetTimeOfNNN(ref result, ref raw)) - { - return false; - } - break; - default: - result.SetBadDateTimeFailure(); - return false; - } - if (dps > DS.ERROR) - { - // - // We have reached a terminal state. Reset the raw num count. - // - raw.numCount = 0; - } - return true; - } - - // - // A terminal state has been reached, call the appropriate function to fill in the parsing result. - // Return true if the state is a terminal state. - // - internal static bool ProcessTerminalState(DS dps, ref __DTString str, ref DateTimeResult result, ref DateTimeStyles styles, ref DateTimeRawInfo raw, DateTimeFormatInfo dtfi) - { - bool passed = true; - switch (dps) - { - case DS.DX_NN: - passed = GetDayOfNN(ref result, ref styles, ref raw, dtfi); - break; - case DS.DX_NNN: - passed = GetDayOfNNN(ref result, ref raw, dtfi); - break; - case DS.DX_MN: - passed = GetDayOfMN(ref result, ref styles, ref raw, dtfi); - break; - case DS.DX_NM: - passed = GetDayOfNM(ref result, ref styles, ref raw, dtfi); - break; - case DS.DX_MNN: - passed = GetDayOfMNN(ref result, ref raw, dtfi); - break; - case DS.DX_DS: - // The result has got the correct value. No need to process. - passed = true; - break; - case DS.DX_YNN: - passed = GetDayOfYNN(ref result, ref raw, dtfi); - break; - case DS.DX_NNY: - passed = GetDayOfNNY(ref result, ref raw, dtfi); - break; - case DS.DX_YMN: - passed = GetDayOfYMN(ref result, ref raw); - break; - case DS.DX_YN: - passed = GetDayOfYN(ref result, ref raw); - break; - case DS.DX_YM: - passed = GetDayOfYM(ref result, ref raw); - break; - case DS.TX_N: - passed = GetTimeOfN(ref result, ref raw); - break; - case DS.TX_NN: - passed = GetTimeOfNN(ref result, ref raw); - break; - case DS.TX_NNN: - passed = GetTimeOfNNN(ref result, ref raw); - break; - case DS.TX_TS: - // The result has got the correct value. Nothing to do. - passed = true; - break; - case DS.DX_DSN: - passed = GetDateOfDSN(ref result, ref raw); - break; - case DS.DX_NDS: - passed = GetDateOfNDS(ref result, ref raw); - break; - case DS.DX_NNDS: - passed = GetDateOfNNDS(ref result, ref raw, dtfi); - break; - } - - PTSTraceExit(dps, passed); - if (!passed) - { - return false; - } - - if (dps > DS.ERROR) - { - // - // We have reached a terminal state. Reset the raw num count. - // - raw.numCount = 0; - } - return true; - } - - internal static DateTime Parse(ReadOnlySpan<char> s, DateTimeFormatInfo dtfi, DateTimeStyles styles) - { - DateTimeResult result = default; // The buffer to store the parsing result. - result.Init(s); - if (TryParse(s, dtfi, styles, ref result)) - { - return result.parsedDate; - } - else - { - throw GetDateTimeParseException(ref result); - } - } - - internal static DateTime Parse(ReadOnlySpan<char> s, DateTimeFormatInfo dtfi, DateTimeStyles styles, out TimeSpan offset) - { - DateTimeResult result = default; // The buffer to store the parsing result. - result.Init(s); - result.flags |= ParseFlags.CaptureOffset; - if (TryParse(s, dtfi, styles, ref result)) - { - offset = result.timeZoneOffset; - return result.parsedDate; - } - else - { - throw GetDateTimeParseException(ref result); - } - } - - internal static bool TryParse(ReadOnlySpan<char> s, DateTimeFormatInfo dtfi, DateTimeStyles styles, out DateTime result) - { - DateTimeResult resultData = default; // The buffer to store the parsing result. - resultData.Init(s); - - if (TryParse(s, dtfi, styles, ref resultData)) - { - result = resultData.parsedDate; - return true; - } - - result = DateTime.MinValue; - return false; - } - - internal static bool TryParse(ReadOnlySpan<char> s, DateTimeFormatInfo dtfi, DateTimeStyles styles, out DateTime result, out TimeSpan offset) - { - DateTimeResult parseResult = default; // The buffer to store the parsing result. - parseResult.Init(s); - parseResult.flags |= ParseFlags.CaptureOffset; - - if (TryParse(s, dtfi, styles, ref parseResult)) - { - result = parseResult.parsedDate; - offset = parseResult.timeZoneOffset; - return true; - } - - result = DateTime.MinValue; - offset = TimeSpan.Zero; - return false; - } - - // - // This is the real method to do the parsing work. - // - internal static bool TryParse(ReadOnlySpan<char> s, DateTimeFormatInfo dtfi, DateTimeStyles styles, ref DateTimeResult result) - { - if (s.Length == 0) - { - result.SetFailure(ParseFailureKind.FormatWithParameter, nameof(SR.Format_BadDateTime)); - return false; - } - - Debug.Assert(dtfi != null, "dtfi == null"); - -#if _LOGGING - DTFITrace(dtfi); -#endif - - DateTime time; - // - // First try the predefined format. - // - - DS dps = DS.BEGIN; // Date Parsing State. - bool reachTerminalState = false; - - DateTimeToken dtok = default; // The buffer to store the parsing token. - dtok.suffix = TokenType.SEP_Unk; - DateTimeRawInfo raw = default; // The buffer to store temporary parsing information. - unsafe - { - int* numberPointer = stackalloc int[3]; - raw.Init(numberPointer); - } - raw.hasSameDateAndTimeSeparators = dtfi.DateSeparator.Equals(dtfi.TimeSeparator, StringComparison.Ordinal); - - result.calendar = dtfi.Calendar; - result.era = Calendar.CurrentEra; - - // - // The string to be parsed. Use a __DTString wrapper so that we can trace the index which - // indicates the begining of next token. - // - __DTString str = new __DTString(s, dtfi); - - str.GetNext(); - - // - // The following loop will break out when we reach the end of the str. - // - do - { - // - // Call the lexer to get the next token. - // - // If we find a era in Lex(), the era value will be in raw.era. - if (!Lex(dps, ref str, ref dtok, ref raw, ref result, ref dtfi, styles)) - { - TPTraceExit("0000", dps); - return false; - } - - // - // If the token is not unknown, process it. - // Otherwise, just discard it. - // - if (dtok.dtt != DTT.Unk) - { - // - // Check if we got any CJK Date/Time suffix. - // Since the Date/Time suffix tells us the number belongs to year/month/day/hour/minute/second, - // store the number in the appropriate field in the result. - // - if (dtok.suffix != TokenType.SEP_Unk) - { - if (!ProcessDateTimeSuffix(ref result, ref raw, ref dtok)) - { - result.SetBadDateTimeFailure(); - TPTraceExit("0010", dps); - return false; - } - - dtok.suffix = TokenType.SEP_Unk; // Reset suffix to SEP_Unk; - } - - if (dtok.dtt == DTT.NumLocalTimeMark) - { - if (dps == DS.D_YNd || dps == DS.D_YN) - { - // Consider this as ISO 8601 format: - // "yyyy-MM-dd'T'HH:mm:ss" 1999-10-31T02:00:00 - TPTraceExit("0020", dps); - return ParseISO8601(ref raw, ref str, styles, ref result); - } - else - { - result.SetBadDateTimeFailure(); - TPTraceExit("0030", dps); - return false; - } - } - - if (raw.hasSameDateAndTimeSeparators) - { - if (dtok.dtt == DTT.YearEnd || dtok.dtt == DTT.YearSpace || dtok.dtt == DTT.YearDateSep) - { - // When time and date separators are same and we are hitting a year number while the first parsed part of the string was recognized - // as part of time (and not a date) DS.T_Nt, DS.T_NNt then change the state to be a date so we try to parse it as a date instead - if (dps == DS.T_Nt) - { - dps = DS.D_Nd; - } - if (dps == DS.T_NNt) - { - dps = DS.D_NNd; - } - } - - bool atEnd = str.AtEnd(); - if (dateParsingStates[(int)dps][(int)dtok.dtt] == DS.ERROR || atEnd) - { - switch (dtok.dtt) - { - // we have the case of Serbia have dates in forms 'd.M.yyyy.' so we can expect '.' after the date parts. - // changing the token to end with space instead of Date Separator will avoid failing the parsing. - - case DTT.YearDateSep: dtok.dtt = atEnd ? DTT.YearEnd : DTT.YearSpace; break; - case DTT.NumDatesep: dtok.dtt = atEnd ? DTT.NumEnd : DTT.NumSpace; break; - case DTT.NumTimesep: dtok.dtt = atEnd ? DTT.NumEnd : DTT.NumSpace; break; - case DTT.MonthDatesep: dtok.dtt = atEnd ? DTT.MonthEnd : DTT.MonthSpace; break; - } - } - } - - // - // Advance to the next state, and continue - // - dps = dateParsingStates[(int)dps][(int)dtok.dtt]; - - if (dps == DS.ERROR) - { - result.SetBadDateTimeFailure(); - TPTraceExit("0040 (invalid state transition)", dps); - return false; - } - else if (dps > DS.ERROR) - { - if ((dtfi.FormatFlags & DateTimeFormatFlags.UseHebrewRule) != 0) - { - if (!ProcessHebrewTerminalState(dps, ref result, ref styles, ref raw, dtfi)) - { - TPTraceExit("0050 (ProcessHebrewTerminalState)", dps); - return false; - } - } - else - { - if (!ProcessTerminalState(dps, ref str, ref result, ref styles, ref raw, dtfi)) - { - TPTraceExit("0060 (ProcessTerminalState)", dps); - return false; - } - } - reachTerminalState = true; - - // - // If we have reached a terminal state, start over from DS.BEGIN again. - // For example, when we parsed "1999-12-23 13:30", we will reach a terminal state at "1999-12-23", - // and we start over so we can continue to parse "12:30". - // - dps = DS.BEGIN; - } - } - } while (dtok.dtt != DTT.End && dtok.dtt != DTT.NumEnd && dtok.dtt != DTT.MonthEnd); - - if (!reachTerminalState) - { - result.SetBadDateTimeFailure(); - TPTraceExit("0070 (did not reach terminal state)", dps); - return false; - } - - AdjustTimeMark(dtfi, ref raw); - if (!AdjustHour(ref result.Hour, raw.timeMark)) - { - result.SetBadDateTimeFailure(); - TPTraceExit("0080 (AdjustHour)", dps); - return false; - } - - // Check if the parsed string only contains hour/minute/second values. - bool bTimeOnly = (result.Year == -1 && result.Month == -1 && result.Day == -1); - - // - // Check if any year/month/day is missing in the parsing string. - // If yes, get the default value from today's date. - // - if (!CheckDefaultDateTime(ref result, ref result.calendar, styles)) - { - TPTraceExit("0090 (failed to fill in missing year/month/day defaults)", dps); - return false; - } - - if (!result.calendar.TryToDateTime(result.Year, result.Month, result.Day, - result.Hour, result.Minute, result.Second, 0, result.era, out time)) - { - result.SetFailure(ParseFailureKind.FormatBadDateTimeCalendar, nameof(SR.Format_BadDateTimeCalendar)); - TPTraceExit("0100 (result.calendar.TryToDateTime)", dps); - return false; - } - - if (raw.fraction > 0) - { - if (!time.TryAddTicks((long)Math.Round(raw.fraction * Calendar.TicksPerSecond), out time)) - { - result.SetBadDateTimeFailure(); - TPTraceExit("0100 (time.TryAddTicks)", dps); - return false; - } - } - - // - // We have to check day of week before we adjust to the time zone. - // Otherwise, the value of day of week may change after adjusting to the time zone. - // - if (raw.dayOfWeek != -1) - { - // - // Check if day of week is correct. - // - if (raw.dayOfWeek != (int)result.calendar.GetDayOfWeek(time)) - { - result.SetFailure(ParseFailureKind.FormatWithOriginalDateTime, nameof(SR.Format_BadDayOfWeek)); - TPTraceExit("0110 (dayOfWeek check)", dps); - return false; - } - } - - result.parsedDate = time; - - if (!DetermineTimeZoneAdjustments(ref result, styles, bTimeOnly)) - { - TPTraceExit("0120 (DetermineTimeZoneAdjustments)", dps); - return false; - } - TPTraceExit("0130 (success)", dps); - return true; - } - - // Handles time zone adjustments and sets DateTimeKind values as required by the styles - private static bool DetermineTimeZoneAdjustments(ref DateTimeResult result, DateTimeStyles styles, bool bTimeOnly) - { - if ((result.flags & ParseFlags.CaptureOffset) != 0) - { - // This is a DateTimeOffset parse, so the offset will actually be captured directly, and - // no adjustment is required in most cases - return DateTimeOffsetTimeZonePostProcessing(ref result, styles); - } - else - { - long offsetTicks = result.timeZoneOffset.Ticks; - - // the DateTime offset must be within +- 14:00 hours. - if (offsetTicks < DateTimeOffset.MinOffset || offsetTicks > DateTimeOffset.MaxOffset) - { - result.SetFailure(ParseFailureKind.FormatWithOriginalDateTime, nameof(SR.Format_OffsetOutOfRange)); - return false; - } - } - - // The flags AssumeUniveral and AssumeLocal only apply when the input does not have a time zone - if ((result.flags & ParseFlags.TimeZoneUsed) == 0) - { - // If AssumeLocal or AssumeLocal is used, there will always be a kind specified. As in the - // case when a time zone is present, it will default to being local unless AdjustToUniversal - // is present. These comparisons determine whether setting the kind is sufficient, or if a - // time zone adjustment is required. For consistentcy with the rest of parsing, it is desirable - // to fall through to the Adjust methods below, so that there is consist handling of boundary - // cases like wrapping around on time-only dates and temporarily allowing an adjusted date - // to exceed DateTime.MaxValue - if ((styles & DateTimeStyles.AssumeLocal) != 0) - { - if ((styles & DateTimeStyles.AdjustToUniversal) != 0) - { - result.flags |= ParseFlags.TimeZoneUsed; - result.timeZoneOffset = TimeZoneInfo.GetLocalUtcOffset(result.parsedDate, TimeZoneInfoOptions.NoThrowOnInvalidTime); - } - else - { - result.parsedDate = DateTime.SpecifyKind(result.parsedDate, DateTimeKind.Local); - return true; - } - } - else if ((styles & DateTimeStyles.AssumeUniversal) != 0) - { - if ((styles & DateTimeStyles.AdjustToUniversal) != 0) - { - result.parsedDate = DateTime.SpecifyKind(result.parsedDate, DateTimeKind.Utc); - return true; - } - else - { - result.flags |= ParseFlags.TimeZoneUsed; - result.timeZoneOffset = TimeSpan.Zero; - } - } - else - { - // No time zone and no Assume flags, so DateTimeKind.Unspecified is fine - Debug.Assert(result.parsedDate.Kind == DateTimeKind.Unspecified, "result.parsedDate.Kind == DateTimeKind.Unspecified"); - return true; - } - } - - if (((styles & DateTimeStyles.RoundtripKind) != 0) && ((result.flags & ParseFlags.TimeZoneUtc) != 0)) - { - result.parsedDate = DateTime.SpecifyKind(result.parsedDate, DateTimeKind.Utc); - return true; - } - - if ((styles & DateTimeStyles.AdjustToUniversal) != 0) - { - return AdjustTimeZoneToUniversal(ref result); - } - return AdjustTimeZoneToLocal(ref result, bTimeOnly); - } - - // Apply validation and adjustments specific to DateTimeOffset - private static bool DateTimeOffsetTimeZonePostProcessing(ref DateTimeResult result, DateTimeStyles styles) - { - // For DateTimeOffset, default to the Utc or Local offset when an offset was not specified by - // the input string. - if ((result.flags & ParseFlags.TimeZoneUsed) == 0) - { - if ((styles & DateTimeStyles.AssumeUniversal) != 0) - { - // AssumeUniversal causes the offset to default to zero (0) - result.timeZoneOffset = TimeSpan.Zero; - } - else - { - // AssumeLocal causes the offset to default to Local. This flag is on by default for DateTimeOffset. - result.timeZoneOffset = TimeZoneInfo.GetLocalUtcOffset(result.parsedDate, TimeZoneInfoOptions.NoThrowOnInvalidTime); - } - } - - long offsetTicks = result.timeZoneOffset.Ticks; - - // there should be no overflow, because the offset can be no more than -+100 hours and the date already - // fits within a DateTime. - long utcTicks = result.parsedDate.Ticks - offsetTicks; - - // For DateTimeOffset, both the parsed time and the corresponding UTC value must be within the boundaries - // of a DateTime instance. - if (utcTicks < DateTime.MinTicks || utcTicks > DateTime.MaxTicks) - { - result.SetFailure(ParseFailureKind.FormatWithOriginalDateTime, nameof(SR.Format_UTCOutOfRange)); - return false; - } - - // the offset must be within +- 14:00 hours. - if (offsetTicks < DateTimeOffset.MinOffset || offsetTicks > DateTimeOffset.MaxOffset) - { - result.SetFailure(ParseFailureKind.FormatWithOriginalDateTime, nameof(SR.Format_OffsetOutOfRange)); - return false; - } - - // DateTimeOffset should still honor the AdjustToUniversal flag for consistency with DateTime. It means you - // want to return an adjusted UTC value, so store the utcTicks in the DateTime and set the offset to zero - if ((styles & DateTimeStyles.AdjustToUniversal) != 0) - { - if (((result.flags & ParseFlags.TimeZoneUsed) == 0) && ((styles & DateTimeStyles.AssumeUniversal) == 0)) - { - // Handle the special case where the timeZoneOffset was defaulted to Local - bool toUtcResult = AdjustTimeZoneToUniversal(ref result); - result.timeZoneOffset = TimeSpan.Zero; - return toUtcResult; - } - - // The constructor should always succeed because of the range check earlier in the function - // Although it is UTC, internally DateTimeOffset does not use this flag - result.parsedDate = new DateTime(utcTicks, DateTimeKind.Utc); - result.timeZoneOffset = TimeSpan.Zero; - } - - return true; - } - - // - // Adjust the specified time to universal time based on the supplied timezone. - // E.g. when parsing "2001/06/08 14:00-07:00", - // the time is 2001/06/08 14:00, and timeZoneOffset = -07:00. - // The result will be "2001/06/08 21:00" - // - private static bool AdjustTimeZoneToUniversal(ref DateTimeResult result) - { - long resultTicks = result.parsedDate.Ticks; - resultTicks -= result.timeZoneOffset.Ticks; - if (resultTicks < 0) - { - resultTicks += Calendar.TicksPerDay; - } - - if (resultTicks < DateTime.MinTicks || resultTicks > DateTime.MaxTicks) - { - result.SetFailure(ParseFailureKind.FormatWithOriginalDateTime, nameof(SR.Format_DateOutOfRange)); - return false; - } - result.parsedDate = new DateTime(resultTicks, DateTimeKind.Utc); - return true; - } - - // - // Adjust the specified time to universal time based on the supplied timezone, - // and then convert to local time. - // E.g. when parsing "2001/06/08 14:00-04:00", and local timezone is GMT-7. - // the time is 2001/06/08 14:00, and timeZoneOffset = -05:00. - // The result will be "2001/06/08 11:00" - // - private static bool AdjustTimeZoneToLocal(ref DateTimeResult result, bool bTimeOnly) - { - long resultTicks = result.parsedDate.Ticks; - // Convert to local ticks - TimeZoneInfo tz = TimeZoneInfo.Local; - bool isAmbiguousLocalDst = false; - if (resultTicks < Calendar.TicksPerDay) - { - // - // This is time of day. - // - - // Adjust timezone. - resultTicks -= result.timeZoneOffset.Ticks; - // If the time is time of day, use the current timezone offset. - resultTicks += tz.GetUtcOffset(bTimeOnly ? DateTime.Now : result.parsedDate, TimeZoneInfoOptions.NoThrowOnInvalidTime).Ticks; - - if (resultTicks < 0) - { - resultTicks += Calendar.TicksPerDay; - } - } - else - { - // Adjust timezone to GMT. - resultTicks -= result.timeZoneOffset.Ticks; - if (resultTicks < DateTime.MinTicks || resultTicks > DateTime.MaxTicks) - { - // If the result ticks is greater than DateTime.MaxValue, we can not create a DateTime from this ticks. - // In this case, keep using the old code. - resultTicks += tz.GetUtcOffset(result.parsedDate, TimeZoneInfoOptions.NoThrowOnInvalidTime).Ticks; - } - else - { - // Convert the GMT time to local time. - DateTime utcDt = new DateTime(resultTicks, DateTimeKind.Utc); - bool isDaylightSavings = false; - resultTicks += TimeZoneInfo.GetUtcOffsetFromUtc(utcDt, TimeZoneInfo.Local, out isDaylightSavings, out isAmbiguousLocalDst).Ticks; - } - } - if (resultTicks < DateTime.MinTicks || resultTicks > DateTime.MaxTicks) - { - result.parsedDate = DateTime.MinValue; - result.SetFailure(ParseFailureKind.FormatWithOriginalDateTime, nameof(SR.Format_DateOutOfRange)); - return false; - } - result.parsedDate = new DateTime(resultTicks, DateTimeKind.Local, isAmbiguousLocalDst); - return true; - } - - // - // Parse the ISO8601 format string found during Parse(); - // - // - private static bool ParseISO8601(ref DateTimeRawInfo raw, ref __DTString str, DateTimeStyles styles, ref DateTimeResult result) - { - if (raw.year < 0 || raw.GetNumber(0) < 0 || raw.GetNumber(1) < 0) - { - } - str.Index--; - int hour, minute; - int second = 0; - double partSecond = 0; - - str.SkipWhiteSpaces(); - if (!ParseDigits(ref str, 2, out hour)) - { - result.SetBadDateTimeFailure(); - return false; - } - str.SkipWhiteSpaces(); - if (!str.Match(':')) - { - result.SetBadDateTimeFailure(); - return false; - } - str.SkipWhiteSpaces(); - if (!ParseDigits(ref str, 2, out minute)) - { - result.SetBadDateTimeFailure(); - return false; - } - str.SkipWhiteSpaces(); - if (str.Match(':')) - { - str.SkipWhiteSpaces(); - if (!ParseDigits(ref str, 2, out second)) - { - result.SetBadDateTimeFailure(); - return false; - } - if (str.Match('.')) - { - if (!ParseFraction(ref str, out partSecond)) - { - result.SetBadDateTimeFailure(); - return false; - } - str.Index--; - } - str.SkipWhiteSpaces(); - } - if (str.GetNext()) - { - char ch = str.GetChar(); - if (ch == '+' || ch == '-') - { - result.flags |= ParseFlags.TimeZoneUsed; - if (!ParseTimeZone(ref str, ref result.timeZoneOffset)) - { - result.SetBadDateTimeFailure(); - return false; - } - } - else if (ch == 'Z' || ch == 'z') - { - result.flags |= ParseFlags.TimeZoneUsed; - result.timeZoneOffset = TimeSpan.Zero; - result.flags |= ParseFlags.TimeZoneUtc; - } - else - { - str.Index--; - } - str.SkipWhiteSpaces(); - if (str.Match('#')) - { - if (!VerifyValidPunctuation(ref str)) - { - result.SetBadDateTimeFailure(); - return false; - } - str.SkipWhiteSpaces(); - } - if (str.Match('\0')) - { - if (!VerifyValidPunctuation(ref str)) - { - result.SetBadDateTimeFailure(); - return false; - } - } - if (str.GetNext()) - { - // If this is true, there were non-white space characters remaining in the DateTime - result.SetBadDateTimeFailure(); - return false; - } - } - - DateTime time; - Calendar calendar = GregorianCalendar.GetDefaultInstance(); - if (!calendar.TryToDateTime(raw.year, raw.GetNumber(0), raw.GetNumber(1), - hour, minute, second, 0, result.era, out time)) - { - result.SetFailure(ParseFailureKind.FormatBadDateTimeCalendar, nameof(SR.Format_BadDateTimeCalendar)); - return false; - } - - if (!time.TryAddTicks((long)Math.Round(partSecond * Calendar.TicksPerSecond), out time)) - { - result.SetBadDateTimeFailure(); - return false; - } - - result.parsedDate = time; - return DetermineTimeZoneAdjustments(ref result, styles, false); - } - - //////////////////////////////////////////////////////////////////////// - // - // Actions: - // Parse the current word as a Hebrew number. - // This is used by DateTime.ParseExact(). - // - //////////////////////////////////////////////////////////////////////// - - internal static bool MatchHebrewDigits(ref __DTString str, int digitLen, out int number) - { - number = 0; - - // Create a context object so that we can parse the Hebrew number text character by character. - HebrewNumberParsingContext context = new HebrewNumberParsingContext(0); - - // Set this to ContinueParsing so that we will run the following while loop in the first time. - HebrewNumberParsingState state = HebrewNumberParsingState.ContinueParsing; - - while (state == HebrewNumberParsingState.ContinueParsing && str.GetNext()) - { - state = HebrewNumber.ParseByChar(str.GetChar(), ref context); - } - - if (state == HebrewNumberParsingState.FoundEndOfHebrewNumber) - { - // If we have reached a terminal state, update the result and returns. - number = context.result; - return true; - } - - // If we run out of the character before reaching FoundEndOfHebrewNumber, or - // the state is InvalidHebrewNumber or ContinueParsing, we fail to match a Hebrew number. - // Return an error. - return false; - } - - /*=================================ParseDigits================================== - **Action: Parse the number string in __DTString that are formatted using - ** the following patterns: - ** "0", "00", and "000..0" - **Returns: the integer value - **Arguments: str: a __DTString. The parsing will start from the - ** next character after str.Index. - **Exceptions: FormatException if error in parsing number. - ==============================================================================*/ - - internal static bool ParseDigits(ref __DTString str, int digitLen, out int result) - { - if (digitLen == 1) - { - // 1 really means 1 or 2 for this call - return ParseDigits(ref str, 1, 2, out result); - } - else - { - return ParseDigits(ref str, digitLen, digitLen, out result); - } - } - - internal static bool ParseDigits(ref __DTString str, int minDigitLen, int maxDigitLen, out int result) - { - Debug.Assert(minDigitLen > 0, "minDigitLen > 0"); - Debug.Assert(maxDigitLen < 9, "maxDigitLen < 9"); - Debug.Assert(minDigitLen <= maxDigitLen, "minDigitLen <= maxDigitLen"); - int localResult = 0; - int startingIndex = str.Index; - int tokenLength = 0; - while (tokenLength < maxDigitLen) - { - if (!str.GetNextDigit()) - { - str.Index--; - break; - } - localResult = localResult * 10 + str.GetDigit(); - tokenLength++; - } - result = localResult; - if (tokenLength < minDigitLen) - { - str.Index = startingIndex; - return false; - } - return true; - } - - /*=================================ParseFractionExact================================== - **Action: Parse the number string in __DTString that are formatted using - ** the following patterns: - ** "0", "00", and "000..0" - **Returns: the fraction value - **Arguments: str: a __DTString. The parsing will start from the - ** next character after str.Index. - **Exceptions: FormatException if error in parsing number. - ==============================================================================*/ - - private static bool ParseFractionExact(ref __DTString str, int maxDigitLen, ref double result) - { - if (!str.GetNextDigit()) - { - str.Index--; - return false; - } - result = str.GetDigit(); - - int digitLen = 1; - for (; digitLen < maxDigitLen; digitLen++) - { - if (!str.GetNextDigit()) - { - str.Index--; - break; - } - result = result * 10 + str.GetDigit(); - } - - result /= TimeSpanParse.Pow10(digitLen); - return digitLen == maxDigitLen; - } - - /*=================================ParseSign================================== - **Action: Parse a positive or a negative sign. - **Returns: true if postive sign. flase if negative sign. - **Arguments: str: a __DTString. The parsing will start from the - ** next character after str.Index. - **Exceptions: FormatException if end of string is encountered or a sign - ** symbol is not found. - ==============================================================================*/ - - private static bool ParseSign(ref __DTString str, ref bool result) - { - if (!str.GetNext()) - { - // A sign symbol ('+' or '-') is expected. However, end of string is encountered. - return false; - } - char ch = str.GetChar(); - if (ch == '+') - { - result = true; - return true; - } - else if (ch == '-') - { - result = false; - return true; - } - // A sign symbol ('+' or '-') is expected. - return false; - } - - /*=================================ParseTimeZoneOffset================================== - **Action: Parse the string formatted using "z", "zz", "zzz" in DateTime.Format(). - **Returns: the TimeSpan for the parsed timezone offset. - **Arguments: str: a __DTString. The parsing will start from the - ** next character after str.Index. - ** len: the repeated number of the "z" - **Exceptions: FormatException if errors in parsing. - ==============================================================================*/ - - private static bool ParseTimeZoneOffset(ref __DTString str, int len, ref TimeSpan result) - { - bool isPositive = true; - int hourOffset; - int minuteOffset = 0; - - switch (len) - { - case 1: - case 2: - if (!ParseSign(ref str, ref isPositive)) - { - return false; - } - if (!ParseDigits(ref str, len, out hourOffset)) - { - return false; - } - break; - default: - if (!ParseSign(ref str, ref isPositive)) - { - return false; - } - - // Parsing 1 digit will actually parse 1 or 2. - if (!ParseDigits(ref str, 1, out hourOffset)) - { - return false; - } - // ':' is optional. - if (str.Match(":")) - { - // Found ':' - if (!ParseDigits(ref str, 2, out minuteOffset)) - { - return false; - } - } - else - { - // Since we can not match ':', put the char back. - str.Index--; - if (!ParseDigits(ref str, 2, out minuteOffset)) - { - return false; - } - } - break; - } - if (minuteOffset < 0 || minuteOffset >= 60) - { - return false; - } - - result = (new TimeSpan(hourOffset, minuteOffset, 0)); - if (!isPositive) - { - result = result.Negate(); - } - return true; - } - - /*=================================MatchAbbreviatedMonthName================================== - **Action: Parse the abbreviated month name from string starting at str.Index. - **Returns: A value from 1 to 12 for the first month to the twelfth month. - **Arguments: str: a __DTString. The parsing will start from the - ** next character after str.Index. - **Exceptions: FormatException if an abbreviated month name can not be found. - ==============================================================================*/ - - private static bool MatchAbbreviatedMonthName(ref __DTString str, DateTimeFormatInfo dtfi, ref int result) - { - int maxMatchStrLen = 0; - result = -1; - if (str.GetNext()) - { - // - // Scan the month names (note that some calendars has 13 months) and find - // the matching month name which has the max string length. - // We need to do this because some cultures (e.g. "cs-CZ") which have - // abbreviated month names with the same prefix. - // - int monthsInYear = (dtfi.GetMonthName(13).Length == 0 ? 12 : 13); - for (int i = 1; i <= monthsInYear; i++) - { - string searchStr = dtfi.GetAbbreviatedMonthName(i); - int matchStrLen = searchStr.Length; - if (dtfi.HasSpacesInMonthNames - ? str.MatchSpecifiedWords(searchStr, false, ref matchStrLen) - : str.MatchSpecifiedWord(searchStr)) - { - if (matchStrLen > maxMatchStrLen) - { - maxMatchStrLen = matchStrLen; - result = i; - } - } - } - - // Search genitive form. - if ((dtfi.FormatFlags & DateTimeFormatFlags.UseGenitiveMonth) != 0) - { - int tempResult = str.MatchLongestWords(dtfi.AbbreviatedMonthGenitiveNames, ref maxMatchStrLen); - - // We found a longer match in the genitive month name. Use this as the result. - // tempResult + 1 should be the month value. - if (tempResult >= 0) - { - result = tempResult + 1; - } - } - - // Search leap year form. - if ((dtfi.FormatFlags & DateTimeFormatFlags.UseLeapYearMonth) != 0) - { - int tempResult = str.MatchLongestWords(dtfi.InternalGetLeapYearMonthNames(), ref maxMatchStrLen); - // We found a longer match in the leap year month name. Use this as the result. - // The result from MatchLongestWords is 0 ~ length of word array. - // So we increment the result by one to become the month value. - if (tempResult >= 0) - { - result = tempResult + 1; - } - } - } - if (result > 0) - { - str.Index += (maxMatchStrLen - 1); - return true; - } - return false; - } - - /*=================================MatchMonthName================================== - **Action: Parse the month name from string starting at str.Index. - **Returns: A value from 1 to 12 indicating the first month to the twelfth month. - **Arguments: str: a __DTString. The parsing will start from the - ** next character after str.Index. - **Exceptions: FormatException if a month name can not be found. - ==============================================================================*/ - - private static bool MatchMonthName(ref __DTString str, DateTimeFormatInfo dtfi, ref int result) - { - int maxMatchStrLen = 0; - result = -1; - if (str.GetNext()) - { - // - // Scan the month names (note that some calendars has 13 months) and find - // the matching month name which has the max string length. - // We need to do this because some cultures (e.g. "vi-VN") which have - // month names with the same prefix. - // - int monthsInYear = (dtfi.GetMonthName(13).Length == 0 ? 12 : 13); - for (int i = 1; i <= monthsInYear; i++) - { - string searchStr = dtfi.GetMonthName(i); - int matchStrLen = searchStr.Length; - if (dtfi.HasSpacesInMonthNames - ? str.MatchSpecifiedWords(searchStr, false, ref matchStrLen) - : str.MatchSpecifiedWord(searchStr)) - { - if (matchStrLen > maxMatchStrLen) - { - maxMatchStrLen = matchStrLen; - result = i; - } - } - } - - // Search genitive form. - if ((dtfi.FormatFlags & DateTimeFormatFlags.UseGenitiveMonth) != 0) - { - int tempResult = str.MatchLongestWords(dtfi.MonthGenitiveNames, ref maxMatchStrLen); - // We found a longer match in the genitive month name. Use this as the result. - // The result from MatchLongestWords is 0 ~ length of word array. - // So we increment the result by one to become the month value. - if (tempResult >= 0) - { - result = tempResult + 1; - } - } - - // Search leap year form. - if ((dtfi.FormatFlags & DateTimeFormatFlags.UseLeapYearMonth) != 0) - { - int tempResult = str.MatchLongestWords(dtfi.InternalGetLeapYearMonthNames(), ref maxMatchStrLen); - // We found a longer match in the leap year month name. Use this as the result. - // The result from MatchLongestWords is 0 ~ length of word array. - // So we increment the result by one to become the month value. - if (tempResult >= 0) - { - result = tempResult + 1; - } - } - } - - if (result > 0) - { - str.Index += (maxMatchStrLen - 1); - return true; - } - return false; - } - - /*=================================MatchAbbreviatedDayName================================== - **Action: Parse the abbreviated day of week name from string starting at str.Index. - **Returns: A value from 0 to 6 indicating Sunday to Saturday. - **Arguments: str: a __DTString. The parsing will start from the - ** next character after str.Index. - **Exceptions: FormatException if a abbreviated day of week name can not be found. - ==============================================================================*/ - - private static bool MatchAbbreviatedDayName(ref __DTString str, DateTimeFormatInfo dtfi, ref int result) - { - int maxMatchStrLen = 0; - result = -1; - if (str.GetNext()) - { - for (DayOfWeek i = DayOfWeek.Sunday; i <= DayOfWeek.Saturday; i++) - { - string searchStr = dtfi.GetAbbreviatedDayName(i); - int matchStrLen = searchStr.Length; - if (dtfi.HasSpacesInDayNames - ? str.MatchSpecifiedWords(searchStr, false, ref matchStrLen) - : str.MatchSpecifiedWord(searchStr)) - { - if (matchStrLen > maxMatchStrLen) - { - maxMatchStrLen = matchStrLen; - result = (int)i; - } - } - } - } - if (result >= 0) - { - str.Index += maxMatchStrLen - 1; - return true; - } - return false; - } - - /*=================================MatchDayName================================== - **Action: Parse the day of week name from string starting at str.Index. - **Returns: A value from 0 to 6 indicating Sunday to Saturday. - **Arguments: str: a __DTString. The parsing will start from the - ** next character after str.Index. - **Exceptions: FormatException if a day of week name can not be found. - ==============================================================================*/ - - private static bool MatchDayName(ref __DTString str, DateTimeFormatInfo dtfi, ref int result) - { - // Turkish (tr-TR) got day names with the same prefix. - int maxMatchStrLen = 0; - result = -1; - if (str.GetNext()) - { - for (DayOfWeek i = DayOfWeek.Sunday; i <= DayOfWeek.Saturday; i++) - { - string searchStr = dtfi.GetDayName(i); - int matchStrLen = searchStr.Length; - if (dtfi.HasSpacesInDayNames - ? str.MatchSpecifiedWords(searchStr, false, ref matchStrLen) - : str.MatchSpecifiedWord(searchStr)) - { - if (matchStrLen > maxMatchStrLen) - { - maxMatchStrLen = matchStrLen; - result = (int)i; - } - } - } - } - if (result >= 0) - { - str.Index += maxMatchStrLen - 1; - return true; - } - return false; - } - - /*=================================MatchEraName================================== - **Action: Parse era name from string starting at str.Index. - **Returns: An era value. - **Arguments: str: a __DTString. The parsing will start from the - ** next character after str.Index. - **Exceptions: FormatException if an era name can not be found. - ==============================================================================*/ - - private static bool MatchEraName(ref __DTString str, DateTimeFormatInfo dtfi, ref int result) - { - if (str.GetNext()) - { - int[] eras = dtfi.Calendar.Eras; - - if (eras != null) - { - for (int i = 0; i < eras.Length; i++) - { - string searchStr = dtfi.GetEraName(eras[i]); - if (str.MatchSpecifiedWord(searchStr)) - { - str.Index += (searchStr.Length - 1); - result = eras[i]; - return true; - } - searchStr = dtfi.GetAbbreviatedEraName(eras[i]); - if (str.MatchSpecifiedWord(searchStr)) - { - str.Index += (searchStr.Length - 1); - result = eras[i]; - return true; - } - } - } - } - return false; - } - - /*=================================MatchTimeMark================================== - **Action: Parse the time mark (AM/PM) from string starting at str.Index. - **Returns: TM_AM or TM_PM. - **Arguments: str: a __DTString. The parsing will start from the - ** next character after str.Index. - **Exceptions: FormatException if a time mark can not be found. - ==============================================================================*/ - - private static bool MatchTimeMark(ref __DTString str, DateTimeFormatInfo dtfi, ref TM result) - { - result = TM.NotSet; - // In some cultures have empty strings in AM/PM mark. E.g. af-ZA (0x0436), the AM mark is "", and PM mark is "nm". - if (dtfi.AMDesignator.Length == 0) - { - result = TM.AM; - } - if (dtfi.PMDesignator.Length == 0) - { - result = TM.PM; - } - - if (str.GetNext()) - { - string searchStr = dtfi.AMDesignator; - if (searchStr.Length > 0) - { - if (str.MatchSpecifiedWord(searchStr)) - { - // Found an AM timemark with length > 0. - str.Index += (searchStr.Length - 1); - result = TM.AM; - return true; - } - } - searchStr = dtfi.PMDesignator; - if (searchStr.Length > 0) - { - if (str.MatchSpecifiedWord(searchStr)) - { - // Found a PM timemark with length > 0. - str.Index += (searchStr.Length - 1); - result = TM.PM; - return true; - } - } - str.Index--; // Undo the GetNext call. - } - if (result != TM.NotSet) - { - // If one of the AM/PM marks is empty string, return the result. - return true; - } - return false; - } - - /*=================================MatchAbbreviatedTimeMark================================== - **Action: Parse the abbreviated time mark (AM/PM) from string starting at str.Index. - **Returns: TM_AM or TM_PM. - **Arguments: str: a __DTString. The parsing will start from the - ** next character after str.Index. - **Exceptions: FormatException if a abbreviated time mark can not be found. - ==============================================================================*/ - - private static bool MatchAbbreviatedTimeMark(ref __DTString str, DateTimeFormatInfo dtfi, ref TM result) - { - // NOTENOTE : the assumption here is that abbreviated time mark is the first - // character of the AM/PM designator. If this invariant changes, we have to - // change the code below. - if (str.GetNext()) - { - string amDesignator = dtfi.AMDesignator; - if (amDesignator.Length > 0 && str.GetChar() == amDesignator[0]) - { - result = TM.AM; - return true; - } - - string pmDesignator = dtfi.PMDesignator; - if (pmDesignator.Length > 0 && str.GetChar() == pmDesignator[0]) - { - result = TM.PM; - return true; - } - } - return false; - } - - /*=================================CheckNewValue================================== - **Action: Check if currentValue is initialized. If not, return the newValue. - ** If yes, check if the current value is equal to newValue. Return false - ** if they are not equal. This is used to check the case like "d" and "dd" are both - ** used to format a string. - **Returns: the correct value for currentValue. - **Arguments: - **Exceptions: - ==============================================================================*/ - - private static bool CheckNewValue(ref int currentValue, int newValue, char patternChar, ref DateTimeResult result) - { - if (currentValue == -1) - { - currentValue = newValue; - return true; - } - else - { - if (newValue != currentValue) - { - result.SetFailure(ParseFailureKind.FormatWithParameter, nameof(SR.Format_RepeatDateTimePattern), patternChar); - return false; - } - } - return true; - } - - private static DateTime GetDateTimeNow(ref DateTimeResult result, ref DateTimeStyles styles) - { - if ((result.flags & ParseFlags.CaptureOffset) != 0) - { - if ((result.flags & ParseFlags.TimeZoneUsed) != 0) - { - // use the supplied offset to calculate 'Now' - return new DateTime(DateTime.UtcNow.Ticks + result.timeZoneOffset.Ticks, DateTimeKind.Unspecified); - } - else if ((styles & DateTimeStyles.AssumeUniversal) != 0) - { - // assume the offset is Utc - return DateTime.UtcNow; - } - } - - // assume the offset is Local - return DateTime.Now; - } - - private static bool CheckDefaultDateTime(ref DateTimeResult result, ref Calendar cal, DateTimeStyles styles) - { - if ((result.flags & ParseFlags.CaptureOffset) != 0) - { - // DateTimeOffset.Parse should allow dates without a year, but only if there is also no time zone marker; - // e.g. "May 1 5pm" is OK, but "May 1 5pm -08:30" is not. This is somewhat pragmatic, since we would - // have to rearchitect parsing completely to allow this one case to correctly handle things like leap - // years and leap months. Is an extremely corner case, and DateTime is basically incorrect in that - // case today. - // - // values like "11:00Z" or "11:00 -3:00" are also acceptable - // - // if ((month or day is set) and (year is not set and time zone is set)) - // - if (((result.Month != -1) || (result.Day != -1)) - && ((result.Year == -1 || ((result.flags & ParseFlags.YearDefault) != 0)) && (result.flags & ParseFlags.TimeZoneUsed) != 0)) - { - result.SetFailure(ParseFailureKind.FormatWithOriginalDateTime, nameof(SR.Format_MissingIncompleteDate)); - return false; - } - } - - if ((result.Year == -1) || (result.Month == -1) || (result.Day == -1)) - { - /* - The following table describes the behaviors of getting the default value - when a certain year/month/day values are missing. - - An "X" means that the value exists. And "--" means that value is missing. - - Year Month Day => ResultYear ResultMonth ResultDay Note - - X X X Parsed year Parsed month Parsed day - X X -- Parsed Year Parsed month First day If we have year and month, assume the first day of that month. - X -- X Parsed year First month Parsed day If the month is missing, assume first month of that year. - X -- -- Parsed year First month First day If we have only the year, assume the first day of that year. - - -- X X CurrentYear Parsed month Parsed day If the year is missing, assume the current year. - -- X -- CurrentYear Parsed month First day If we have only a month value, assume the current year and current day. - -- -- X CurrentYear First month Parsed day If we have only a day value, assume current year and first month. - -- -- -- CurrentYear Current month Current day So this means that if the date string only contains time, you will get current date. - - */ - - DateTime now = GetDateTimeNow(ref result, ref styles); - if (result.Month == -1 && result.Day == -1) - { - if (result.Year == -1) - { - if ((styles & DateTimeStyles.NoCurrentDateDefault) != 0) - { - // If there is no year/month/day values, and NoCurrentDateDefault flag is used, - // set the year/month/day value to the beginning year/month/day of DateTime(). - // Note we should be using Gregorian for the year/month/day. - cal = GregorianCalendar.GetDefaultInstance(); - result.Year = result.Month = result.Day = 1; - } - else - { - // Year/Month/Day are all missing. - result.Year = cal.GetYear(now); - result.Month = cal.GetMonth(now); - result.Day = cal.GetDayOfMonth(now); - } - } - else - { - // Month/Day are both missing. - result.Month = 1; - result.Day = 1; - } - } - else - { - if (result.Year == -1) - { - result.Year = cal.GetYear(now); - } - if (result.Month == -1) - { - result.Month = 1; - } - if (result.Day == -1) - { - result.Day = 1; - } - } - } - // Set Hour/Minute/Second to zero if these value are not in str. - if (result.Hour == -1) result.Hour = 0; - if (result.Minute == -1) result.Minute = 0; - if (result.Second == -1) result.Second = 0; - if (result.era == -1) result.era = Calendar.CurrentEra; - return true; - } - - // Expand a pre-defined format string (like "D" for long date) to the real format that - // we are going to use in the date time parsing. - // This method also set the dtfi according/parseInfo to some special pre-defined - // formats. - // - private static string ExpandPredefinedFormat(ReadOnlySpan<char> format, ref DateTimeFormatInfo dtfi, ref ParsingInfo parseInfo, ref DateTimeResult result) - { - // - // Check the format to see if we need to override the dtfi to be InvariantInfo, - // and see if we need to set up the userUniversalTime flag. - // - switch (format[0]) - { - case 's': // Sortable format (in local time) - case 'o': - case 'O': // Round Trip Format - ConfigureFormatOS(ref dtfi, ref parseInfo); - break; - case 'r': - case 'R': // RFC 1123 Standard. (in Universal time) - ConfigureFormatR(ref dtfi, ref parseInfo, ref result); - break; - case 'u': // Universal time format in sortable format. - parseInfo.calendar = GregorianCalendar.GetDefaultInstance(); - dtfi = DateTimeFormatInfo.InvariantInfo; - - if ((result.flags & ParseFlags.CaptureOffset) != 0) - { - result.flags |= ParseFlags.UtcSortPattern; - } - break; - case 'U': // Universal time format with culture-dependent format. - parseInfo.calendar = GregorianCalendar.GetDefaultInstance(); - result.flags |= ParseFlags.TimeZoneUsed; - result.timeZoneOffset = new TimeSpan(0); - result.flags |= ParseFlags.TimeZoneUtc; - if (dtfi.Calendar.GetType() != typeof(GregorianCalendar)) - { - dtfi = (DateTimeFormatInfo)dtfi.Clone(); - dtfi.Calendar = GregorianCalendar.GetDefaultInstance(); - } - break; - } - - // - // Expand the pre-defined format character to the real format from DateTimeFormatInfo. - // - return DateTimeFormat.GetRealFormat(format, dtfi); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static bool ParseJapaneseEraStart(ref __DTString str, DateTimeFormatInfo dtfi) - { - // ParseJapaneseEraStart will be called when parsing the year number. We can have dates which not listing - // the year as a number and listing it as JapaneseEraStart symbol (which means year 1). - // This will be legitimate date to recognize. - if (LocalAppContextSwitches.EnforceLegacyJapaneseDateParsing || dtfi.Calendar.ID != CalendarId.JAPAN || !str.GetNext()) - return false; - - if (str.m_current != DateTimeFormatInfo.JapaneseEraStart[0]) - { - str.Index--; - return false; - } - - return true; - } - - private static void ConfigureFormatR(ref DateTimeFormatInfo dtfi, ref ParsingInfo parseInfo, ref DateTimeResult result) - { - parseInfo.calendar = GregorianCalendar.GetDefaultInstance(); - dtfi = DateTimeFormatInfo.InvariantInfo; - if ((result.flags & ParseFlags.CaptureOffset) != 0) - { - result.flags |= ParseFlags.Rfc1123Pattern; - } - } - - private static void ConfigureFormatOS(ref DateTimeFormatInfo dtfi, ref ParsingInfo parseInfo) - { - parseInfo.calendar = GregorianCalendar.GetDefaultInstance(); - dtfi = DateTimeFormatInfo.InvariantInfo; - } - - // Given a specified format character, parse and update the parsing result. - // - private static bool ParseByFormat( - ref __DTString str, - ref __DTString format, - ref ParsingInfo parseInfo, - DateTimeFormatInfo dtfi, - ref DateTimeResult result) - { - int tokenLen = 0; - int tempYear = 0, tempMonth = 0, tempDay = 0, tempDayOfWeek = 0, tempHour = 0, tempMinute = 0, tempSecond = 0; - double tempFraction = 0; - TM tempTimeMark = 0; - - char ch = format.GetChar(); - - switch (ch) - { - case 'y': - tokenLen = format.GetRepeatCount(); - bool parseResult; - if (ParseJapaneseEraStart(ref str, dtfi)) - { - tempYear = 1; - parseResult = true; - } - else if (dtfi.HasForceTwoDigitYears) - { - parseResult = ParseDigits(ref str, 1, 4, out tempYear); - } - else - { - if (tokenLen <= 2) - { - parseInfo.fUseTwoDigitYear = true; - } - parseResult = ParseDigits(ref str, tokenLen, out tempYear); - } - if (!parseResult && parseInfo.fCustomNumberParser) - { - parseResult = parseInfo.parseNumberDelegate(ref str, tokenLen, out tempYear); - } - if (!parseResult) - { - result.SetBadDateTimeFailure(); - return false; - } - if (!CheckNewValue(ref result.Year, tempYear, ch, ref result)) - { - return false; - } - break; - case 'M': - tokenLen = format.GetRepeatCount(); - if (tokenLen <= 2) - { - if (!ParseDigits(ref str, tokenLen, out tempMonth)) - { - if (!parseInfo.fCustomNumberParser || - !parseInfo.parseNumberDelegate(ref str, tokenLen, out tempMonth)) - { - result.SetBadDateTimeFailure(); - return false; - } - } - } - else - { - if (tokenLen == 3) - { - if (!MatchAbbreviatedMonthName(ref str, dtfi, ref tempMonth)) - { - result.SetBadDateTimeFailure(); - return false; - } - } - else - { - if (!MatchMonthName(ref str, dtfi, ref tempMonth)) - { - result.SetBadDateTimeFailure(); - return false; - } - } - result.flags |= ParseFlags.ParsedMonthName; - } - if (!CheckNewValue(ref result.Month, tempMonth, ch, ref result)) - { - return false; - } - break; - case 'd': - // Day & Day of week - tokenLen = format.GetRepeatCount(); - if (tokenLen <= 2) - { - // "d" & "dd" - - if (!ParseDigits(ref str, tokenLen, out tempDay)) - { - if (!parseInfo.fCustomNumberParser || - !parseInfo.parseNumberDelegate(ref str, tokenLen, out tempDay)) - { - result.SetBadDateTimeFailure(); - return false; - } - } - if (!CheckNewValue(ref result.Day, tempDay, ch, ref result)) - { - return false; - } - } - else - { - if (tokenLen == 3) - { - // "ddd" - if (!MatchAbbreviatedDayName(ref str, dtfi, ref tempDayOfWeek)) - { - result.SetBadDateTimeFailure(); - return false; - } - } - else - { - // "dddd*" - if (!MatchDayName(ref str, dtfi, ref tempDayOfWeek)) - { - result.SetBadDateTimeFailure(); - return false; - } - } - if (!CheckNewValue(ref parseInfo.dayOfWeek, tempDayOfWeek, ch, ref result)) - { - return false; - } - } - break; - case 'g': - tokenLen = format.GetRepeatCount(); - // Put the era value in result.era. - if (!MatchEraName(ref str, dtfi, ref result.era)) - { - result.SetBadDateTimeFailure(); - return false; - } - break; - case 'h': - parseInfo.fUseHour12 = true; - tokenLen = format.GetRepeatCount(); - if (!ParseDigits(ref str, tokenLen < 2 ? 1 : 2, out tempHour)) - { - result.SetBadDateTimeFailure(); - return false; - } - if (!CheckNewValue(ref result.Hour, tempHour, ch, ref result)) - { - return false; - } - break; - case 'H': - tokenLen = format.GetRepeatCount(); - if (!ParseDigits(ref str, tokenLen < 2 ? 1 : 2, out tempHour)) - { - result.SetBadDateTimeFailure(); - return false; - } - if (!CheckNewValue(ref result.Hour, tempHour, ch, ref result)) - { - return false; - } - break; - case 'm': - tokenLen = format.GetRepeatCount(); - if (!ParseDigits(ref str, tokenLen < 2 ? 1 : 2, out tempMinute)) - { - result.SetBadDateTimeFailure(); - return false; - } - if (!CheckNewValue(ref result.Minute, tempMinute, ch, ref result)) - { - return false; - } - break; - case 's': - tokenLen = format.GetRepeatCount(); - if (!ParseDigits(ref str, tokenLen < 2 ? 1 : 2, out tempSecond)) - { - result.SetBadDateTimeFailure(); - return false; - } - if (!CheckNewValue(ref result.Second, tempSecond, ch, ref result)) - { - return false; - } - break; - case 'f': - case 'F': - tokenLen = format.GetRepeatCount(); - if (tokenLen <= DateTimeFormat.MaxSecondsFractionDigits) - { - if (!ParseFractionExact(ref str, tokenLen, ref tempFraction)) - { - if (ch == 'f') - { - result.SetBadDateTimeFailure(); - return false; - } - } - if (result.fraction < 0) - { - result.fraction = tempFraction; - } - else - { - if (tempFraction != result.fraction) - { - result.SetFailure(ParseFailureKind.FormatWithParameter, nameof(SR.Format_RepeatDateTimePattern), ch); - return false; - } - } - } - else - { - result.SetBadDateTimeFailure(); - return false; - } - break; - case 't': - // AM/PM designator - tokenLen = format.GetRepeatCount(); - if (tokenLen == 1) - { - if (!MatchAbbreviatedTimeMark(ref str, dtfi, ref tempTimeMark)) - { - result.SetBadDateTimeFailure(); - return false; - } - } - else - { - if (!MatchTimeMark(ref str, dtfi, ref tempTimeMark)) - { - result.SetBadDateTimeFailure(); - return false; - } - } - - if (parseInfo.timeMark == TM.NotSet) - { - parseInfo.timeMark = tempTimeMark; - } - else - { - if (parseInfo.timeMark != tempTimeMark) - { - result.SetFailure(ParseFailureKind.FormatWithParameter, nameof(SR.Format_RepeatDateTimePattern), ch); - return false; - } - } - break; - case 'z': - // timezone offset - tokenLen = format.GetRepeatCount(); - { - TimeSpan tempTimeZoneOffset = new TimeSpan(0); - if (!ParseTimeZoneOffset(ref str, tokenLen, ref tempTimeZoneOffset)) - { - result.SetBadDateTimeFailure(); - return false; - } - if ((result.flags & ParseFlags.TimeZoneUsed) != 0 && tempTimeZoneOffset != result.timeZoneOffset) - { - result.SetFailure(ParseFailureKind.FormatWithParameter, nameof(SR.Format_RepeatDateTimePattern), 'z'); - return false; - } - result.timeZoneOffset = tempTimeZoneOffset; - result.flags |= ParseFlags.TimeZoneUsed; - } - break; - case 'Z': - if ((result.flags & ParseFlags.TimeZoneUsed) != 0 && result.timeZoneOffset != TimeSpan.Zero) - { - result.SetFailure(ParseFailureKind.FormatWithParameter, nameof(SR.Format_RepeatDateTimePattern), 'Z'); - return false; - } - - result.flags |= ParseFlags.TimeZoneUsed; - result.timeZoneOffset = new TimeSpan(0); - result.flags |= ParseFlags.TimeZoneUtc; - - // The updating of the indexes is to reflect that ParseExact MatchXXX methods assume that - // they need to increment the index and Parse GetXXX do not. Since we are calling a Parse - // method from inside ParseExact we need to adjust this. Long term, we should try to - // eliminate this discrepancy. - str.Index++; - if (!GetTimeZoneName(ref str)) - { - result.SetBadDateTimeFailure(); - return false; - } - str.Index--; - break; - case 'K': - // This should parse either as a blank, the 'Z' character or a local offset like "-07:00" - if (str.Match('Z')) - { - if ((result.flags & ParseFlags.TimeZoneUsed) != 0 && result.timeZoneOffset != TimeSpan.Zero) - { - result.SetFailure(ParseFailureKind.FormatWithParameter, nameof(SR.Format_RepeatDateTimePattern), 'K'); - return false; - } - - result.flags |= ParseFlags.TimeZoneUsed; - result.timeZoneOffset = new TimeSpan(0); - result.flags |= ParseFlags.TimeZoneUtc; - } - else if (str.Match('+') || str.Match('-')) - { - str.Index--; // Put the character back for the parser - TimeSpan tempTimeZoneOffset = new TimeSpan(0); - if (!ParseTimeZoneOffset(ref str, 3, ref tempTimeZoneOffset)) - { - result.SetBadDateTimeFailure(); - return false; - } - if ((result.flags & ParseFlags.TimeZoneUsed) != 0 && tempTimeZoneOffset != result.timeZoneOffset) - { - result.SetFailure(ParseFailureKind.FormatWithParameter, nameof(SR.Format_RepeatDateTimePattern), 'K'); - return false; - } - result.timeZoneOffset = tempTimeZoneOffset; - result.flags |= ParseFlags.TimeZoneUsed; - } - // Otherwise it is unspecified and we consume no characters - break; - case ':': - // We match the separator in time pattern with the character in the time string if both equal to ':' or the date separator is matching the characters in the date string - // We have to exclude the case when the time separator is more than one character and starts with ':' something like "::" for instance. - if (((dtfi.TimeSeparator.Length > 1 && dtfi.TimeSeparator[0] == ':') || !str.Match(':')) && - !str.Match(dtfi.TimeSeparator)) - { - // A time separator is expected. - result.SetBadDateTimeFailure(); - return false; - } - break; - case '/': - // We match the separator in date pattern with the character in the date string if both equal to '/' or the date separator is matching the characters in the date string - // We have to exclude the case when the date separator is more than one character and starts with '/' something like "//" for instance. - if (((dtfi.DateSeparator.Length > 1 && dtfi.DateSeparator[0] == '/') || !str.Match('/')) && - !str.Match(dtfi.DateSeparator)) - { - // A date separator is expected. - result.SetBadDateTimeFailure(); - return false; - } - break; - case '\"': - case '\'': - StringBuilder enquotedString = StringBuilderCache.Acquire(); - // Use ParseQuoteString so that we can handle escape characters within the quoted string. - if (!TryParseQuoteString(format.Value, format.Index, enquotedString, out tokenLen)) - { - result.SetFailure(ParseFailureKind.FormatWithParameter, nameof(SR.Format_BadQuote), ch); - StringBuilderCache.Release(enquotedString); - return false; - } - format.Index += tokenLen - 1; - - // Some cultures uses space in the quoted string. E.g. Spanish has long date format as: - // "dddd, dd' de 'MMMM' de 'yyyy". When inner spaces flag is set, we should skip whitespaces if there is space - // in the quoted string. - string quotedStr = StringBuilderCache.GetStringAndRelease(enquotedString); - - for (int i = 0; i < quotedStr.Length; i++) - { - if (quotedStr[i] == ' ' && parseInfo.fAllowInnerWhite) - { - str.SkipWhiteSpaces(); - } - else if (!str.Match(quotedStr[i])) - { - // Can not find the matching quoted string. - result.SetBadDateTimeFailure(); - return false; - } - } - - // The "r" and "u" formats incorrectly quoted 'GMT' and 'Z', respectively. We cannot - // correct this mistake for DateTime.ParseExact for compatibility reasons, but we can - // fix it for DateTimeOffset.ParseExact as DateTimeOffset has not been publically released - // with this issue. - if ((result.flags & ParseFlags.CaptureOffset) != 0) - { - if (((result.flags & ParseFlags.Rfc1123Pattern) != 0 && quotedStr == GMTName) || - ((result.flags & ParseFlags.UtcSortPattern) != 0 && quotedStr == ZuluName)) - { - result.flags |= ParseFlags.TimeZoneUsed; - result.timeZoneOffset = TimeSpan.Zero; - } - } - - break; - case '%': - // Skip this so we can get to the next pattern character. - // Used in case like "%d", "%y" - - // Make sure the next character is not a '%' again. - if (format.Index >= format.Value.Length - 1 || format.Value[format.Index + 1] == '%') - { - result.SetBadFormatSpecifierFailure(format.Value); - return false; - } - break; - case '\\': - // Escape character. For example, "\d". - // Get the next character in format, and see if we can - // find a match in str. - if (format.GetNext()) - { - if (!str.Match(format.GetChar())) - { - // Can not find a match for the escaped character. - result.SetBadDateTimeFailure(); - return false; - } - } - else - { - result.SetBadFormatSpecifierFailure(format.Value); - return false; - } - break; - case '.': - if (!str.Match(ch)) - { - if (format.GetNext()) - { - // If we encounter the pattern ".F", and the dot is not present, it is an optional - // second fraction and we can skip this format. - if (format.Match('F')) - { - format.GetRepeatCount(); - break; - } - } - result.SetBadDateTimeFailure(); - return false; - } - break; - default: - if (ch == ' ') - { - if (parseInfo.fAllowInnerWhite) - { - // Skip whitespaces if AllowInnerWhite. - // Do nothing here. - } - else - { - if (!str.Match(ch)) - { - // If the space does not match, and trailing space is allowed, we do - // one more step to see if the next format character can lead to - // successful parsing. - // This is used to deal with special case that a empty string can match - // a specific pattern. - // The example here is af-ZA, which has a time format like "hh:mm:ss tt". However, - // its AM symbol is "" (empty string). If fAllowTrailingWhite is used, and time is in - // the AM, we will trim the whitespaces at the end, which will lead to a failure - // when we are trying to match the space before "tt". - if (parseInfo.fAllowTrailingWhite) - { - if (format.GetNext()) - { - if (ParseByFormat(ref str, ref format, ref parseInfo, dtfi, ref result)) - { - return true; - } - } - } - result.SetBadDateTimeFailure(); - return false; - } - // Found a macth. - } - } - else - { - if (format.MatchSpecifiedWord(GMTName)) - { - format.Index += (GMTName.Length - 1); - // Found GMT string in format. This means the DateTime string - // is in GMT timezone. - result.flags |= ParseFlags.TimeZoneUsed; - result.timeZoneOffset = TimeSpan.Zero; - if (!str.Match(GMTName)) - { - result.SetBadDateTimeFailure(); - return false; - } - } - else if (!str.Match(ch)) - { - // ch is expected. - result.SetBadDateTimeFailure(); - return false; - } - } - break; - } // switch - return true; - } - - // - // The pos should point to a quote character. This method will - // get the string enclosed by the quote character. - // - internal static bool TryParseQuoteString(ReadOnlySpan<char> format, int pos, StringBuilder result, out int returnValue) - { - // - // NOTE : pos will be the index of the quote character in the 'format' string. - // - returnValue = 0; - int formatLen = format.Length; - int beginPos = pos; - char quoteChar = format[pos++]; // Get the character used to quote the following string. - - bool foundQuote = false; - while (pos < formatLen) - { - char ch = format[pos++]; - if (ch == quoteChar) - { - foundQuote = true; - break; - } - else if (ch == '\\') - { - // The following are used to support escaped character. - // Escaped character is also supported in the quoted string. - // Therefore, someone can use a format like "'minute:' mm\"" to display: - // minute: 45" - // because the second double quote is escaped. - if (pos < formatLen) - { - result.Append(format[pos++]); - } - else - { - // - // This means that '\' is at the end of the formatting string. - // - return false; - } - } - else - { - result.Append(ch); - } - } - - if (!foundQuote) - { - // Here we can't find the matching quote. - return false; - } - - // - // Return the character count including the begin/end quote characters and enclosed string. - // - returnValue = (pos - beginPos); - return true; - } - - /*=================================DoStrictParse================================== - **Action: Do DateTime parsing using the format in formatParam. - **Returns: The parsed DateTime. - **Arguments: - **Exceptions: - ** - **Notes: - ** When the following general formats are used, InvariantInfo is used in dtfi: - ** 'r', 'R', 's'. - ** When the following general formats are used, the time is assumed to be in Universal time. - ** - **Limitations: - ** Only GregorianCalendar is supported for now. - ** Only support GMT timezone. - ==============================================================================*/ - - private static bool DoStrictParse( - ReadOnlySpan<char> s, - ReadOnlySpan<char> formatParam, - DateTimeStyles styles, - DateTimeFormatInfo dtfi, - ref DateTimeResult result) - { - ParsingInfo parseInfo = default; - parseInfo.Init(); - - parseInfo.calendar = dtfi.Calendar; - parseInfo.fAllowInnerWhite = ((styles & DateTimeStyles.AllowInnerWhite) != 0); - parseInfo.fAllowTrailingWhite = ((styles & DateTimeStyles.AllowTrailingWhite) != 0); - - if (formatParam.Length == 1) - { - char formatParamChar = formatParam[0]; - - // Fast-paths for common and important formats/configurations. - if (styles == DateTimeStyles.None) - { - switch (formatParamChar) - { - case 'R': - case 'r': - ConfigureFormatR(ref dtfi, ref parseInfo, ref result); - return ParseFormatR(s, ref parseInfo, ref result); - - case 'O': - case 'o': - ConfigureFormatOS(ref dtfi, ref parseInfo); - return ParseFormatO(s, ref result); - } - } - - if (((result.flags & ParseFlags.CaptureOffset) != 0) && formatParamChar == 'U') - { - // The 'U' format is not allowed for DateTimeOffset - result.SetBadFormatSpecifierFailure(formatParam); - return false; - } - - formatParam = ExpandPredefinedFormat(formatParam, ref dtfi, ref parseInfo, ref result); - } - - bool bTimeOnly = false; - result.calendar = parseInfo.calendar; - - if (parseInfo.calendar.ID == CalendarId.HEBREW) - { - parseInfo.parseNumberDelegate = m_hebrewNumberParser; - parseInfo.fCustomNumberParser = true; - } - - // Reset these values to negative one so that we could throw exception - // if we have parsed every item twice. - result.Hour = result.Minute = result.Second = -1; - - __DTString format = new __DTString(formatParam, dtfi, false); - __DTString str = new __DTString(s, dtfi, false); - - if (parseInfo.fAllowTrailingWhite) - { - // Trim trailing spaces if AllowTrailingWhite. - format.TrimTail(); - format.RemoveTrailingInQuoteSpaces(); - str.TrimTail(); - } - - if ((styles & DateTimeStyles.AllowLeadingWhite) != 0) - { - format.SkipWhiteSpaces(); - format.RemoveLeadingInQuoteSpaces(); - str.SkipWhiteSpaces(); - } - - // - // Scan every character in format and match the pattern in str. - // - while (format.GetNext()) - { - // We trim inner spaces here, so that we will not eat trailing spaces when - // AllowTrailingWhite is not used. - if (parseInfo.fAllowInnerWhite) - { - str.SkipWhiteSpaces(); - } - if (!ParseByFormat(ref str, ref format, ref parseInfo, dtfi, ref result)) - { - return false; - } - } - - if (str.Index < str.Value.Length - 1) - { - // There are still remaining character in str. - result.SetBadDateTimeFailure(); - return false; - } - - if (parseInfo.fUseTwoDigitYear && ((dtfi.FormatFlags & DateTimeFormatFlags.UseHebrewRule) == 0)) - { - // A two digit year value is expected. Check if the parsed year value is valid. - if (result.Year >= 100) - { - result.SetBadDateTimeFailure(); - return false; - } - try - { - result.Year = parseInfo.calendar.ToFourDigitYear(result.Year); - } - catch (ArgumentOutOfRangeException) - { - result.SetBadDateTimeFailure(); - return false; - } - } - - if (parseInfo.fUseHour12) - { - if (parseInfo.timeMark == TM.NotSet) - { - // hh is used, but no AM/PM designator is specified. - // Assume the time is AM. - // Don't throw exceptions in here becasue it is very confusing for the caller. - // I always got confused myself when I use "hh:mm:ss" to parse a time string, - // and ParseExact() throws on me (because I didn't use the 24-hour clock 'HH'). - parseInfo.timeMark = TM.AM; - } - if (result.Hour > 12) - { - // AM/PM is used, but the value for HH is too big. - result.SetBadDateTimeFailure(); - return false; - } - if (parseInfo.timeMark == TM.AM) - { - if (result.Hour == 12) - { - result.Hour = 0; - } - } - else - { - result.Hour = (result.Hour == 12) ? 12 : result.Hour + 12; - } - } - else - { - // Military (24-hour time) mode - // - // AM cannot be set with a 24-hour time like 17:15. - // PM cannot be set with a 24-hour time like 03:15. - if ((parseInfo.timeMark == TM.AM && result.Hour >= 12) - || (parseInfo.timeMark == TM.PM && result.Hour < 12)) - { - result.SetBadDateTimeFailure(); - return false; - } - } - - // Check if the parsed string only contains hour/minute/second values. - bTimeOnly = (result.Year == -1 && result.Month == -1 && result.Day == -1); - if (!CheckDefaultDateTime(ref result, ref parseInfo.calendar, styles)) - { - return false; - } - - if (!bTimeOnly && dtfi.HasYearMonthAdjustment) - { - if (!dtfi.YearMonthAdjustment(ref result.Year, ref result.Month, (result.flags & ParseFlags.ParsedMonthName) != 0)) - { - result.SetFailure(ParseFailureKind.FormatBadDateTimeCalendar, nameof(SR.Format_BadDateTimeCalendar)); - return false; - } - } - if (!parseInfo.calendar.TryToDateTime(result.Year, result.Month, result.Day, - result.Hour, result.Minute, result.Second, 0, result.era, out result.parsedDate)) - { - result.SetFailure(ParseFailureKind.FormatBadDateTimeCalendar, nameof(SR.Format_BadDateTimeCalendar)); - return false; - } - if (result.fraction > 0) - { - if (!result.parsedDate.TryAddTicks((long)Math.Round(result.fraction * Calendar.TicksPerSecond), out result.parsedDate)) - { - result.SetBadDateTimeFailure(); - return false; - } - } - - // - // We have to check day of week before we adjust to the time zone. - // It is because the value of day of week may change after adjusting - // to the time zone. - // - if (parseInfo.dayOfWeek != -1) - { - // - // Check if day of week is correct. - // - if (parseInfo.dayOfWeek != (int)parseInfo.calendar.GetDayOfWeek(result.parsedDate)) - { - result.SetFailure(ParseFailureKind.FormatWithOriginalDateTime, nameof(SR.Format_BadDayOfWeek)); - return false; - } - } - - return DetermineTimeZoneAdjustments(ref result, styles, bTimeOnly); - } - - private static bool ParseFormatR(ReadOnlySpan<char> source, ref ParsingInfo parseInfo, ref DateTimeResult result) - { - // Example: - // Tue, 03 Jan 2017 08:08:05 GMT - - // The format is exactly 29 characters. - if ((uint)source.Length != 29) - { - result.SetBadDateTimeFailure(); - return false; - } - - // Parse the three-letter day of week. Any casing is valid. - DayOfWeek dayOfWeek; - { - uint dow0 = source[0], dow1 = source[1], dow2 = source[2], comma = source[3]; - - if ((dow0 | dow1 | dow2 | comma) > 0x7F) - { - result.SetBadDateTimeFailure(); - return false; - } - - uint dowString = (dow0 << 24) | (dow1 << 16) | (dow2 << 8) | comma | 0x20202000; - switch (dowString) - { - case 0x73756E2c /* 'sun,' */: dayOfWeek = DayOfWeek.Sunday; break; - case 0x6d6f6e2c /* 'mon,' */: dayOfWeek = DayOfWeek.Monday; break; - case 0x7475652c /* 'tue,' */: dayOfWeek = DayOfWeek.Tuesday; break; - case 0x7765642c /* 'wed,' */: dayOfWeek = DayOfWeek.Wednesday; break; - case 0x7468752c /* 'thu,' */: dayOfWeek = DayOfWeek.Thursday; break; - case 0x6672692c /* 'fri,' */: dayOfWeek = DayOfWeek.Friday; break; - case 0x7361742c /* 'sat,' */: dayOfWeek = DayOfWeek.Saturday; break; - default: - result.SetBadDateTimeFailure(); - return false; - } - } - - if (source[4] != ' ') - { - result.SetBadDateTimeFailure(); - return false; - } - - // Parse the two digit day. - int day; - { - uint digit1 = (uint)(source[5] - '0'), digit2 = (uint)(source[6] - '0'); - - if (digit1 > 9 || digit2 > 9) - { - result.SetBadDateTimeFailure(); - return false; - } - - day = (int)(digit1 * 10 + digit2); - } - - if (source[7] != ' ') - { - result.SetBadDateTimeFailure(); - return false; - } - - // Parse the three letter month (followed by a space). Any casing is valid. - int month; - { - uint m0 = source[8], m1 = source[9], m2 = source[10], space = source[11]; - - if ((m0 | m1 | m2 | space) > 0x7F) - { - result.SetBadDateTimeFailure(); - return false; - } - - switch ((m0 << 24) | (m1 << 16) | (m2 << 8) | space | 0x20202000) - { - case 0x6a616e20: /* 'jan ' */ month = 1; break; - case 0x66656220: /* 'feb ' */ month = 2; break; - case 0x6d617220: /* 'mar ' */ month = 3; break; - case 0x61707220: /* 'apr ' */ month = 4; break; - case 0x6d617920: /* 'may ' */ month = 5; break; - case 0x6a756e20: /* 'jun ' */ month = 6; break; - case 0x6a756c20: /* 'jul ' */ month = 7; break; - case 0x61756720: /* 'aug ' */ month = 8; break; - case 0x73657020: /* 'sep ' */ month = 9; break; - case 0x6f637420: /* 'oct ' */ month = 10; break; - case 0x6e6f7620: /* 'nov ' */ month = 11; break; - case 0x64656320: /* 'dec ' */ month = 12; break; - default: - result.SetBadDateTimeFailure(); - return false; - } - } - - // Parse the four-digit year. - int year; - { - uint y1 = (uint)(source[12] - '0'), y2 = (uint)(source[13] - '0'), y3 = (uint)(source[14] - '0'), y4 = (uint)(source[15] - '0'); - - if (y1 > 9 || y2 > 9 || y3 > 9 || y4 > 9) - { - result.SetBadDateTimeFailure(); - return false; - } - - year = (int)(y1 * 1000 + y2 * 100 + y3 * 10 + y4); - } - - if (source[16] != ' ') - { - result.SetBadDateTimeFailure(); - return false; - } - - // Parse the two digit hour. - int hour; - { - uint h1 = (uint)(source[17] - '0'), h2 = (uint)(source[18] - '0'); - - if (h1 > 9 || h2 > 9) - { - result.SetBadDateTimeFailure(); - return false; - } - - hour = (int)(h1 * 10 + h2); - } - - if (source[19] != ':') - { - result.SetBadDateTimeFailure(); - return false; - } - - // Parse the two-digit minute. - int minute; - { - uint m1 = (uint)(source[20] - '0'); - uint m2 = (uint)(source[21] - '0'); - - if (m1 > 9 || m2 > 9) - { - result.SetBadDateTimeFailure(); - return false; - } - - minute = (int)(m1 * 10 + m2); - } - - if (source[22] != ':') - { - result.SetBadDateTimeFailure(); - return false; - } - - // Parse the two-digit second. - int second; - { - uint s1 = (uint)(source[23] - '0'), s2 = (uint)(source[24] - '0'); - - if (s1 > 9 || s2 > 9) - { - result.SetBadDateTimeFailure(); - return false; - } - - second = (int)(s1 * 10 + s2); - } - - // Parse " GMT". It must be upper case. - if (source[25] != ' ' || source[26] != 'G' || source[27] != 'M' || source[28] != 'T') - { - result.SetBadDateTimeFailure(); - return false; - } - - // Validate that the parsed date is valid according to the calendar. - if (!parseInfo.calendar.TryToDateTime(year, month, day, hour, minute, second, 0, 0, out result.parsedDate)) - { - result.SetFailure(ParseFailureKind.FormatBadDateTimeCalendar, nameof(SR.Format_BadDateTimeCalendar)); - return false; - } - - // And validate that the parsed day of week matches what the calendar said it should be. - if (dayOfWeek != result.parsedDate.DayOfWeek) - { - result.SetFailure(ParseFailureKind.FormatWithOriginalDateTime, nameof(SR.Format_BadDayOfWeek)); - return false; - } - - return true; - } - - private static bool ParseFormatO(ReadOnlySpan<char> source, ref DateTimeResult result) - { - // Examples: - // 2017-06-12T05:30:45.7680000 (interpreted as local time wrt to current time zone) - // 2017-06-12T05:30:45.7680000Z (Z is short for "+00:00" but also distinguishes DateTimeKind.Utc from DateTimeKind.Local) - // 2017-06-12T05:30:45.7680000-7:00 (special-case of one-digit offset hour) - // 2017-06-12T05:30:45.7680000-07:00 - - if ((uint)source.Length < 27 || - source[4] != '-' || - source[7] != '-' || - source[10] != 'T' || - source[13] != ':' || - source[16] != ':' || - source[19] != '.') - { - result.SetBadDateTimeFailure(); - return false; - } - - int year; - { - uint y1 = (uint)(source[0] - '0'), y2 = (uint)(source[1] - '0'), y3 = (uint)(source[2] - '0'), y4 = (uint)(source[3] - '0'); - - if (y1 > 9 || y2 > 9 || y3 > 9 || y4 > 9) - { - result.SetBadDateTimeFailure(); - return false; - } - - year = (int)(y1 * 1000 + y2 * 100 + y3 * 10 + y4); - } - - int month; - { - uint m1 = (uint)(source[5] - '0'), m2 = (uint)(source[6] - '0'); - - if (m1 > 9 || m2 > 9) - { - result.SetBadDateTimeFailure(); - return false; - } - - month = (int)(m1 * 10 + m2); - } - - int day; - { - uint d1 = (uint)(source[8] - '0'), d2 = (uint)(source[9] - '0'); - - if (d1 > 9 || d2 > 9) - { - result.SetBadDateTimeFailure(); - return false; - } - - day = (int)(d1 * 10 + d2); - } - - int hour; - { - uint h1 = (uint)(source[11] - '0'), h2 = (uint)(source[12] - '0'); - - if (h1 > 9 || h2 > 9) - { - result.SetBadDateTimeFailure(); - return false; - } - - hour = (int)(h1 * 10 + h2); - } - - int minute; - { - uint m1 = (uint)(source[14] - '0'), m2 = (uint)(source[15] - '0'); - - if (m1 > 9 || m2 > 9) - { - result.SetBadDateTimeFailure(); - return false; - } - - minute = (int)(m1 * 10 + m2); - } - - int second; - { - uint s1 = (uint)(source[17] - '0'), s2 = (uint)(source[18] - '0'); - - if (s1 > 9 || s2 > 9) - { - result.SetBadDateTimeFailure(); - return false; - } - - second = (int)(s1 * 10 + s2); - } - - double fraction; - { - uint f1 = (uint)(source[20] - '0'); - uint f2 = (uint)(source[21] - '0'); - uint f3 = (uint)(source[22] - '0'); - uint f4 = (uint)(source[23] - '0'); - uint f5 = (uint)(source[24] - '0'); - uint f6 = (uint)(source[25] - '0'); - uint f7 = (uint)(source[26] - '0'); - - if (f1 > 9 || f2 > 9 || f3 > 9 || f4 > 9 || f5 > 9 || f6 > 9 || f7 > 9) - { - result.SetBadDateTimeFailure(); - return false; - } - - fraction = (f1 * 1000000 + f2 * 100000 + f3 * 10000 + f4 * 1000 + f5 * 100 + f6 * 10 + f7) / 10000000.0; - } - - if (!DateTime.TryCreate(year, month, day, hour, minute, second, 0, out DateTime dateTime)) - { - result.SetBadDateTimeFailure(); - return false; - } - - if (!dateTime.TryAddTicks((long)Math.Round(fraction * Calendar.TicksPerSecond), out result.parsedDate)) - { - result.SetBadDateTimeFailure(); - return false; - } - - if ((uint)source.Length > 27) - { - char offsetChar = source[27]; - switch (offsetChar) - { - case 'Z': - if (source.Length != 28) - { - result.SetBadDateTimeFailure(); - return false; - } - result.flags |= ParseFlags.TimeZoneUsed | ParseFlags.TimeZoneUtc; - break; - - case '+': - case '-': - int offsetHours, colonIndex; - - if ((uint)source.Length == 33) - { - uint oh1 = (uint)(source[28] - '0'), oh2 = (uint)(source[29] - '0'); - - if (oh1 > 9 || oh2 > 9) - { - result.SetBadDateTimeFailure(); - return false; - } - - offsetHours = (int)(oh1 * 10 + oh2); - colonIndex = 30; - } - else if ((uint)source.Length == 32) // special-case allowed for compat: only one offset hour digit - { - offsetHours = source[28] - '0'; - - if ((uint)offsetHours > 9) - { - result.SetBadDateTimeFailure(); - return false; - } - - colonIndex = 29; - } - else - { - result.SetBadDateTimeFailure(); - return false; - } - - if (source[colonIndex] != ':') - { - result.SetBadDateTimeFailure(); - return false; - } - - int offsetMinutes; - { - uint om1 = (uint)(source[colonIndex + 1] - '0'), om2 = (uint)(source[colonIndex + 2] - '0'); - - if (om1 > 9 || om2 > 9) - { - result.SetBadDateTimeFailure(); - return false; - } - - offsetMinutes = (int)(om1 * 10 + om2); - } - - result.flags |= ParseFlags.TimeZoneUsed; - result.timeZoneOffset = new TimeSpan(offsetHours, offsetMinutes, 0); - if (offsetChar == '-') - { - result.timeZoneOffset = result.timeZoneOffset.Negate(); - } - break; - - default: - result.SetBadDateTimeFailure(); - return false; - } - } - - return DetermineTimeZoneAdjustments(ref result, DateTimeStyles.None, bTimeOnly: false); - } - - private static Exception GetDateTimeParseException(ref DateTimeResult result) - { - switch (result.failure) - { - case ParseFailureKind.ArgumentNull: - return new ArgumentNullException(result.failureArgumentName, SR.GetResourceString(result.failureMessageID)); - case ParseFailureKind.Format: - return new FormatException(SR.GetResourceString(result.failureMessageID)); - case ParseFailureKind.FormatWithParameter: - return new FormatException(SR.Format(SR.GetResourceString(result.failureMessageID)!, result.failureMessageFormatArgument)); - case ParseFailureKind.FormatBadDateTimeCalendar: - return new FormatException(SR.Format(SR.GetResourceString(result.failureMessageID)!, new string(result.originalDateTimeString), result.calendar)); - case ParseFailureKind.FormatWithOriginalDateTime: - return new FormatException(SR.Format(SR.GetResourceString(result.failureMessageID)!, new string(result.originalDateTimeString))); - case ParseFailureKind.FormatWithFormatSpecifier: - return new FormatException(SR.Format(SR.GetResourceString(result.failureMessageID)!, new string(result.failedFormatSpecifier))); - case ParseFailureKind.FormatWithOriginalDateTimeAndParameter: - return new FormatException(SR.Format(SR.GetResourceString(result.failureMessageID)!, new string(result.originalDateTimeString), result.failureMessageFormatArgument)); - default: - Debug.Fail("Unknown DateTimeParseFailure: " + result.failure.ToString()); - return null!; - } - } - - [Conditional("_LOGGING")] - private static void LexTraceExit(string message, DS dps) - { -#if _LOGGING - if (!_tracingEnabled) - return; - Trace($"Lex return {message}, DS.{dps}"); -#endif // _LOGGING - } - [Conditional("_LOGGING")] - private static void PTSTraceExit(DS dps, bool passed) - { -#if _LOGGING - if (!_tracingEnabled) - return; - Trace($"ProcessTerminalState {(passed ? "passed" : "failed")} @ DS.{dps}"); -#endif // _LOGGING - } - [Conditional("_LOGGING")] - private static void TPTraceExit(string message, DS dps) - { -#if _LOGGING - if (!_tracingEnabled) - return; - Trace($"TryParse return {message}, DS.{dps}"); -#endif // _LOGGING - } - [Conditional("_LOGGING")] - private static void DTFITrace(DateTimeFormatInfo dtfi) - { -#if _LOGGING - if (!_tracingEnabled) - return; - - Trace("DateTimeFormatInfo Properties"); - Trace($" NativeCalendarName {Hex(dtfi.NativeCalendarName)}"); - Trace($" AMDesignator {Hex(dtfi.AMDesignator)}"); - Trace($" PMDesignator {Hex(dtfi.PMDesignator)}"); - Trace($" TimeSeparator {Hex(dtfi.TimeSeparator)}"); - Trace($" AbbrvDayNames {Hex(dtfi.AbbreviatedDayNames)}"); - Trace($" ShortestDayNames {Hex(dtfi.ShortestDayNames)}"); - Trace($" DayNames {Hex(dtfi.DayNames)}"); - Trace($" AbbrvMonthNames {Hex(dtfi.AbbreviatedMonthNames)}"); - Trace($" MonthNames {Hex(dtfi.MonthNames)}"); - Trace($" AbbrvMonthGenNames {Hex(dtfi.AbbreviatedMonthGenitiveNames)}"); - Trace($" MonthGenNames {Hex(dtfi.MonthGenitiveNames)}"); -#endif // _LOGGING - } -#if _LOGGING - // return a string in the form: "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" - private static string Hex(string[] strs) - { - if (strs == null || strs.Length == 0) - return string.Empty; - if (strs.Length == 1) - return Hex(strs[0]); - - int curLineLength = 0; - const int MaxLineLength = 55; - const int NewLinePadding = 20; - - // invariant: strs.Length >= 2 - StringBuilder buffer = new StringBuilder(); - buffer.Append(Hex(strs[0])); - curLineLength = buffer.Length; - string s; - - for (int i = 1; i < strs.Length - 1; i++) - { - s = Hex(strs[i]); - - if (s.Length > MaxLineLength || (curLineLength + s.Length + 2) > MaxLineLength) - { - buffer.Append(','); - buffer.Append(Environment.NewLineConst); - buffer.Append(' ', NewLinePadding); - curLineLength = 0; - } - else - { - buffer.Append(", "); - curLineLength += 2; - } - buffer.Append(s); - curLineLength += s.Length; - } - - buffer.Append(','); - s = Hex(strs[strs.Length - 1]); - if (s.Length > MaxLineLength || (curLineLength + s.Length + 6) > MaxLineLength) - { - buffer.Append(Environment.NewLineConst); - buffer.Append(' ', NewLinePadding); - } - else - { - buffer.Append(' '); - } - buffer.Append(s); - return buffer.ToString(); - } - // return a string in the form: "Sun" - private static string Hex(string str) => Hex((ReadOnlySpan<char>)str); - private static string Hex(ReadOnlySpan<char> str) - { - StringBuilder buffer = new StringBuilder(); - buffer.Append("\""); - for (int i = 0; i < str.Length; i++) - { - if (str[i] <= '\x007f') - buffer.Append(str[i]); - else - buffer.Append("\\u").Append(((int)str[i]).ToString("x4", CultureInfo.InvariantCulture)); - } - buffer.Append("\""); - return buffer.ToString(); - } - // return an unicode escaped string form of char c - private static string Hex(char c) - { - if (c <= '\x007f') - return c.ToString(CultureInfo.InvariantCulture); - else - return "\\u" + ((int)c).ToString("x4", CultureInfo.InvariantCulture); - } - - private static void Trace(string s) - { - // Internal.Console.WriteLine(s); - } - - // for testing; do not make this readonly - private static bool _tracingEnabled = false; -#endif // _LOGGING - } - - // - // This is a string parsing helper which wraps a String object. - // It has a Index property which tracks - // the current parsing pointer of the string. - // - internal ref struct __DTString - { - // - // Value property: stores the real string to be parsed. - // - internal ReadOnlySpan<char> Value; - - // - // Index property: points to the character that we are currently parsing. - // - internal int Index; - - // The length of Value string. - internal int Length => Value.Length; - - // The current character to be looked at. - internal char m_current; - - private readonly CompareInfo m_info; - // Flag to indicate if we encouter an digit, we should check for token or not. - // In some cultures, such as mn-MN, it uses "\x0031\x00a0\x0434\x04af\x0433\x044d\x044d\x0440\x00a0\x0441\x0430\x0440" in month names. - private readonly bool m_checkDigitToken; - - internal __DTString(ReadOnlySpan<char> str, DateTimeFormatInfo dtfi, bool checkDigitToken) : this(str, dtfi) - { - m_checkDigitToken = checkDigitToken; - } - - internal __DTString(ReadOnlySpan<char> str, DateTimeFormatInfo dtfi) - { - Debug.Assert(dtfi != null, "Expected non-null DateTimeFormatInfo"); - - Index = -1; - Value = str; - - m_current = '\0'; - m_info = dtfi.CompareInfo; - m_checkDigitToken = ((dtfi.FormatFlags & DateTimeFormatFlags.UseDigitPrefixInTokens) != 0); - } - - internal CompareInfo CompareInfo => m_info; - - // - // Advance the Index. - // Return true if Index is NOT at the end of the string. - // - // Typical usage: - // while (str.GetNext()) - // { - // char ch = str.GetChar() - // } - internal bool GetNext() - { - Index++; - if (Index < Length) - { - m_current = Value[Index]; - return true; - } - return false; - } - - internal bool AtEnd() - { - return Index < Length ? false : true; - } - - internal bool Advance(int count) - { - Debug.Assert(Index + count <= Length, "__DTString::Advance: Index + count <= len"); - Index += count; - if (Index < Length) - { - m_current = Value[Index]; - return true; - } - return false; - } - - // Used by DateTime.Parse() to get the next token. - internal void GetRegularToken(out TokenType tokenType, out int tokenValue, DateTimeFormatInfo dtfi) - { - tokenValue = 0; - if (Index >= Length) - { - tokenType = TokenType.EndOfString; - return; - } - - Start: - if (DateTimeParse.IsDigit(m_current)) - { - // This is a digit. - tokenValue = m_current - '0'; - int value; - int start = Index; - - // - // Collect other digits. - // - while (++Index < Length) - { - m_current = Value[Index]; - value = m_current - '0'; - if (value >= 0 && value <= 9) - { - tokenValue = tokenValue * 10 + value; - } - else - { - break; - } - } - if (Index - start > DateTimeParse.MaxDateTimeNumberDigits) - { - tokenType = TokenType.NumberToken; - tokenValue = -1; - } - else if (Index - start < 3) - { - tokenType = TokenType.NumberToken; - } - else - { - // If there are more than 3 digits, assume that it's a year value. - tokenType = TokenType.YearNumberToken; - } - if (m_checkDigitToken) - { - int save = Index; - char saveCh = m_current; - // Re-scan using the staring Index to see if this is a token. - Index = start; // To include the first digit. - m_current = Value[Index]; - TokenType tempType; - int tempValue; - // This DTFI has tokens starting with digits. - // E.g. mn-MN has month name like "\x0031\x00a0\x0434\x04af\x0433\x044d\x044d\x0440\x00a0\x0441\x0430\x0440" - if (dtfi.Tokenize(TokenType.RegularTokenMask, out tempType, out tempValue, ref this)) - { - tokenType = tempType; - tokenValue = tempValue; - // This is a token, so the Index has been advanced propertly in DTFI.Tokenizer(). - } - else - { - // Use the number token value. - // Restore the index. - Index = save; - m_current = saveCh; - } - } - } - else if (char.IsWhiteSpace(m_current)) - { - // Just skip to the next character. - while (++Index < Length) - { - m_current = Value[Index]; - if (!char.IsWhiteSpace(m_current)) - { - goto Start; - } - } - // We have reached the end of string. - tokenType = TokenType.EndOfString; - } - else - { - dtfi.Tokenize(TokenType.RegularTokenMask, out tokenType, out tokenValue, ref this); - } - } - - internal TokenType GetSeparatorToken(DateTimeFormatInfo dtfi, out int indexBeforeSeparator, out char charBeforeSeparator) - { - indexBeforeSeparator = Index; - charBeforeSeparator = m_current; - TokenType tokenType; - if (!SkipWhiteSpaceCurrent()) - { - // Reach the end of the string. - return TokenType.SEP_End; - } - if (!DateTimeParse.IsDigit(m_current)) - { - // Not a digit. Tokenize it. - bool found = dtfi.Tokenize(TokenType.SeparatorTokenMask, out tokenType, out _, ref this); - if (!found) - { - tokenType = TokenType.SEP_Space; - } - } - else - { - // Do nothing here. If we see a number, it will not be a separator. There is no need wasting time trying to find the - // separator token. - tokenType = TokenType.SEP_Space; - } - return tokenType; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal bool MatchSpecifiedWord(string target) => - Index + target.Length <= Length && - m_info.Compare(Value.Slice(Index, target.Length), target, CompareOptions.IgnoreCase) == 0; - - private static readonly char[] WhiteSpaceChecks = new char[] { ' ', '\u00A0' }; - - internal bool MatchSpecifiedWords(string target, bool checkWordBoundary, ref int matchLength) - { - int valueRemaining = Value.Length - Index; - matchLength = target.Length; - - if (matchLength > valueRemaining || m_info.Compare(Value.Slice(Index, matchLength), target, CompareOptions.IgnoreCase) != 0) - { - // Check word by word - int targetPosition = 0; // Where we are in the target string - int thisPosition = Index; // Where we are in this string - int wsIndex = target.IndexOfAny(WhiteSpaceChecks, targetPosition); - if (wsIndex == -1) - { - return false; - } - do - { - int segmentLength = wsIndex - targetPosition; - if (thisPosition >= Value.Length - segmentLength) - { // Subtraction to prevent overflow. - return false; - } - if (segmentLength == 0) - { - // If segmentLength == 0, it means that we have leading space in the target string. - // In that case, skip the leading spaces in the target and this string. - matchLength--; - } - else - { - // Make sure we also have whitespace in the input string - if (!char.IsWhiteSpace(Value[thisPosition + segmentLength])) - { - return false; - } - if (m_info.CompareOptionIgnoreCase(Value.Slice(thisPosition, segmentLength), target.AsSpan(targetPosition, segmentLength)) != 0) - { - return false; - } - // Advance the input string - thisPosition = thisPosition + segmentLength + 1; - } - // Advance our target string - targetPosition = wsIndex + 1; - - // Skip past multiple whitespace - while (thisPosition < Value.Length && char.IsWhiteSpace(Value[thisPosition])) - { - thisPosition++; - matchLength++; - } - } while ((wsIndex = target.IndexOfAny(WhiteSpaceChecks, targetPosition)) >= 0); - // now check the last segment; - if (targetPosition < target.Length) - { - int segmentLength = target.Length - targetPosition; - if (thisPosition > Value.Length - segmentLength) - { - return false; - } - if (m_info.CompareOptionIgnoreCase(Value.Slice(thisPosition, segmentLength), target.AsSpan(targetPosition, segmentLength)) != 0) - { - return false; - } - } - } - - if (checkWordBoundary) - { - int nextCharIndex = Index + matchLength; - if (nextCharIndex < Value.Length) - { - if (char.IsLetter(Value[nextCharIndex])) - { - return false; - } - } - } - return true; - } - - // - // Check to see if the string starting from Index is a prefix of - // str. - // If a match is found, true value is returned and Index is updated to the next character to be parsed. - // Otherwise, Index is unchanged. - // - internal bool Match(string str) - { - if (++Index >= Length) - { - return false; - } - - if (str.Length > (Value.Length - Index)) - { - return false; - } - - if (m_info.Compare(Value.Slice(Index, str.Length), str, CompareOptions.Ordinal) == 0) - { - // Update the Index to the end of the matching string. - // So the following GetNext()/Match() opeartion will get - // the next character to be parsed. - Index += (str.Length - 1); - return true; - } - return false; - } - - internal bool Match(char ch) - { - if (++Index >= Length) - { - return false; - } - if (Value[Index] == ch) - { - m_current = ch; - return true; - } - Index--; - return false; - } - - // - // Actions: From the current position, try matching the longest word in the specified string array. - // E.g. words[] = {"AB", "ABC", "ABCD"}, if the current position points to a substring like "ABC DEF", - // MatchLongestWords(words, ref MaxMatchStrLen) will return 1 (the index), and maxMatchLen will be 3. - // Returns: - // The index that contains the longest word to match - // Arguments: - // words The string array that contains words to search. - // maxMatchStrLen [in/out] the initialized maximum length. This parameter can be used to - // find the longest match in two string arrays. - // - internal int MatchLongestWords(string[] words, ref int maxMatchStrLen) - { - int result = -1; - for (int i = 0; i < words.Length; i++) - { - string word = words[i]; - int matchLength = word.Length; - if (MatchSpecifiedWords(word, false, ref matchLength)) - { - if (matchLength > maxMatchStrLen) - { - maxMatchStrLen = matchLength; - result = i; - } - } - } - - return result; - } - - // - // Get the number of repeat character after the current character. - // For a string "hh:mm:ss" at Index of 3. GetRepeatCount() = 2, and Index - // will point to the second ':'. - // - internal int GetRepeatCount() - { - char repeatChar = Value[Index]; - int pos = Index + 1; - while ((pos < Length) && (Value[pos] == repeatChar)) - { - pos++; - } - int repeatCount = (pos - Index); - // Update the Index to the end of the repeated characters. - // So the following GetNext() opeartion will get - // the next character to be parsed. - Index = pos - 1; - return repeatCount; - } - - // Return false when end of string is encountered or a non-digit character is found. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal bool GetNextDigit() => - ++Index < Length && - DateTimeParse.IsDigit(Value[Index]); - - // - // Get the current character. - // - internal char GetChar() - { - Debug.Assert(Index >= 0 && Index < Length, "Index >= 0 && Index < len"); - return Value[Index]; - } - - // - // Convert the current character to a digit, and return it. - // - internal int GetDigit() - { - Debug.Assert(Index >= 0 && Index < Length, "Index >= 0 && Index < len"); - Debug.Assert(DateTimeParse.IsDigit(Value[Index]), "IsDigit(Value[Index])"); - return Value[Index] - '0'; - } - - // - // Eat White Space ahead of the current position - // - // Return false if end of string is encountered. - // - internal void SkipWhiteSpaces() - { - // Look ahead to see if the next character - // is a whitespace. - while (Index + 1 < Length) - { - char ch = Value[Index + 1]; - if (!char.IsWhiteSpace(ch)) - { - return; - } - Index++; - } - return; - } - - // - // Skip white spaces from the current position - // - // Return false if end of string is encountered. - // - internal bool SkipWhiteSpaceCurrent() - { - if (Index >= Length) - { - return false; - } - - if (!char.IsWhiteSpace(m_current)) - { - return true; - } - - while (++Index < Length) - { - m_current = Value[Index]; - if (!char.IsWhiteSpace(m_current)) - { - return true; - } - // Nothing here. - } - return false; - } - - internal void TrimTail() - { - int i = Length - 1; - while (i >= 0 && char.IsWhiteSpace(Value[i])) - { - i--; - } - Value = Value.Slice(0, i + 1); - } - - // Trim the trailing spaces within a quoted string. - // Call this after TrimTail() is done. - internal void RemoveTrailingInQuoteSpaces() - { - int i = Length - 1; - if (i <= 1) - { - return; - } - char ch = Value[i]; - // Check if the last character is a quote. - if (ch == '\'' || ch == '\"') - { - if (char.IsWhiteSpace(Value[i - 1])) - { - i--; - while (i >= 1 && char.IsWhiteSpace(Value[i - 1])) - { - i--; - } - Span<char> result = new char[i + 1]; - result[i] = ch; - Value.Slice(0, i).CopyTo(result); - Value = result; - } - } - } - - // Trim the leading spaces within a quoted string. - // Call this after the leading spaces before quoted string are trimmed. - internal void RemoveLeadingInQuoteSpaces() - { - if (Length <= 2) - { - return; - } - int i = 0; - char ch = Value[i]; - // Check if the last character is a quote. - if (ch == '\'' || ch == '\"') - { - while ((i + 1) < Length && char.IsWhiteSpace(Value[i + 1])) - { - i++; - } - if (i != 0) - { - Span<char> result = new char[Value.Length - i]; - result[0] = ch; - Value.Slice(i + 1).CopyTo(result.Slice(1)); - Value = result; - } - } - } - - internal DTSubString GetSubString() - { - DTSubString sub = default; - sub.index = Index; - sub.s = Value; - while (Index + sub.length < Length) - { - DTSubStringType currentType; - char ch = Value[Index + sub.length]; - if (ch >= '0' && ch <= '9') - { - currentType = DTSubStringType.Number; - } - else - { - currentType = DTSubStringType.Other; - } - - if (sub.length == 0) - { - sub.type = currentType; - } - else - { - if (sub.type != currentType) - { - break; - } - } - sub.length++; - if (currentType == DTSubStringType.Number) - { - // Incorporate the number into the value - // Limit the digits to prevent overflow - if (sub.length > DateTimeParse.MaxDateTimeNumberDigits) - { - sub.type = DTSubStringType.Invalid; - return sub; - } - int number = ch - '0'; - Debug.Assert(number >= 0 && number <= 9, "number >= 0 && number <= 9"); - sub.value = sub.value * 10 + number; - } - else - { - // For non numbers, just return this length 1 token. This should be expanded - // to more types of thing if this parsing approach is used for things other - // than numbers and single characters - break; - } - } - if (sub.length == 0) - { - sub.type = DTSubStringType.End; - return sub; - } - - return sub; - } - - internal void ConsumeSubString(DTSubString sub) - { - Debug.Assert(sub.index == Index, "sub.index == Index"); - Debug.Assert(sub.index + sub.length <= Length, "sub.index + sub.length <= len"); - Index = sub.index + sub.length; - if (Index < Length) - { - m_current = Value[Index]; - } - } - } - - internal enum DTSubStringType - { - Unknown = 0, - Invalid = 1, - Number = 2, - End = 3, - Other = 4, - } - - internal ref struct DTSubString - { - internal ReadOnlySpan<char> s; - internal int index; - internal int length; - internal DTSubStringType type; - internal int value; - - internal char this[int relativeIndex] => s[index + relativeIndex]; - } - - // - // The buffer to store the parsing token. - // - internal - struct DateTimeToken - { - internal DateTimeParse.DTT dtt; // Store the token - internal TokenType suffix; // Store the CJK Year/Month/Day suffix (if any) - internal int num; // Store the number that we are parsing (if any) - } - - // - // The buffer to store temporary parsing information. - // - internal unsafe struct DateTimeRawInfo - { - private int* num; - internal int numCount; - internal int month; - internal int year; - internal int dayOfWeek; - internal int era; - internal DateTimeParse.TM timeMark; - internal double fraction; - internal bool hasSameDateAndTimeSeparators; - - internal void Init(int* numberBuffer) - { - month = -1; - year = -1; - dayOfWeek = -1; - era = -1; - timeMark = DateTimeParse.TM.NotSet; - fraction = -1; - num = numberBuffer; - } - - internal void AddNumber(int value) - { - num[numCount++] = value; - } - - internal int GetNumber(int index) - { - return num[index]; - } - } - - internal enum ParseFailureKind - { - None = 0, - ArgumentNull = 1, - Format = 2, - FormatWithParameter = 3, - FormatWithOriginalDateTime = 4, - FormatWithFormatSpecifier = 5, - FormatWithOriginalDateTimeAndParameter = 6, - FormatBadDateTimeCalendar = 7, // FormatException when ArgumentOutOfRange is thrown by a Calendar.TryToDateTime(). - } - - [Flags] - internal enum ParseFlags - { - HaveYear = 0x00000001, - HaveMonth = 0x00000002, - HaveDay = 0x00000004, - HaveHour = 0x00000008, - HaveMinute = 0x00000010, - HaveSecond = 0x00000020, - HaveTime = 0x00000040, - HaveDate = 0x00000080, - TimeZoneUsed = 0x00000100, - TimeZoneUtc = 0x00000200, - ParsedMonthName = 0x00000400, - CaptureOffset = 0x00000800, - YearDefault = 0x00001000, - Rfc1123Pattern = 0x00002000, - UtcSortPattern = 0x00004000, - } - - // - // This will store the result of the parsing. And it will be eventually - // used to construct a DateTime instance. - // - internal ref struct DateTimeResult - { - internal int Year; - internal int Month; - internal int Day; - // - // Set time default to 00:00:00. - // - internal int Hour; - internal int Minute; - internal int Second; - internal double fraction; - - internal int era; - - internal ParseFlags flags; - - internal TimeSpan timeZoneOffset; - - internal Calendar calendar; - - internal DateTime parsedDate; - - internal ParseFailureKind failure; - internal string failureMessageID; - internal object? failureMessageFormatArgument; - internal string failureArgumentName; - internal ReadOnlySpan<char> originalDateTimeString; - internal ReadOnlySpan<char> failedFormatSpecifier; - - internal void Init(ReadOnlySpan<char> originalDateTimeString) - { - this.originalDateTimeString = originalDateTimeString; - Year = -1; - Month = -1; - Day = -1; - fraction = -1; - era = -1; - } - - internal void SetDate(int year, int month, int day) - { - Year = year; - Month = month; - Day = day; - } - - internal void SetBadFormatSpecifierFailure() - { - SetBadFormatSpecifierFailure(ReadOnlySpan<char>.Empty); - } - - internal void SetBadFormatSpecifierFailure(ReadOnlySpan<char> failedFormatSpecifier) - { - this.failure = ParseFailureKind.FormatWithFormatSpecifier; - this.failureMessageID = nameof(SR.Format_BadFormatSpecifier); - this.failedFormatSpecifier = failedFormatSpecifier; - } - - internal void SetBadDateTimeFailure() - { - this.failure = ParseFailureKind.FormatWithOriginalDateTime; - this.failureMessageID = nameof(SR.Format_BadDateTime); - this.failureMessageFormatArgument = null; - } - - internal void SetFailure(ParseFailureKind failure, string failureMessageID) - { - this.failure = failure; - this.failureMessageID = failureMessageID; - this.failureMessageFormatArgument = null; - } - - internal void SetFailure(ParseFailureKind failure, string failureMessageID, object? failureMessageFormatArgument) - { - this.failure = failure; - this.failureMessageID = failureMessageID; - this.failureMessageFormatArgument = failureMessageFormatArgument; - } - - internal void SetFailure(ParseFailureKind failure, string failureMessageID, object? failureMessageFormatArgument, string failureArgumentName) - { - this.failure = failure; - this.failureMessageID = failureMessageID; - this.failureMessageFormatArgument = failureMessageFormatArgument; - this.failureArgumentName = failureArgumentName; - } - } - - // This is the helper data structure used in ParseExact(). - internal struct ParsingInfo - { - internal Calendar calendar; - internal int dayOfWeek; - internal DateTimeParse.TM timeMark; - - internal bool fUseHour12; - internal bool fUseTwoDigitYear; - internal bool fAllowInnerWhite; - internal bool fAllowTrailingWhite; - internal bool fCustomNumberParser; - internal DateTimeParse.MatchNumberDelegate parseNumberDelegate; - - internal void Init() - { - dayOfWeek = -1; - timeMark = DateTimeParse.TM.NotSet; - } - } - - // - // The type of token that will be returned by DateTimeFormatInfo.Tokenize(). - // - internal enum TokenType - { - // The valid token should start from 1. - - // Regular tokens. The range is from 0x00 ~ 0xff. - NumberToken = 1, // The number. E.g. "12" - YearNumberToken = 2, // The number which is considered as year number, which has 3 or more digits. E.g. "2003" - Am = 3, // AM timemark. E.g. "AM" - Pm = 4, // PM timemark. E.g. "PM" - MonthToken = 5, // A word (or words) that represents a month name. E.g. "March" - EndOfString = 6, // End of string - DayOfWeekToken = 7, // A word (or words) that represents a day of week name. E.g. "Monday" or "Mon" - TimeZoneToken = 8, // A word that represents a timezone name. E.g. "GMT" - EraToken = 9, // A word that represents a era name. E.g. "A.D." - DateWordToken = 10, // A word that can appear in a DateTime string, but serves no parsing semantics. E.g. "de" in Spanish culture. - UnknownToken = 11, // An unknown word, which signals an error in parsing. - HebrewNumber = 12, // A number that is composed of Hebrew text. Hebrew calendar uses Hebrew digits for year values, month values, and day values. - JapaneseEraToken = 13, // Era name for JapaneseCalendar - TEraToken = 14, // Era name for TaiwanCalendar - IgnorableSymbol = 15, // A separator like "," that is equivalent to whitespace - - // Separator tokens. - SEP_Unk = 0x100, // Unknown separator. - SEP_End = 0x200, // The end of the parsing string. - SEP_Space = 0x300, // Whitespace (including comma). - SEP_Am = 0x400, // AM timemark. E.g. "AM" - SEP_Pm = 0x500, // PM timemark. E.g. "PM" - SEP_Date = 0x600, // date separator. E.g. "/" - SEP_Time = 0x700, // time separator. E.g. ":" - SEP_YearSuff = 0x800, // Chinese/Japanese/Korean year suffix. - SEP_MonthSuff = 0x900, // Chinese/Japanese/Korean month suffix. - SEP_DaySuff = 0xa00, // Chinese/Japanese/Korean day suffix. - SEP_HourSuff = 0xb00, // Chinese/Japanese/Korean hour suffix. - SEP_MinuteSuff = 0xc00, // Chinese/Japanese/Korean minute suffix. - SEP_SecondSuff = 0xd00, // Chinese/Japanese/Korean second suffix. - SEP_LocalTimeMark = 0xe00, // 'T', used in ISO 8601 format. - SEP_DateOrOffset = 0xf00, // '-' which could be a date separator or start of a time zone offset - - RegularTokenMask = 0x00ff, - SeparatorTokenMask = 0xff00, - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/DateTimeStyles.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/DateTimeStyles.cs deleted file mode 100644 index 94a1eeb71f4..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/DateTimeStyles.cs +++ /dev/null @@ -1,49 +0,0 @@ -// 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: Contains valid formats for DateTime recognized by -** the DateTime class' parsing code. -** -** -===========================================================*/ - -namespace System.Globalization -{ - [Flags] - public enum DateTimeStyles - { - // Bit flag indicating that leading whitespace is allowed. Character values - // 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, and 0x0020 are considered to be - // whitespace. - - - None = 0x00000000, - - AllowLeadingWhite = 0x00000001, - - AllowTrailingWhite = 0x00000002, // Bitflag indicating trailing whitespace is allowed. - - AllowInnerWhite = 0x00000004, - - AllowWhiteSpaces = AllowLeadingWhite | AllowInnerWhite | AllowTrailingWhite, - // When parsing a date/time string, if all year/month/day are missing, set the default date - // to 0001/1/1, instead of the current year/month/day. - - NoCurrentDateDefault = 0x00000008, - // When parsing a date/time string, if a timezone specifier ("GMT","Z","+xxxx", "-xxxx" exists), we will - // adjust the parsed time based to GMT. - - AdjustToUniversal = 0x00000010, - - AssumeLocal = 0x00000020, - - AssumeUniversal = 0x00000040, - // Attempt to preserve whether the input is unspecified, local or UTC - RoundtripKind = 0x00000080, - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/DaylightTime.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/DaylightTime.cs deleted file mode 100644 index 72a572c97de..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/DaylightTime.cs +++ /dev/null @@ -1,45 +0,0 @@ -// 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 -{ - // This class represents a starting/ending time for a period of daylight saving time. - public class DaylightTime - { - private readonly DateTime _start; - private readonly DateTime _end; - private readonly TimeSpan _delta; - - public DaylightTime(DateTime start, DateTime end, TimeSpan delta) - { - _start = start; - _end = end; - _delta = delta; - } - - // The start date of a daylight saving period. - public DateTime Start => _start; - - // The end date of a daylight saving period. - public DateTime End => _end; - - // Delta to stardard offset in ticks. - public TimeSpan Delta => _delta; - } - - // Value type version of DaylightTime - internal readonly struct DaylightTimeStruct - { - public DaylightTimeStruct(DateTime start, DateTime end, TimeSpan delta) - { - Start = start; - End = end; - Delta = delta; - } - - public readonly DateTime Start; - public readonly DateTime End; - public readonly TimeSpan Delta; - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/DigitShapes.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/DigitShapes.cs deleted file mode 100644 index 27ff391ca72..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/DigitShapes.cs +++ /dev/null @@ -1,13 +0,0 @@ -// 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 enum DigitShapes : int - { - Context = 0x0000, // The shape depends on the previous text in the same output. - None = 0x0001, // Gives full Unicode compatibility. - NativeNational = 0x0002 // National shapes - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/EastAsianLunisolarCalendar.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/EastAsianLunisolarCalendar.cs deleted file mode 100644 index 113fec1a7d6..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/EastAsianLunisolarCalendar.cs +++ /dev/null @@ -1,692 +0,0 @@ -// 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 abstract class EastAsianLunisolarCalendar : Calendar - { - private const int LeapMonth = 0; - private const int Jan1Month = 1; - private const int Jan1Date = 2; - private const int nDaysPerMonth = 3; - - // # of days so far in the solar year - private static readonly int[] s_daysToMonth365 = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; - - private static readonly int[] s_daysToMonth366 = { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 }; - - public override CalendarAlgorithmType AlgorithmType => CalendarAlgorithmType.LunisolarCalendar; - - /// <summary> - /// Return the year number in the 60-year cycle. - /// </summary> - public virtual int GetSexagenaryYear(DateTime time) - { - CheckTicksRange(time.Ticks); - - TimeToLunar(time, out int year, out _, out _); - return ((year - 4) % 60) + 1; - } - - /// <summary> - /// Return the celestial year from the 60-year cycle. - /// The returned value is from 1 ~ 10. - /// </summary> - public int GetCelestialStem(int sexagenaryYear) - { - if (sexagenaryYear < 1 || sexagenaryYear > 60) - { - throw new ArgumentOutOfRangeException( - nameof(sexagenaryYear), - sexagenaryYear, - SR.Format(SR.ArgumentOutOfRange_Range, 1, 60)); - } - - return ((sexagenaryYear - 1) % 10) + 1; - } - - /// <summary> - /// Return the Terrestial Branch from the 60-year cycle. - /// The returned value is from 1 ~ 12. - /// </summary> - public int GetTerrestrialBranch(int sexagenaryYear) - { - if (sexagenaryYear < 1 || sexagenaryYear > 60) - { - throw new ArgumentOutOfRangeException( - nameof(sexagenaryYear), - sexagenaryYear, - SR.Format(SR.ArgumentOutOfRange_Range, 1, 60)); - } - - return ((sexagenaryYear - 1) % 12) + 1; - } - - internal abstract int GetYearInfo(int LunarYear, int Index); - internal abstract int GetYear(int year, DateTime time); - internal abstract int GetGregorianYear(int year, int era); - - internal abstract int MinCalendarYear { get; } - internal abstract int MaxCalendarYear { get; } - internal abstract EraInfo[]? CalEraInfo { get; } - internal abstract DateTime MinDate { get; } - internal abstract DateTime MaxDate { get; } - - internal const int MaxCalendarMonth = 13; - internal const int MaxCalendarDay = 30; - - internal int MinEraCalendarYear(int era) - { - EraInfo[]? eraInfo = CalEraInfo; - if (eraInfo == null) - { - return MinCalendarYear; - } - - if (era == Calendar.CurrentEra) - { - era = CurrentEraValue; - } - - // Era has to be in the supported range otherwise we will throw exception in CheckEraRange() - if (era == GetEra(MinDate)) - { - return GetYear(MinCalendarYear, MinDate); - } - - for (int i = 0; i < eraInfo.Length; i++) - { - if (era == eraInfo[i].era) - { - return eraInfo[i].minEraYear; - } - } - - throw new ArgumentOutOfRangeException(nameof(era), era, SR.ArgumentOutOfRange_InvalidEraValue); - } - - internal int MaxEraCalendarYear(int era) - { - EraInfo[]? eraInfo = CalEraInfo; - if (eraInfo == null) - { - return MaxCalendarYear; - } - - if (era == Calendar.CurrentEra) - { - era = CurrentEraValue; - } - - // Era has to be in the supported range otherwise we will throw exception in CheckEraRange() - if (era == GetEra(MaxDate)) - { - return GetYear(MaxCalendarYear, MaxDate); - } - - for (int i = 0; i < eraInfo.Length; i++) - { - if (era == eraInfo[i].era) - { - return eraInfo[i].maxEraYear; - } - } - - throw new ArgumentOutOfRangeException(nameof(era), era, SR.ArgumentOutOfRange_InvalidEraValue); - } - - internal EastAsianLunisolarCalendar() - { - } - - internal void CheckTicksRange(long ticks) - { - if (ticks < MinSupportedDateTime.Ticks || ticks > MaxSupportedDateTime.Ticks) - { - throw new ArgumentOutOfRangeException( - "time", - ticks, - SR.Format(CultureInfo.InvariantCulture, SR.ArgumentOutOfRange_CalendarRange, - MinSupportedDateTime, MaxSupportedDateTime)); - } - } - - internal void CheckEraRange(int era) - { - if (era == Calendar.CurrentEra) - { - era = CurrentEraValue; - } - - if (era < GetEra(MinDate) || era > GetEra(MaxDate)) - { - throw new ArgumentOutOfRangeException(nameof(era), era, SR.ArgumentOutOfRange_InvalidEraValue); - } - } - - internal int CheckYearRange(int year, int era) - { - CheckEraRange(era); - year = GetGregorianYear(year, era); - - if (year < MinCalendarYear || year > MaxCalendarYear) - { - throw new ArgumentOutOfRangeException( - nameof(year), - year, - SR.Format(SR.ArgumentOutOfRange_Range, MinEraCalendarYear(era), MaxEraCalendarYear(era))); - } - return year; - } - - internal int CheckYearMonthRange(int year, int month, int era) - { - year = CheckYearRange(year, era); - - if (month == 13) - { - // Reject if there is no leap month this year - if (GetYearInfo(year, LeapMonth) == 0) - { - throw new ArgumentOutOfRangeException(nameof(month), month, SR.ArgumentOutOfRange_Month); - } - } - - if (month < 1 || month > 13) - { - throw new ArgumentOutOfRangeException(nameof(month), month, SR.ArgumentOutOfRange_Month); - } - - return year; - } - - internal int InternalGetDaysInMonth(int year, int month) - { - int mask = 0x8000; - - // convert the lunar day into a lunar month/date - mask >>= (month - 1); - if ((GetYearInfo(year, nDaysPerMonth) & mask) == 0) - { - return 29; - } - - return 30; - } - - /// <summary> - /// Returns the number of days in the month given by the year and - /// month arguments. - /// </summary> - public override int GetDaysInMonth(int year, int month, int era) - { - year = CheckYearMonthRange(year, month, era); - return InternalGetDaysInMonth(year, month); - } - - private static bool GregorianIsLeapYear(int y) - { - if ((y % 4) != 0) - { - return false; - } - if ((y % 100) != 0) - { - return true; - } - - return (y % 400) == 0; - } - - /// <summary> - /// Returns the date and time converted to a DateTime value. - /// Throws an exception if the n-tuple is invalid. - /// </summary> - public override DateTime ToDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int era) - { - year = CheckYearMonthRange(year, month, era); - int daysInMonth = InternalGetDaysInMonth(year, month); - if (day < 1 || day > daysInMonth) - { - throw new ArgumentOutOfRangeException( - nameof(day), - day, - SR.Format(SR.ArgumentOutOfRange_Day, daysInMonth, month)); - } - - if (!LunarToGregorian(year, month, day, out int gy, out int gm, out int gd)) - { - throw new ArgumentOutOfRangeException(null, SR.ArgumentOutOfRange_BadYearMonthDay); - } - - return new DateTime(gy, gm, gd, hour, minute, second, millisecond); - } - - /// <summary> - /// Calculates lunar calendar info for the given gregorian year, month, date. - /// The input date should be validated before calling this method. - /// </summary> - private void GregorianToLunar(int solarYear, int solarMonth, int solarDate, out int lunarYear, out int lunarMonth, out int lunarDate) - { - bool isLeapYear = GregorianIsLeapYear(solarYear); - int jan1Month; - int jan1Date; - - // Calculate the day number in the solar year. - int solarDay = isLeapYear ? s_daysToMonth366[solarMonth - 1] : s_daysToMonth365[solarMonth - 1]; - solarDay += solarDate; - - // Calculate the day number in the lunar year. - int lunarDay = solarDay; - lunarYear = solarYear; - if (lunarYear == (MaxCalendarYear + 1)) - { - lunarYear--; - lunarDay += (GregorianIsLeapYear(lunarYear) ? 366 : 365); - jan1Month = GetYearInfo(lunarYear, Jan1Month); - jan1Date = GetYearInfo(lunarYear, Jan1Date); - } - else - { - jan1Month = GetYearInfo(lunarYear, Jan1Month); - jan1Date = GetYearInfo(lunarYear, Jan1Date); - - // check if this solar date is actually part of the previous - // lunar year - if ((solarMonth < jan1Month) || - (solarMonth == jan1Month && solarDate < jan1Date)) - { - // the corresponding lunar day is actually part of the previous - // lunar year - lunarYear--; - - // add a solar year to the lunar day # - lunarDay += (GregorianIsLeapYear(lunarYear) ? 366 : 365); - - // update the new start of year - jan1Month = GetYearInfo(lunarYear, Jan1Month); - jan1Date = GetYearInfo(lunarYear, Jan1Date); - } - } - - // convert solar day into lunar day. - // subtract off the beginning part of the solar year which is not - // part of the lunar year. since this part is always in Jan or Feb, - // we don't need to handle Leap Year (LY only affects March - // and later). - lunarDay -= s_daysToMonth365[jan1Month - 1]; - lunarDay -= (jan1Date - 1); - - // convert the lunar day into a lunar month/date - int mask = 0x8000; - int yearInfo = GetYearInfo(lunarYear, nDaysPerMonth); - int days = ((yearInfo & mask) != 0) ? 30 : 29; - lunarMonth = 1; - while (lunarDay > days) - { - lunarDay -= days; - lunarMonth++; - mask >>= 1; - days = ((yearInfo & mask) != 0) ? 30 : 29; - } - lunarDate = lunarDay; - } - - /// <summary> - /// Convert from Lunar to Gregorian - /// </summary> - /// <remarks> - /// Highly inefficient, but it works based on the forward conversion - /// </remarks> - private bool LunarToGregorian(int lunarYear, int lunarMonth, int lunarDate, out int solarYear, out int solarMonth, out int solarDay) - { - if (lunarDate < 1 || lunarDate > 30) - { - solarYear = 0; - solarMonth = 0; - solarDay = 0; - return false; - } - - int numLunarDays = lunarDate - 1; - - // Add previous months days to form the total num of days from the first of the month. - for (int i = 1; i < lunarMonth; i++) - { - numLunarDays += InternalGetDaysInMonth(lunarYear, i); - } - - // Get Gregorian First of year - int jan1Month = GetYearInfo(lunarYear, Jan1Month); - int jan1Date = GetYearInfo(lunarYear, Jan1Date); - - // calc the solar day of year of 1 Lunar day - bool isLeapYear = GregorianIsLeapYear(lunarYear); - int[] days = isLeapYear ? s_daysToMonth366 : s_daysToMonth365; - - solarDay = jan1Date; - - if (jan1Month > 1) - { - solarDay += days[jan1Month - 1]; - } - - // Add the actual lunar day to get the solar day we want - solarDay += numLunarDays; - - if (solarDay > (365 + (isLeapYear ? 1 : 0))) - { - solarYear = lunarYear + 1; - solarDay -= (365 + (isLeapYear ? 1 : 0)); - } - else - { - solarYear = lunarYear; - } - - for (solarMonth = 1; solarMonth < 12; solarMonth++) - { - if (days[solarMonth] >= solarDay) - { - break; - } - } - - solarDay -= days[solarMonth - 1]; - return true; - } - - private DateTime LunarToTime(DateTime time, int year, int month, int day) - { - LunarToGregorian(year, month, day, out int gy, out int gm, out int gd); - return GregorianCalendar.GetDefaultInstance().ToDateTime(gy, gm, gd, time.Hour, time.Minute, time.Second, time.Millisecond); - } - - private void TimeToLunar(DateTime time, out int year, out int month, out int day) - { - Calendar gregorianCalendar = GregorianCalendar.GetDefaultInstance(); - int gy = gregorianCalendar.GetYear(time); - int gm = gregorianCalendar.GetMonth(time); - int gd = gregorianCalendar.GetDayOfMonth(time); - - GregorianToLunar(gy, gm, gd, out year, out month, out day); - } - - /// <summary> - /// 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. - /// </summary> - public override DateTime AddMonths(DateTime time, int months) - { - if (months < -120000 || months > 120000) - { - throw new ArgumentOutOfRangeException( - nameof(months), - months, - SR.Format(SR.ArgumentOutOfRange_Range, -120000, 120000)); - } - - CheckTicksRange(time.Ticks); - TimeToLunar(time, out int y, out int m, out int d); - - int i = m + months; - if (i > 0) - { - int monthsInYear = InternalIsLeapYear(y) ? 13 : 12; - - while (i - monthsInYear > 0) - { - i -= monthsInYear; - y++; - monthsInYear = InternalIsLeapYear(y) ? 13 : 12; - } - m = i; - } - else - { - int monthsInYear; - while (i <= 0) - { - monthsInYear = InternalIsLeapYear(y - 1) ? 13 : 12; - i += monthsInYear; - y--; - } - m = i; - } - - int days = InternalGetDaysInMonth(y, m); - if (d > days) - { - d = days; - } - DateTime dt = LunarToTime(time, y, m, d); - - CheckAddResult(dt.Ticks, MinSupportedDateTime, MaxSupportedDateTime); - return dt; - } - - public override DateTime AddYears(DateTime time, int years) - { - CheckTicksRange(time.Ticks); - TimeToLunar(time, out int y, out int m, out int d); - - y += years; - - if (m == 13 && !InternalIsLeapYear(y)) - { - m = 12; - d = InternalGetDaysInMonth(y, m); - } - int daysInMonths = InternalGetDaysInMonth(y, m); - if (d > daysInMonths) - { - d = daysInMonths; - } - - DateTime dt = LunarToTime(time, y, m, d); - CheckAddResult(dt.Ticks, MinSupportedDateTime, MaxSupportedDateTime); - return dt; - } - - /// <summary> - /// Returns the day-of-year part of the specified DateTime. The returned value - /// is an integer between 1 and [354|355 |383|384]. - /// </summary> - public override int GetDayOfYear(DateTime time) - { - CheckTicksRange(time.Ticks); - TimeToLunar(time, out int y, out int m, out int d); - - for (int i = 1; i < m; i++) - { - d += InternalGetDaysInMonth(y, i); - } - return d; - } - - /// <summary> - /// Returns the day-of-month part of the specified DateTime. The returned - /// value is an integer between 1 and 29 or 30. - /// </summary> - public override int GetDayOfMonth(DateTime time) - { - CheckTicksRange(time.Ticks); - - TimeToLunar(time, out _, out _, out int d); - - return d; - } - - /// <summary> - /// Returns the number of days in the year given by the year argument for the current era. - /// </summary> - public override int GetDaysInYear(int year, int era) - { - year = CheckYearRange(year, era); - - int days = 0; - int monthsInYear = InternalIsLeapYear(year) ? 13 : 12; - - while (monthsInYear != 0) - { - days += InternalGetDaysInMonth(year, monthsInYear--); - } - - return days; - } - - /// <summary> - /// Returns the month part of the specified DateTime. - /// The returned value is an integer between 1 and 13. - /// </summary> - public override int GetMonth(DateTime time) - { - CheckTicksRange(time.Ticks); - - TimeToLunar(time, out _, out int m, out _); - - return m; - } - - /// <summary> - /// Returns the year part of the specified DateTime. - /// The returned value is an integer between 1 and MaxCalendarYear. - /// </summary> - public override int GetYear(DateTime time) - { - CheckTicksRange(time.Ticks); - - TimeToLunar(time, out int y, out _, out _); - - return GetYear(y, time); - } - - /// <summary> - /// 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. - /// </summary> - public override DayOfWeek GetDayOfWeek(DateTime time) - { - CheckTicksRange(time.Ticks); - return (DayOfWeek)((int)(time.Ticks / Calendar.TicksPerDay + 1) % 7); - } - - /// <summary> - /// Returns the number of months in the specified year and era. - /// </summary> - public override int GetMonthsInYear(int year, int era) - { - year = CheckYearRange(year, era); - return InternalIsLeapYear(year) ? 13 : 12; - } - - /// <summary> - /// 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. - /// </summary> - public override bool IsLeapDay(int year, int month, int day, int era) - { - year = CheckYearMonthRange(year, month, era); - int daysInMonth = InternalGetDaysInMonth(year, month); - - if (day < 1 || day > daysInMonth) - { - throw new ArgumentOutOfRangeException( - nameof(day), - day, - SR.Format(SR.ArgumentOutOfRange_Day, daysInMonth, month)); - } - - int m = GetYearInfo(year, LeapMonth); - return (m != 0) && (month == (m + 1)); - } - - /// <summary> - /// 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. - /// </summary> - public override bool IsLeapMonth(int year, int month, int era) - { - year = CheckYearMonthRange(year, month, era); - int m = GetYearInfo(year, LeapMonth); - return (m != 0) && (month == (m + 1)); - } - - /// <summary> - /// Returns the leap month in a calendar year of the specified era. This method returns 0 - /// if this year is not a leap year. - /// </summary> - public override int GetLeapMonth(int year, int era) - { - year = CheckYearRange(year, era); - int month = GetYearInfo(year, LeapMonth); - return month > 0 ? month + 1 : 0; - } - - internal bool InternalIsLeapYear(int year) - { - return GetYearInfo(year, LeapMonth) != 0; - } - - /// <summary> - /// 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. - /// </summary> - public override bool IsLeapYear(int year, int era) - { - year = CheckYearRange(year, era); - return InternalIsLeapYear(year); - } - - private const int DefaultGregorianTwoDigitYearMax = 2029; - - public override int TwoDigitYearMax - { - get - { - if (_twoDigitYearMax == -1) - { - _twoDigitYearMax = GetSystemTwoDigitYearSetting(BaseCalendarID, GetYear(new DateTime(DefaultGregorianTwoDigitYearMax, 1, 1))); - } - - return _twoDigitYearMax; - } - set - { - VerifyWritable(); - if (value < 99 || value > MaxCalendarYear) - { - throw new ArgumentOutOfRangeException( - nameof(value), - value, - SR.Format(SR.ArgumentOutOfRange_Range, 99, MaxCalendarYear)); - } - - _twoDigitYearMax = value; - } - } - - public override int ToFourDigitYear(int year) - { - if (year < 0) - { - throw new ArgumentOutOfRangeException( - nameof(year), - year, - SR.ArgumentOutOfRange_NeedNonNegNum); - } - - year = base.ToFourDigitYear(year); - CheckYearRange(year, CurrentEra); - return year; - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/GlobalizationExtensions.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/GlobalizationExtensions.cs deleted file mode 100644 index 2e61b5394ab..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/GlobalizationExtensions.cs +++ /dev/null @@ -1,29 +0,0 @@ -// 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 static class GlobalizationExtensions - { - public static StringComparer GetStringComparer(this CompareInfo compareInfo, CompareOptions options) - { - if (compareInfo == null) - { - throw new ArgumentNullException(nameof(compareInfo)); - } - - if (options == CompareOptions.Ordinal) - { - return StringComparer.Ordinal; - } - - if (options == CompareOptions.OrdinalIgnoreCase) - { - return StringComparer.OrdinalIgnoreCase; - } - - return new CultureAwareComparer(compareInfo, options); - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/GregorianCalendar.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/GregorianCalendar.cs deleted file mode 100644 index 6767b9a26a2..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/GregorianCalendar.cs +++ /dev/null @@ -1,488 +0,0 @@ -// 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 -{ - /// <remarks> - /// This calendar recognizes two era values: - /// 0 CurrentEra (AD) - /// 1 BeforeCurrentEra (BC) - /// </remarks> - public class GregorianCalendar : Calendar - { - public const int ADEra = 1; - - // This is the min Gregorian year can be represented by the DateTime class. - // The limitation is derived from the DateTime class. - internal const int MinYear = 1; - - // This is the max Gregorian year can be represented by the DateTime class. - // The limitation is derived from the DateTime class. - internal const int MaxYear = 9999; - - private GregorianCalendarTypes _type; - - private static readonly int[] DaysToMonth365 = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }; - - private static readonly int[] DaysToMonth366 = { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }; - - private static volatile Calendar? s_defaultInstance; - - public override DateTime MinSupportedDateTime => DateTime.MinValue; - - public override DateTime MaxSupportedDateTime => DateTime.MaxValue; - - public override CalendarAlgorithmType AlgorithmType => CalendarAlgorithmType.SolarCalendar; - - /// <summary> - /// Internal method to provide a default intance of GregorianCalendar. - /// Used by NLS+ implementation - /// </summary> - internal static Calendar GetDefaultInstance() => s_defaultInstance ??= new GregorianCalendar(); - - public GregorianCalendar() : this(GregorianCalendarTypes.Localized) - { - } - - public GregorianCalendar(GregorianCalendarTypes type) - { - if (type < GregorianCalendarTypes.Localized || type > GregorianCalendarTypes.TransliteratedFrench) - { - throw new ArgumentOutOfRangeException( - nameof(type), - type, - SR.Format(SR.ArgumentOutOfRange_Range, GregorianCalendarTypes.Localized, GregorianCalendarTypes.TransliteratedFrench)); - } - - _type = type; - } - - public virtual GregorianCalendarTypes CalendarType - { - get => _type; - set - { - VerifyWritable(); - if (value < GregorianCalendarTypes.Localized || value > GregorianCalendarTypes.TransliteratedFrench) - { - throw new ArgumentOutOfRangeException( - nameof(value), - value, - SR.Format(SR.ArgumentOutOfRange_Range, GregorianCalendarTypes.Localized, GregorianCalendarTypes.TransliteratedFrench)); - } - - _type = value; - } - } - - internal override CalendarId ID => - // By returning different ID for different variations of GregorianCalendar, - // we can support the Transliterated Gregorian calendar. - // DateTimeFormatInfo will use this ID to get formatting information about - // the calendar. - (CalendarId)_type; - - /// <summary> - /// Gets the absolute date for the given Gregorian date. The absolute date means - /// the number of days from January 1st, 1 A.D. - /// </summary> - /// <remarks> - /// This is an internal method used by DateToTicks() and the calculations of Hijri and Hebrew calendars. - /// Number of Days in Prior Years (both common and leap years) + - /// Number of Days in Prior Months of Current Year + - /// Number of Days in Current Month - /// </remarks> - internal static long GetAbsoluteDate(int year, int month, int day) - { - if (year >= 1 && year <= MaxYear && month >= 1 && month <= 12) - { - int[] days = (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) ? DaysToMonth366 : DaysToMonth365; - if (day >= 1 && (day <= days[month] - days[month - 1])) - { - int y = year - 1; - return y * 365 + y / 4 - y / 100 + y / 400 + days[month - 1] + day - 1; - } - } - - throw new ArgumentOutOfRangeException(null, SR.ArgumentOutOfRange_BadYearMonthDay); - } - - /// <summary> - /// Returns the tick count corresponding to the given year, month, and day. - /// Will check the if the parameters are valid. - /// </summary> - internal virtual long DateToTicks(int year, int month, int day) - { - return GetAbsoluteDate(year, month, day) * TicksPerDay; - } - - /// <summary> - /// 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. - /// </summary> - public override DateTime AddMonths(DateTime time, int months) - { - if (months < -120000 || months > 120000) - { - throw new ArgumentOutOfRangeException( - nameof(months), - months, - SR.Format(SR.ArgumentOutOfRange_Range, -120000, 120000)); - } - - time.GetDatePart(out int y, out int m, out int d); - int i = m - 1 + months; - if (i >= 0) - { - m = i % 12 + 1; - y += i / 12; - } - else - { - m = 12 + (i + 1) % 12; - y += (i - 11) / 12; - } - - int[] daysArray = (y % 4 == 0 && (y % 100 != 0 || y % 400 == 0)) ? DaysToMonth366 : DaysToMonth365; - int days = (daysArray[m] - daysArray[m - 1]); - - if (d > days) - { - d = days; - } - long ticks = DateToTicks(y, m, d) + time.Ticks % TicksPerDay; - Calendar.CheckAddResult(ticks, MinSupportedDateTime, MaxSupportedDateTime); - - return new DateTime(ticks); - } - - /// <summary> - /// 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. - /// </summary> - public override DateTime AddYears(DateTime time, int years) - { - return AddMonths(time, years * 12); - } - - /// <summary> - /// Returns the day-of-month part of the specified DateTime. The returned - /// value is an integer between 1 and 31. - /// </summary> - public override int GetDayOfMonth(DateTime time) => time.Day; - - /// <summary> - /// 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. - /// </summary> - public override DayOfWeek GetDayOfWeek(DateTime time) - { - return (DayOfWeek)((int)(time.Ticks / TicksPerDay + 1) % 7); - } - - /// <summary> - /// Returns the day-of-year part of the specified DateTime. The returned value - /// is an integer between 1 and 366. - /// </summary> - public override int GetDayOfYear(DateTime time) => time.DayOfYear; - - /// <summary> - /// Returns the number of days in the month given by the year and - /// month arguments. - /// </summary> - public override int GetDaysInMonth(int year, int month, int era) - { - if (era != CurrentEra && era != ADEra) - { - throw new ArgumentOutOfRangeException(nameof(era), era, SR.ArgumentOutOfRange_InvalidEraValue); - } - - if (year < 1 || year > MaxYear) - { - throw new ArgumentOutOfRangeException( - nameof(year), - year, - SR.Format(SR.ArgumentOutOfRange_Range, 1, MaxYear)); - } - if (month < 1 || month > 12) - { - throw new ArgumentOutOfRangeException(nameof(month), month, SR.ArgumentOutOfRange_Month); - } - - int[] days = ((year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) ? DaysToMonth366 : DaysToMonth365); - return days[month] - days[month - 1]; - } - - /// <summary> - /// Returns the number of days in the year given by the year argument for - /// the current era. - /// </summary> - public override int GetDaysInYear(int year, int era) - { - if (era != CurrentEra && era != ADEra) - { - throw new ArgumentOutOfRangeException(nameof(era), era, SR.ArgumentOutOfRange_InvalidEraValue); - } - - if (year < 1 || year > MaxYear) - { - throw new ArgumentOutOfRangeException( - nameof(year), - year, - SR.Format(SR.ArgumentOutOfRange_Range, 1, MaxYear)); - } - - return (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) ? 366 : 365; - } - - public override int GetEra(DateTime time) => ADEra; - - public override int[] Eras => new int[] { ADEra }; - - /// <summary> - /// Returns the month part of the specified DateTime. - /// The returned value is an integer between 1 and 12. - /// </summary> - public override int GetMonth(DateTime time) => time.Month; - - /// <summary> - /// Returns the number of months in the specified year and era. - /// </summary> - public override int GetMonthsInYear(int year, int era) - { - if (era != CurrentEra && era != ADEra) - { - throw new ArgumentOutOfRangeException(nameof(era), era, SR.ArgumentOutOfRange_InvalidEraValue); - } - if (year < 1 || year > MaxYear) - { - throw new ArgumentOutOfRangeException( - nameof(year), - year, - SR.Format(SR.ArgumentOutOfRange_Range, 1, MaxYear)); - } - - return 12; - } - - /// <summary> - /// Returns the year part of the specified DateTime. The returned value is an - /// integer between 1 and 9999. - /// </summary> - public override int GetYear(DateTime time) => time.Year; - - internal override bool IsValidYear(int year, int era) => year >= 1 && year <= MaxYear; - - internal override bool IsValidDay(int year, int month, int day, int era) - { - if ((era != CurrentEra && era != ADEra) || - year < 1 || year > MaxYear || - month < 1 || month > 12 || - day < 1) - { - return false; - } - - int[] days = (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) ? DaysToMonth366 : DaysToMonth365; - return day <= (days[month] - days[month - 1]); - } - - /// <summary> - /// 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. - /// </summary> - public override bool IsLeapDay(int year, int month, int day, int era) - { - if (month < 1 || month > 12) - { - throw new ArgumentOutOfRangeException( - nameof(month), - month, - SR.Format(SR.ArgumentOutOfRange_Range, 1, 12)); - } - - if (era != CurrentEra && era != ADEra) - { - throw new ArgumentOutOfRangeException(nameof(era), era, SR.ArgumentOutOfRange_InvalidEraValue); - } - if (year < 1 || year > MaxYear) - { - throw new ArgumentOutOfRangeException( - nameof(year), - year, - SR.Format(SR.ArgumentOutOfRange_Range, 1, MaxYear)); - } - if (day < 1 || day > GetDaysInMonth(year, month)) - { - throw new ArgumentOutOfRangeException( - nameof(day), - day, - SR.Format(SR.ArgumentOutOfRange_Range, 1, GetDaysInMonth(year, month))); - } - - return IsLeapYear(year) && month == 2 && day == 29; - } - - /// <summary> - /// 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. - /// </summary> - public override int GetLeapMonth(int year, int era) - { - if (era != CurrentEra && era != ADEra) - { - throw new ArgumentOutOfRangeException(nameof(era), era, SR.ArgumentOutOfRange_InvalidEraValue); - } - if (year < 1 || year > MaxYear) - { - throw new ArgumentOutOfRangeException( - nameof(year), - year, - SR.Format(SR.ArgumentOutOfRange_Range, 1, MaxYear)); - } - - return 0; - } - - /// <summary> - /// 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. - /// </summary> - public override bool IsLeapMonth(int year, int month, int era) - { - if (era != CurrentEra && era != ADEra) - { - throw new ArgumentOutOfRangeException(nameof(era), era, SR.ArgumentOutOfRange_InvalidEraValue); - } - if (year < 1 || year > MaxYear) - { - throw new ArgumentOutOfRangeException( - nameof(year), - year, - SR.Format(SR.ArgumentOutOfRange_Range, 1, MaxYear)); - } - if (month < 1 || month > 12) - { - throw new ArgumentOutOfRangeException( - nameof(month), - month, - SR.Format(SR.ArgumentOutOfRange_Range, 1, 12)); - } - - return false; - } - - /// <summary> - /// 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. - /// </summary> - public override bool IsLeapYear(int year, int era) - { - if (era != CurrentEra && era != ADEra) - { - throw new ArgumentOutOfRangeException(nameof(era), era, SR.ArgumentOutOfRange_InvalidEraValue); - } - if (year < 1 || year > MaxYear) - { - throw new ArgumentOutOfRangeException( - nameof(year), - year, - SR.Format(SR.ArgumentOutOfRange_Range, 1, MaxYear)); - } - - return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0); - } - - /// <summary> - /// Returns the date and time converted to a DateTime value. - /// Throws an exception if the n-tuple is invalid. - /// </summary> - public override DateTime ToDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int era) - { - if (era != CurrentEra && era != ADEra) - { - throw new ArgumentOutOfRangeException(nameof(era), era, SR.ArgumentOutOfRange_InvalidEraValue); - } - - return new DateTime(year, month, day, hour, minute, second, millisecond); - } - - internal override bool TryToDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int era, out DateTime result) - { - if (era != CurrentEra && era != ADEra) - { - result = DateTime.MinValue; - return false; - } - - return DateTime.TryCreate(year, month, day, hour, minute, second, millisecond, out result); - } - - private const int DefaultTwoDigitYearMax = 2029; - - public override int TwoDigitYearMax - { - get - { - if (_twoDigitYearMax == -1) - { - _twoDigitYearMax = GetSystemTwoDigitYearSetting(ID, DefaultTwoDigitYearMax); - } - - return _twoDigitYearMax; - } - set - { - VerifyWritable(); - if (value < 99 || value > MaxYear) - { - throw new ArgumentOutOfRangeException( - nameof(value), - value, - SR.Format(SR.ArgumentOutOfRange_Range, 99, MaxYear)); - } - _twoDigitYearMax = value; - } - } - - public override int ToFourDigitYear(int year) - { - if (year < 0) - { - throw new ArgumentOutOfRangeException(nameof(year), year, SR.ArgumentOutOfRange_NeedNonNegNum); - } - if (year > MaxYear) - { - throw new ArgumentOutOfRangeException( - nameof(year), - year, - SR.Format(SR.ArgumentOutOfRange_Range, 1, MaxYear)); - } - - return base.ToFourDigitYear(year); - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/GregorianCalendarHelper.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/GregorianCalendarHelper.cs deleted file mode 100644 index 589a8b662f0..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/GregorianCalendarHelper.cs +++ /dev/null @@ -1,660 +0,0 @@ -// 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 -{ - // Gregorian Calendars use Era Info - internal class EraInfo - { - internal int era; // The value of the era. - internal long ticks; // The time in ticks when the era starts - internal int yearOffset; // The offset to Gregorian year when the era starts. - // Gregorian Year = Era Year + yearOffset - // Era Year = Gregorian Year - yearOffset - internal int minEraYear; // Min year value in this era. Generally, this value is 1, but this may - // be affected by the DateTime.MinValue; - internal int maxEraYear; // Max year value in this era. (== the year length of the era + 1) - - internal string? eraName; // The era name - internal string? abbrevEraName; // Abbreviated Era Name - internal string? englishEraName; // English era name - - internal EraInfo(int era, int startYear, int startMonth, int startDay, int yearOffset, int minEraYear, int maxEraYear) - { - this.era = era; - this.yearOffset = yearOffset; - this.minEraYear = minEraYear; - this.maxEraYear = maxEraYear; - this.ticks = new DateTime(startYear, startMonth, startDay).Ticks; - } - - internal EraInfo(int era, int startYear, int startMonth, int startDay, int yearOffset, int minEraYear, int maxEraYear, - string eraName, string abbrevEraName, string englishEraName) - { - this.era = era; - this.yearOffset = yearOffset; - this.minEraYear = minEraYear; - this.maxEraYear = maxEraYear; - this.ticks = new DateTime(startYear, startMonth, startDay).Ticks; - this.eraName = eraName; - this.abbrevEraName = abbrevEraName; - this.englishEraName = englishEraName; - } - } - - // This calendar recognizes two era values: - // 0 CurrentEra (AD) - // 1 BeforeCurrentEra (BC) - internal class GregorianCalendarHelper - { - // 1 tick = 100ns = 10E-7 second - // Number of 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; - - internal const int DatePartYear = 0; - internal const int DatePartDayOfYear = 1; - internal const int DatePartMonth = 2; - internal const int DatePartDay = 3; - - // - // This is the max Gregorian year can be represented by DateTime class. The limitation - // is derived from DateTime class. - // - internal int MaxYear => m_maxYear; - - internal static readonly int[] DaysToMonth365 = - { - 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 - }; - - internal static readonly int[] DaysToMonth366 = - { - 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 - }; - - internal int m_maxYear; - internal int m_minYear; - internal Calendar m_Cal; - - internal EraInfo[] m_EraInfo; - internal int[]? m_eras = null; - - // Construct an instance of gregorian calendar. - internal GregorianCalendarHelper(Calendar cal, EraInfo[] eraInfo) - { - m_Cal = cal; - m_EraInfo = eraInfo; - m_maxYear = m_EraInfo[0].maxEraYear; - m_minYear = m_EraInfo[0].minEraYear; - } - - // EraInfo.yearOffset: The offset to Gregorian year when the era starts. Gregorian Year = Era Year + yearOffset - // Era Year = Gregorian Year - yearOffset - // EraInfo.minEraYear: Min year value in this era. Generally, this value is 1, but this may be affected by the DateTime.MinValue; - // EraInfo.maxEraYear: Max year value in this era. (== the year length of the era + 1) - private int GetYearOffset(int year, int era, bool throwOnError) - { - if (year < 0) - { - if (throwOnError) - { - throw new ArgumentOutOfRangeException(nameof(year), SR.ArgumentOutOfRange_NeedNonNegNum); - } - return -1; - } - - if (era == Calendar.CurrentEra) - { - era = m_Cal.CurrentEraValue; - } - - for (int i = 0; i < m_EraInfo.Length; i++) - { - if (era == m_EraInfo[i].era) - { - if (year >= m_EraInfo[i].minEraYear) - { - if (year <= m_EraInfo[i].maxEraYear) - { - return m_EraInfo[i].yearOffset; - } - else if (!LocalAppContextSwitches.EnforceJapaneseEraYearRanges) - { - // If we got the year number exceeding the era max year number, this still possible be valid as the date can be created before - // introducing new eras after the era we are checking. we'll loop on the eras after the era we have and ensure the year - // can exist in one of these eras. otherwise, we'll throw. - // Note, we always return the offset associated with the requested era. - // - // Here is some example: - // if we are getting the era number 4 (Heisei) and getting the year number 32. if the era 4 has year range from 1 to 31 - // then year 32 exceeded the range of era 4 and we'll try to find out if the years difference (32 - 31 = 1) would lay in - // the subsequent eras (e.g era 5 and up) - - int remainingYears = year - m_EraInfo[i].maxEraYear; - - for (int j = i - 1; j >= 0; j--) - { - if (remainingYears <= m_EraInfo[j].maxEraYear) - { - return m_EraInfo[i].yearOffset; - } - remainingYears -= m_EraInfo[j].maxEraYear; - } - } - } - - if (throwOnError) - { - throw new ArgumentOutOfRangeException( - nameof(year), - SR.Format( - SR.ArgumentOutOfRange_Range, - m_EraInfo[i].minEraYear, - m_EraInfo[i].maxEraYear)); - } - - break; // no need to iterate more on eras. - } - } - - if (throwOnError) - { - throw new ArgumentOutOfRangeException(nameof(era), SR.ArgumentOutOfRange_InvalidEraValue); - } - return -1; - } - - /*=================================GetGregorianYear========================== - **Action: Get the Gregorian year value for the specified year in an era. - **Returns: The Gregorian year value. - **Arguments: - ** year the year value in Japanese calendar - ** era the Japanese emperor era value. - **Exceptions: - ** ArgumentOutOfRangeException if year value is invalid or era value is invalid. - ============================================================================*/ - - internal int GetGregorianYear(int year, int era) - { - return GetYearOffset(year, era, throwOnError: true) + year; - } - - internal bool IsValidYear(int year, int era) - { - return GetYearOffset(year, era, throwOnError: false) >= 0; - } - - // Returns a given date part of this DateTime. This method is used - // to compute the year, day-of-year, month, or day part. - internal virtual int GetDatePart(long ticks, int part) - { - CheckTicksRange(ticks); - // n = number of days since 1/1/0001 - int n = (int)(ticks / TicksPerDay); - // y400 = number of whole 400-year periods since 1/1/0001 - int y400 = n / DaysPer400Years; - // n = day number within 400-year period - n -= y400 * DaysPer400Years; - // y100 = number of whole 100-year periods within 400-year period - int y100 = n / DaysPer100Years; - // Last 100-year period has an extra day, so decrement result if 4 - if (y100 == 4) y100 = 3; - // n = day number within 100-year period - n -= y100 * DaysPer100Years; - // y4 = number of whole 4-year periods within 100-year period - int y4 = n / DaysPer4Years; - // n = day number within 4-year period - n -= y4 * DaysPer4Years; - // y1 = number of whole years within 4-year period - int y1 = n / DaysPerYear; - // Last year has an extra day, so decrement result if 4 - if (y1 == 4) y1 = 3; - // If year was requested, compute and return it - if (part == DatePartYear) - { - return y400 * 400 + y100 * 100 + y4 * 4 + y1 + 1; - } - // n = day number within year - n -= y1 * DaysPerYear; - // If day-of-year was requested, return it - if (part == DatePartDayOfYear) - { - return n + 1; - } - // Leap year calculation looks different from IsLeapYear since y1, y4, - // and y100 are relative to year 1, not year 0 - bool leapYear = (y1 == 3 && (y4 != 24 || y100 == 3)); - int[] days = leapYear ? DaysToMonth366 : DaysToMonth365; - // All months have less than 32 days, so n >> 5 is a good conservative - // estimate for the month - int m = (n >> 5) + 1; - // m = 1-based month number - while (n >= days[m]) m++; - // If month was requested, return it - if (part == DatePartMonth) return m; - // Return 1-based day-of-month - return n - days[m - 1] + 1; - } - - /*=================================GetAbsoluteDate========================== - **Action: Gets the absolute date for the given Gregorian date. The absolute date means - ** the number of days from January 1st, 1 A.D. - **Returns: the absolute date - **Arguments: - ** year the Gregorian year - ** month the Gregorian month - ** day the day - **Exceptions: - ** ArgumentOutOfRangException if year, month, day value is valid. - **Note: - ** This is an internal method used by DateToTicks() and the calculations of Hijri and Hebrew calendars. - ** Number of Days in Prior Years (both common and leap years) + - ** Number of Days in Prior Months of Current Year + - ** Number of Days in Current Month - ** - ============================================================================*/ - - internal static long GetAbsoluteDate(int year, int month, int day) - { - if (year >= 1 && year <= 9999 && month >= 1 && month <= 12) - { - int[] days = (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) ? DaysToMonth366 : DaysToMonth365; - if (day >= 1 && (day <= days[month] - days[month - 1])) - { - int y = year - 1; - int absoluteDate = y * 365 + y / 4 - y / 100 + y / 400 + days[month - 1] + day - 1; - return absoluteDate; - } - } - throw new ArgumentOutOfRangeException(null, SR.ArgumentOutOfRange_BadYearMonthDay); - } - - // Returns the tick count corresponding to the given year, month, and day. - // Will check the if the parameters are valid. - internal static long DateToTicks(int year, int month, int day) - { - return GetAbsoluteDate(year, month, day) * TicksPerDay; - } - - // 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) - { - // TimeSpan.TimeToTicks is a family access function which does no error checking, so - // we need to put some error checking out here. - if (hour >= 0 && hour < 24 && minute >= 0 && minute < 60 && second >= 0 && second < 60) - { - if (millisecond < 0 || millisecond >= MillisPerSecond) - { - throw new ArgumentOutOfRangeException( - nameof(millisecond), - SR.Format( - SR.ArgumentOutOfRange_Range, - 0, - MillisPerSecond - 1)); - } - return InternalGlobalizationHelper.TimeToTicks(hour, minute, second) + millisecond * TicksPerMillisecond; - } - throw new ArgumentOutOfRangeException(null, SR.ArgumentOutOfRange_BadHourMinuteSecond); - } - - internal void CheckTicksRange(long ticks) - { - if (ticks < m_Cal.MinSupportedDateTime.Ticks || ticks > m_Cal.MaxSupportedDateTime.Ticks) - { - throw new ArgumentOutOfRangeException( - "time", - SR.Format( - CultureInfo.InvariantCulture, - SR.ArgumentOutOfRange_CalendarRange, - m_Cal.MinSupportedDateTime, - m_Cal.MaxSupportedDateTime)); - } - } - - // 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 DateTime AddMonths(DateTime time, int months) - { - if (months < -120000 || months > 120000) - { - throw new ArgumentOutOfRangeException( - nameof(months), - SR.Format( - SR.ArgumentOutOfRange_Range, - -120000, - 120000)); - } - CheckTicksRange(time.Ticks); - - int y = GetDatePart(time.Ticks, DatePartYear); - int m = GetDatePart(time.Ticks, DatePartMonth); - int d = GetDatePart(time.Ticks, DatePartDay); - int i = m - 1 + months; - if (i >= 0) - { - m = i % 12 + 1; - y += i / 12; - } - else - { - m = 12 + (i + 1) % 12; - y += (i - 11) / 12; - } - int[] daysArray = (y % 4 == 0 && (y % 100 != 0 || y % 400 == 0)) ? DaysToMonth366 : DaysToMonth365; - int days = (daysArray[m] - daysArray[m - 1]); - - if (d > days) - { - d = days; - } - long ticks = DateToTicks(y, m, d) + (time.Ticks % TicksPerDay); - Calendar.CheckAddResult(ticks, m_Cal.MinSupportedDateTime, m_Cal.MaxSupportedDateTime); - return new DateTime(ticks); - } - - // 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 DateTime AddYears(DateTime time, int years) - { - return AddMonths(time, years * 12); - } - - // Returns the day-of-month part of the specified DateTime. The returned - // value is an integer between 1 and 31. - // - public int GetDayOfMonth(DateTime time) - { - return GetDatePart(time.Ticks, DatePartDay); - } - - // 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 DayOfWeek GetDayOfWeek(DateTime time) - { - CheckTicksRange(time.Ticks); - return (DayOfWeek)((time.Ticks / TicksPerDay + 1) % 7); - } - - // Returns the day-of-year part of the specified DateTime. The returned value - // is an integer between 1 and 366. - // - public int GetDayOfYear(DateTime time) - { - return GetDatePart(time.Ticks, DatePartDayOfYear); - } - - // Returns the number of days in the month given by the year and - // month arguments. - // - public int GetDaysInMonth(int year, int month, int era) - { - // - // Convert year/era value to Gregorain year value. - // - year = GetGregorianYear(year, era); - if (month < 1 || month > 12) - { - throw new ArgumentOutOfRangeException(nameof(month), SR.ArgumentOutOfRange_Month); - } - int[] days = ((year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) ? DaysToMonth366 : DaysToMonth365); - return days[month] - days[month - 1]; - } - - // Returns the number of days in the year given by the year argument for the current era. - // - - public int GetDaysInYear(int year, int era) - { - // - // Convert year/era value to Gregorain year value. - // - year = GetGregorianYear(year, era); - return (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) ? 366 : 365; - } - - // Returns the era for the specified DateTime value. - public int GetEra(DateTime time) - { - long ticks = time.Ticks; - // The assumption here is that m_EraInfo is listed in reverse order. - for (int i = 0; i < m_EraInfo.Length; i++) - { - if (ticks >= m_EraInfo[i].ticks) - { - return m_EraInfo[i].era; - } - } - throw new ArgumentOutOfRangeException(nameof(time), SR.ArgumentOutOfRange_Era); - } - - public int[] Eras - { - get - { - if (m_eras == null) - { - m_eras = new int[m_EraInfo.Length]; - for (int i = 0; i < m_EraInfo.Length; i++) - { - m_eras[i] = m_EraInfo[i].era; - } - } - return (int[])m_eras.Clone(); - } - } - - // Returns the month part of the specified DateTime. The returned value is an - // integer between 1 and 12. - // - public int GetMonth(DateTime time) - { - return GetDatePart(time.Ticks, DatePartMonth); - } - - // Returns the number of months in the specified year and era. - // Always return 12. - public int GetMonthsInYear(int year, int era) - { - ValidateYearInEra(year, era); - return 12; - } - - // Returns the year part of the specified DateTime. The returned value is an - // integer between 1 and 9999. - // - public int GetYear(DateTime time) - { - long ticks = time.Ticks; - int year = GetDatePart(ticks, DatePartYear); - for (int i = 0; i < m_EraInfo.Length; i++) - { - if (ticks >= m_EraInfo[i].ticks) - { - return year - m_EraInfo[i].yearOffset; - } - } - throw new ArgumentException(SR.Argument_NoEra); - } - - // Returns the year that match the specified Gregorian year. The returned value is an - // integer between 1 and 9999. - // - public int GetYear(int year, DateTime time) - { - long ticks = time.Ticks; - for (int i = 0; i < m_EraInfo.Length; i++) - { - // while calculating dates with JapaneseLuniSolarCalendar, we can run into cases right after the start of the era - // and still belong to the month which is started in previous era. Calculating equivalent calendar date will cause - // using the new era info which will have the year offset equal to the year we are calculating year = m_EraInfo[i].yearOffset - // which will end up with zero as calendar year. - // We should use the previous era info instead to get the right year number. Example of such date is Feb 2nd 1989 - if (ticks >= m_EraInfo[i].ticks && year > m_EraInfo[i].yearOffset) - { - return year - m_EraInfo[i].yearOffset; - } - } - throw new ArgumentException(SR.Argument_NoEra); - } - - // 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 bool IsLeapDay(int year, int month, int day, int era) - { - // year/month/era checking is done in GetDaysInMonth() - if (day < 1 || day > GetDaysInMonth(year, month, era)) - { - throw new ArgumentOutOfRangeException( - nameof(day), - SR.Format( - SR.ArgumentOutOfRange_Range, - 1, - GetDaysInMonth(year, month, era))); - } - - if (!IsLeapYear(year, era)) - { - return false; - } - - if (month == 2 && day == 29) - { - return true; - } - - return false; - } - - // Giving the calendar year and era, ValidateYearInEra will validate the existence of the input year in the input era. - // This method will throw if the year or the era is invalid. - public void ValidateYearInEra(int year, int era) => GetYearOffset(year, era, throwOnError: true); - - // Returns the leap month in a calendar year of the specified era. - // This method always returns 0 as all calendars using this method don't have leap months. - public int GetLeapMonth(int year, int era) - { - ValidateYearInEra(year, era); - return 0; - } - - // Checks whether a given month in the specified era is a leap month. - // This method always returns false as all calendars using this method don't have leap months. - public bool IsLeapMonth(int year, int month, int era) - { - ValidateYearInEra(year, era); - if (month < 1 || month > 12) - { - throw new ArgumentOutOfRangeException( - nameof(month), - SR.Format( - SR.ArgumentOutOfRange_Range, - 1, - 12)); - } - return false; - } - - // 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 bool IsLeapYear(int year, int era) - { - year = GetGregorianYear(year, era); - return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0); - } - - // Returns the date and time converted to a DateTime value. Throws an exception if the n-tuple is invalid. - // - public DateTime ToDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int era) - { - year = GetGregorianYear(year, era); - long ticks = DateToTicks(year, month, day) + TimeToTicks(hour, minute, second, millisecond); - CheckTicksRange(ticks); - return new DateTime(ticks); - } - - public virtual int GetWeekOfYear(DateTime time, CalendarWeekRule rule, DayOfWeek firstDayOfWeek) - { - CheckTicksRange(time.Ticks); - // Use GregorianCalendar to get around the problem that the implmentation in Calendar.GetWeekOfYear() - // can call GetYear() that exceeds the supported range of the Gregorian-based calendars. - return GregorianCalendar.GetDefaultInstance().GetWeekOfYear(time, rule, firstDayOfWeek); - } - - public int ToFourDigitYear(int year, int twoDigitYearMax) - { - if (year < 0) - { - throw new ArgumentOutOfRangeException(nameof(year), - SR.ArgumentOutOfRange_NeedPosNum); - } - - if (year < 100) - { - int y = year % 100; - return (twoDigitYearMax / 100 - (y > twoDigitYearMax % 100 ? 1 : 0)) * 100 + y; - } - - if (year < m_minYear || year > m_maxYear) - { - throw new ArgumentOutOfRangeException( - nameof(year), - SR.Format(SR.ArgumentOutOfRange_Range, m_minYear, m_maxYear)); - } - // If the year value is above 100, just return the year value. Don't have to do - // the TwoDigitYearMax comparison. - return year; - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/GregorianCalendarTypes.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/GregorianCalendarTypes.cs deleted file mode 100644 index 46f13b00e06..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/GregorianCalendarTypes.cs +++ /dev/null @@ -1,18 +0,0 @@ -// 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 -{ - // Note: The values of the members of this enum must match the coresponding values - // in the CalendarId enum (since we cast between GregorianCalendarTypes and CalendarId). - public enum GregorianCalendarTypes - { - Localized = CalendarId.GREGORIAN, - USEnglish = CalendarId.GREGORIAN_US, - MiddleEastFrench = CalendarId.GREGORIAN_ME_FRENCH, - Arabic = CalendarId.GREGORIAN_ARABIC, - TransliteratedEnglish = CalendarId.GREGORIAN_XLIT_ENGLISH, - TransliteratedFrench = CalendarId.GREGORIAN_XLIT_FRENCH, - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/HebrewCalendar.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/HebrewCalendar.cs deleted file mode 100644 index 477c1ed8d93..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/HebrewCalendar.cs +++ /dev/null @@ -1,904 +0,0 @@ -// 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; - -namespace System.Globalization -{ - /// <remarks> - /// Rules for the Hebrew calendar: - /// - The Hebrew calendar is both a Lunar (months) and Solar (years) - /// calendar, but allows for a week of seven days. - /// - Days begin at sunset. - /// - Leap Years occur in the 3, 6, 8, 11, 14, 17, & 19th years of a - /// 19-year cycle. Year = leap iff ((7y+1) mod 19 < 7). - /// - There are 12 months in a common year and 13 months in a leap year. - /// - In a common year, the 6th month, Adar, has 29 days. In a leap - /// year, the 6th month, Adar I, has 30 days and the leap month, - /// Adar II, has 29 days. - /// - Common years have 353-355 days. Leap years have 383-385 days. - /// - The Hebrew new year (Rosh HaShanah) begins on the 1st of Tishri, - /// the 7th month in the list below. - /// - The new year may not begin on Sunday, Wednesday, or Friday. - /// - If the new year would fall on a Tuesday and the conjunction of - /// the following year were at midday or later, the new year is - /// delayed until Thursday. - /// - If the new year would fall on a Monday after a leap year, the - /// new year is delayed until Tuesday. - /// - The length of the 8th and 9th months vary from year to year, - /// depending on the overall length of the year. - /// - The length of a year is determined by the dates of the new - /// years (Tishri 1) preceding and following the year in question. - /// - The 2th month is long (30 days) if the year has 355 or 385 days. - /// - The 3th month is short (29 days) if the year has 353 or 383 days. - /// - The Hebrew months are: - /// 1. Tishri (30 days) - /// 2. Heshvan (29 or 30 days) - /// 3. Kislev (29 or 30 days) - /// 4. Teveth (29 days) - /// 5. Shevat (30 days) - /// 6. Adar I (30 days) - /// 7. Adar {II} (29 days, this only exists if that year is a leap year) - /// 8. Nisan (30 days) - /// 9. Iyyar (29 days) - /// 10. Sivan (30 days) - /// 11. Tammuz (29 days) - /// 12. Av (30 days) - /// 13. Elul (29 days) - /// Calendar support range: - /// Calendar Minimum Maximum - /// ========== ========== ========== - /// Gregorian 1583/01/01 2239/09/29 - /// Hebrew 5343/04/07 5999/13/29 - /// - /// Includes CHebrew implemetation;i.e All the code necessary for converting - /// Gregorian to Hebrew Lunar from 1583 to 2239. - /// </remarks> - public class HebrewCalendar : Calendar - { - public static readonly int HebrewEra = 1; - - private const int DatePartYear = 0; - private const int DatePartMonth = 2; - private const int DatePartDay = 3; - - // Hebrew Translation Table. - // - // This table is used to get the following Hebrew calendar information for a - // given Gregorian year: - // 1. The day of the Hebrew month corresponding to Gregorian January 1st - // for a given Gregorian year. - // 2. The month of the Hebrew month corresponding to Gregorian January 1st - // for a given Gregorian year. - // The information is not directly in the table. Instead, the info is decoded - // by special values (numbers above 29 and below 1). - // 3. The type of the Hebrew year for a given Gregorian year. - // - // More notes: - // This table includes 2 numbers for each year. - // The offset into the table determines the year. (offset 0 is Gregorian year 1500) - // 1st number determines the day of the Hebrew month coresponeds to January 1st. - // 2nd number determines the type of the Hebrew year. (the type determines how - // many days are there in the year.) - // - // normal years : 1 = 353 days 2 = 354 days 3 = 355 days. - // Leap years : 4 = 383 5 384 6 = 385 days. - // - // A 99 means the year is not supported for translation. - // for convenience the table was defined for 750 year, - // but only 640 years are supported. (from 1583 to 2239) - // the years before 1582 (starting of Georgian calendar) - // and after 2239, are filled with 99. - // - // Greogrian January 1st falls usually in Tevet (4th month). Tevet has always 29 days. - // That's why, there no nead to specify the lunar month in the table. - // There are exceptions, these are coded by giving numbers above 29 and below 1. - // Actual decoding is takenig place whenever fetching information from the table. - // The function for decoding is in GetLunarMonthDay(). - // - // Example: - // The data for 2000 - 2005 A.D. is: - // 23,6,6,1,17,2,27,6,7,3, // 2000 - 2004 - // - // For year 2000, we know it has a Hebrew year type 6, which means it has 385 days. - // And 1/1/2000 A.D. is Hebrew year 5760, 23rd day of 4th month. - // - // Jewish Era in use today is dated from the supposed year of the - // Creation with its beginning in 3761 B.C. - // - // The Hebrew year of Gregorian 1st year AD. - // 0001/01/01 AD is Hebrew 3760/01/01 - private const int HebrewYearOf1AD = 3760; - - private const int FirstGregorianTableYear = 1583; // == Hebrew Year 5343 - private const int LastGregorianTableYear = 2239; // == Hebrew Year 5999 - - private const int TableSize = (LastGregorianTableYear - FirstGregorianTableYear); - - private const int MinHebrewYear = HebrewYearOf1AD + FirstGregorianTableYear; // == 5343 - private const int MaxHebrewYear = HebrewYearOf1AD + LastGregorianTableYear; // == 5999 - - private static ReadOnlySpan<byte> HebrewTable => new byte[] // rely on C# compiler optimization to reference static data - { - 7, 3, 17, 3, // 1583-1584 (Hebrew year: 5343 - 5344) - 0, 4, 11, 2, 21, 6, 1, 3, 13, 2, // 1585-1589 - 25, 4, 5, 3, 16, 2, 27, 6, 9, 1, // 1590-1594 - 20, 2, 0, 6, 11, 3, 23, 4, 4, 2, // 1595-1599 - 14, 3, 27, 4, 8, 2, 18, 3, 28, 6, // 1600 - 11, 1, 22, 5, 2, 3, 12, 3, 25, 4, // 1605 - 6, 2, 16, 3, 26, 6, 8, 2, 20, 1, // 1610 - 0, 6, 11, 2, 24, 4, 4, 3, 15, 2, // 1615 - 25, 6, 8, 1, 19, 2, 29, 6, 9, 3, // 1620 - 22, 4, 3, 2, 13, 3, 25, 4, 6, 3, // 1625 - 17, 2, 27, 6, 7, 3, 19, 2, 31, 4, // 1630 - 11, 3, 23, 4, 5, 2, 15, 3, 25, 6, // 1635 - 6, 2, 19, 1, 29, 6, 10, 2, 22, 4, // 1640 - 3, 3, 14, 2, 24, 6, 6, 1, 17, 3, // 1645 - 28, 5, 8, 3, 20, 1, 32, 5, 12, 3, // 1650 - 22, 6, 4, 1, 16, 2, 26, 6, 6, 3, // 1655 - 17, 2, 0, 4, 10, 3, 22, 4, 3, 2, // 1660 - 14, 3, 24, 6, 5, 2, 17, 1, 28, 6, // 1665 - 9, 2, 19, 3, 31, 4, 13, 2, 23, 6, // 1670 - 3, 3, 15, 1, 27, 5, 7, 3, 17, 3, // 1675 - 29, 4, 11, 2, 21, 6, 3, 1, 14, 2, // 1680 - 25, 6, 5, 3, 16, 2, 28, 4, 9, 3, // 1685 - 20, 2, 0, 6, 12, 1, 23, 6, 4, 2, // 1690 - 14, 3, 26, 4, 8, 2, 18, 3, 0, 4, // 1695 - 10, 3, 21, 5, 1, 3, 13, 1, 24, 5, // 1700 - 5, 3, 15, 3, 27, 4, 8, 2, 19, 3, // 1705 - 29, 6, 10, 2, 22, 4, 3, 3, 14, 2, // 1710 - 26, 4, 6, 3, 18, 2, 28, 6, 10, 1, // 1715 - 20, 6, 2, 2, 12, 3, 24, 4, 5, 2, // 1720 - 16, 3, 28, 4, 8, 3, 19, 2, 0, 6, // 1725 - 12, 1, 23, 5, 3, 3, 14, 3, 26, 4, // 1730 - 7, 2, 17, 3, 28, 6, 9, 2, 21, 4, // 1735 - 1, 3, 13, 2, 25, 4, 5, 3, 16, 2, // 1740 - 27, 6, 9, 1, 19, 3, 0, 5, 11, 3, // 1745 - 23, 4, 4, 2, 14, 3, 25, 6, 7, 1, // 1750 - 18, 2, 28, 6, 9, 3, 21, 4, 2, 2, // 1755 - 12, 3, 25, 4, 6, 2, 16, 3, 26, 6, // 1760 - 8, 2, 20, 1, 0, 6, 11, 2, 22, 6, // 1765 - 4, 1, 15, 2, 25, 6, 6, 3, 18, 1, // 1770 - 29, 5, 9, 3, 22, 4, 2, 3, 13, 2, // 1775 - 23, 6, 4, 3, 15, 2, 27, 4, 7, 3, // 1780 - 19, 2, 31, 4, 11, 3, 21, 6, 3, 2, // 1785 - 15, 1, 25, 6, 6, 2, 17, 3, 29, 4, // 1790 - 10, 2, 20, 6, 3, 1, 13, 3, 24, 5, // 1795 - 4, 3, 16, 1, 27, 5, 7, 3, 17, 3, // 1800 - 0, 4, 11, 2, 21, 6, 1, 3, 13, 2, // 1805 - 25, 4, 5, 3, 16, 2, 29, 4, 9, 3, // 1810 - 19, 6, 30, 2, 13, 1, 23, 6, 4, 2, // 1815 - 14, 3, 27, 4, 8, 2, 18, 3, 0, 4, // 1820 - 11, 3, 22, 5, 2, 3, 14, 1, 26, 5, // 1825 - 6, 3, 16, 3, 28, 4, 10, 2, 20, 6, // 1830 - 30, 3, 11, 2, 24, 4, 4, 3, 15, 2, // 1835 - 25, 6, 8, 1, 19, 2, 29, 6, 9, 3, // 1840 - 22, 4, 3, 2, 13, 3, 25, 4, 7, 2, // 1845 - 17, 3, 27, 6, 9, 1, 21, 5, 1, 3, // 1850 - 11, 3, 23, 4, 5, 2, 15, 3, 25, 6, // 1855 - 6, 2, 19, 1, 29, 6, 10, 2, 22, 4, // 1860 - 3, 3, 14, 2, 24, 6, 6, 1, 18, 2, // 1865 - 28, 6, 8, 3, 20, 4, 2, 2, 12, 3, // 1870 - 24, 4, 4, 3, 16, 2, 26, 6, 6, 3, // 1875 - 17, 2, 0, 4, 10, 3, 22, 4, 3, 2, // 1880 - 14, 3, 24, 6, 5, 2, 17, 1, 28, 6, // 1885 - 9, 2, 21, 4, 1, 3, 13, 2, 23, 6, // 1890 - 5, 1, 15, 3, 27, 5, 7, 3, 19, 1, // 1895 - 0, 5, 10, 3, 22, 4, 2, 3, 13, 2, // 1900 - 24, 6, 4, 3, 15, 2, 27, 4, 8, 3, // 1905 - 20, 4, 1, 2, 11, 3, 22, 6, 3, 2, // 1910 - 15, 1, 25, 6, 7, 2, 17, 3, 29, 4, // 1915 - 10, 2, 21, 6, 1, 3, 13, 1, 24, 5, // 1920 - 5, 3, 15, 3, 27, 4, 8, 2, 19, 6, // 1925 - 1, 1, 12, 2, 22, 6, 3, 3, 14, 2, // 1930 - 26, 4, 6, 3, 18, 2, 28, 6, 10, 1, // 1935 - 20, 6, 2, 2, 12, 3, 24, 4, 5, 2, // 1940 - 16, 3, 28, 4, 9, 2, 19, 6, 30, 3, // 1945 - 12, 1, 23, 5, 3, 3, 14, 3, 26, 4, // 1950 - 7, 2, 17, 3, 28, 6, 9, 2, 21, 4, // 1955 - 1, 3, 13, 2, 25, 4, 5, 3, 16, 2, // 1960 - 27, 6, 9, 1, 19, 6, 30, 2, 11, 3, // 1965 - 23, 4, 4, 2, 14, 3, 27, 4, 7, 3, // 1970 - 18, 2, 28, 6, 11, 1, 22, 5, 2, 3, // 1975 - 12, 3, 25, 4, 6, 2, 16, 3, 26, 6, // 1980 - 8, 2, 20, 4, 30, 3, 11, 2, 24, 4, // 1985 - 4, 3, 15, 2, 25, 6, 8, 1, 18, 3, // 1990 - 29, 5, 9, 3, 22, 4, 3, 2, 13, 3, // 1995 - 23, 6, 6, 1, 17, 2, 27, 6, 7, 3, // 2000 - 2004 - 20, 4, 1, 2, 11, 3, 23, 4, 5, 2, // 2005 - 2009 - 15, 3, 25, 6, 6, 2, 19, 1, 29, 6, // 2010 - 10, 2, 20, 6, 3, 1, 14, 2, 24, 6, // 2015 - 4, 3, 17, 1, 28, 5, 8, 3, 20, 4, // 2020 - 1, 3, 12, 2, 22, 6, 2, 3, 14, 2, // 2025 - 26, 4, 6, 3, 17, 2, 0, 4, 10, 3, // 2030 - 20, 6, 1, 2, 14, 1, 24, 6, 5, 2, // 2035 - 15, 3, 28, 4, 9, 2, 19, 6, 1, 1, // 2040 - 12, 3, 23, 5, 3, 3, 15, 1, 27, 5, // 2045 - 7, 3, 17, 3, 29, 4, 11, 2, 21, 6, // 2050 - 1, 3, 12, 2, 25, 4, 5, 3, 16, 2, // 2055 - 28, 4, 9, 3, 19, 6, 30, 2, 12, 1, // 2060 - 23, 6, 4, 2, 14, 3, 26, 4, 8, 2, // 2065 - 18, 3, 0, 4, 10, 3, 22, 5, 2, 3, // 2070 - 14, 1, 25, 5, 6, 3, 16, 3, 28, 4, // 2075 - 9, 2, 20, 6, 30, 3, 11, 2, 23, 4, // 2080 - 4, 3, 15, 2, 27, 4, 7, 3, 19, 2, // 2085 - 29, 6, 11, 1, 21, 6, 3, 2, 13, 3, // 2090 - 25, 4, 6, 2, 17, 3, 27, 6, 9, 1, // 2095 - 20, 5, 30, 3, 10, 3, 22, 4, 3, 2, // 2100 - 14, 3, 24, 6, 5, 2, 17, 1, 28, 6, // 2105 - 9, 2, 21, 4, 1, 3, 13, 2, 23, 6, // 2110 - 5, 1, 16, 2, 27, 6, 7, 3, 19, 4, // 2115 - 30, 2, 11, 3, 23, 4, 3, 3, 14, 2, // 2120 - 25, 6, 5, 3, 16, 2, 28, 4, 9, 3, // 2125 - 21, 4, 2, 2, 12, 3, 23, 6, 4, 2, // 2130 - 16, 1, 26, 6, 8, 2, 20, 4, 30, 3, // 2135 - 11, 2, 22, 6, 4, 1, 14, 3, 25, 5, // 2140 - 6, 3, 18, 1, 29, 5, 9, 3, 22, 4, // 2145 - 2, 3, 13, 2, 23, 6, 4, 3, 15, 2, // 2150 - 27, 4, 7, 3, 20, 4, 1, 2, 11, 3, // 2155 - 21, 6, 3, 2, 15, 1, 25, 6, 6, 2, // 2160 - 17, 3, 29, 4, 10, 2, 20, 6, 3, 1, // 2165 - 13, 3, 24, 5, 4, 3, 17, 1, 28, 5, // 2170 - 8, 3, 18, 6, 1, 1, 12, 2, 22, 6, // 2175 - 2, 3, 14, 2, 26, 4, 6, 3, 17, 2, // 2180 - 28, 6, 10, 1, 20, 6, 1, 2, 12, 3, // 2185 - 24, 4, 5, 2, 15, 3, 28, 4, 9, 2, // 2190 - 19, 6, 33, 3, 12, 1, 23, 5, 3, 3, // 2195 - 13, 3, 25, 4, 6, 2, 16, 3, 26, 6, // 2200 - 8, 2, 20, 4, 30, 3, 11, 2, 24, 4, // 2205 - 4, 3, 15, 2, 25, 6, 8, 1, 18, 6, // 2210 - 33, 2, 9, 3, 22, 4, 3, 2, 13, 3, // 2215 - 25, 4, 6, 3, 17, 2, 27, 6, 9, 1, // 2220 - 21, 5, 1, 3, 11, 3, 23, 4, 5, 2, // 2225 - 15, 3, 25, 6, 6, 2, 19, 4, 33, 3, // 2230 - 10, 2, 22, 4, 3, 3, 14, 2, 24, 6, // 2235 - 6, 1 // 2240 (Hebrew year: 6000) - }; - - private const int MaxMonthPlusOne = 14; - - // The lunar calendar has 6 different variations of month lengths - // within a year. - private static ReadOnlySpan<byte> LunarMonthLen => new byte[] // rely on C# compiler optimization to reference static data - { - 0, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 0, - 0, 30, 29, 29, 29, 30, 29, 30, 29, 30, 29, 30, 29, 0, // 3 common year variations - 0, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 0, - 0, 30, 30, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 0, - 0, 30, 29, 29, 29, 30, 30, 29, 30, 29, 30, 29, 30, 29, // 3 leap year variations - 0, 30, 29, 30, 29, 30, 30, 29, 30, 29, 30, 29, 30, 29, - 0, 30, 30, 30, 29, 30, 30, 29, 30, 29, 30, 29, 30, 29 - }; - - private static readonly DateTime s_calendarMinValue = new DateTime(1583, 1, 1); - - // Gregorian 2239/9/29 = Hebrew 5999/13/29 (last day in Hebrew year 5999). - // We can only format/parse Hebrew numbers up to 999, so we limit the max range to Hebrew year 5999. - private static readonly DateTime s_calendarMaxValue = new DateTime((new DateTime(2239, 9, 29, 23, 59, 59, 999)).Ticks + 9999); - - public override DateTime MinSupportedDateTime => s_calendarMinValue; - - public override DateTime MaxSupportedDateTime => s_calendarMaxValue; - - public override CalendarAlgorithmType AlgorithmType => CalendarAlgorithmType.LunisolarCalendar; - - public HebrewCalendar() - { - } - - internal override CalendarId ID => CalendarId.HEBREW; - - private static void CheckHebrewYearValue(int y, int era, string varName) - { - CheckEraRange(era); - if (y > MaxHebrewYear || y < MinHebrewYear) - { - throw new ArgumentOutOfRangeException( - varName, - y, - SR.Format(SR.ArgumentOutOfRange_Range, MinHebrewYear, MaxHebrewYear)); - } - } - - /// <summary> - /// Check if the Hebrew month value is valid. - /// </summary> - /// <remarks> - /// Call CheckHebrewYearValue() before calling this to verify the year value is supported. - /// </remarks> - private void CheckHebrewMonthValue(int year, int month, int era) - { - int monthsInYear = GetMonthsInYear(year, era); - if (month < 1 || month > monthsInYear) - { - throw new ArgumentOutOfRangeException( - nameof(month), - month, - SR.Format(SR.ArgumentOutOfRange_Range, 1, monthsInYear)); - } - } - - /// <summary> - /// Check if the Hebrew day value is valid. - /// </summary> - /// <remarks> - /// Call CheckHebrewYearValue()/CheckHebrewMonthValue() before calling this to verify the year/month values are valid. - /// </remarks> - private void CheckHebrewDayValue(int year, int month, int day, int era) - { - int daysInMonth = GetDaysInMonth(year, month, era); - if (day < 1 || day > daysInMonth) - { - throw new ArgumentOutOfRangeException( - nameof(day), - day, - SR.Format(SR.ArgumentOutOfRange_Range, 1, daysInMonth)); - } - } - - private static void CheckEraRange(int era) - { - if (era != CurrentEra && era != HebrewEra) - { - throw new ArgumentOutOfRangeException(nameof(era), era, SR.ArgumentOutOfRange_InvalidEraValue); - } - } - - private static void CheckTicksRange(long ticks) - { - if (ticks < s_calendarMinValue.Ticks || ticks > s_calendarMaxValue.Ticks) - { - throw new ArgumentOutOfRangeException( - "time", - ticks, - // Print out the date in Gregorian using InvariantCulture since the DateTime is based on GreograinCalendar. - SR.Format( - CultureInfo.InvariantCulture, - SR.ArgumentOutOfRange_CalendarRange, - s_calendarMinValue, - s_calendarMaxValue)); - } - } - - private static int GetResult(DateBuffer result, int part) - { - return part switch - { - DatePartYear => result.year, - DatePartMonth => result.month, - DatePartDay => result.day, - _ => throw new InvalidOperationException(SR.InvalidOperation_DateTimeParsing), - }; - } - - /// <summary> - /// Using the Hebrew table (HebrewTable) to get the Hebrew month/day value for Gregorian January 1st - /// in a given Gregorian year. - /// Greogrian January 1st falls usually in Tevet (4th month). Tevet has always 29 days. - /// That's why, there no nead to specify the lunar month in the table. There are exceptions, and these - /// are coded by giving numbers above 29 and below 1. - /// Actual decoding is takenig place in the switch statement below. - /// </summary> - /// <returns> - /// The Hebrew year type. The value is from 1 to 6. - /// normal years : 1 = 353 days 2 = 354 days 3 = 355 days. - /// Leap years : 4 = 383 5 384 6 = 385 days. - /// </returns> - internal static int GetLunarMonthDay(int gregorianYear, DateBuffer lunarDate) - { - // Get the offset into the LunarMonthLen array and the lunar day - // for January 1st. - int index = gregorianYear - FirstGregorianTableYear; - if (index < 0 || index > TableSize) - { - throw new ArgumentOutOfRangeException(nameof(gregorianYear)); - } - - index *= 2; - lunarDate.day = HebrewTable[index]; - - // Get the type of the year. The value is from 1 to 6 - int lunarYearType = HebrewTable[index + 1]; - - // Get the Lunar Month. - switch (lunarDate.day) - { - case 0: // 1/1 is on Shvat 1 - lunarDate.month = 5; - lunarDate.day = 1; - break; - case 30: // 1/1 is on Kislev 30 - lunarDate.month = 3; - break; - case 31: // 1/1 is on Shvat 2 - lunarDate.month = 5; - lunarDate.day = 2; - break; - case 32: // 1/1 is on Shvat 3 - lunarDate.month = 5; - lunarDate.day = 3; - break; - case 33: // 1/1 is on Kislev 29 - lunarDate.month = 3; - lunarDate.day = 29; - break; - default: // 1/1 is on Tevet (This is the general case) - lunarDate.month = 4; - break; - } - - return lunarYearType; - } - - /// <summary> - /// Returns a given date part of this DateTime. This method is used - /// to compute the year, day-of-year, month, or day part. - /// </summary> - internal virtual int GetDatePart(long ticks, int part) - { - // The Gregorian year, month, day value for ticks. - int gregorianYear, gregorianMonth, gregorianDay; - int hebrewYearType; // lunar year type - long AbsoluteDate; // absolute date - absolute date 1/1/1600 - - // Make sure we have a valid Gregorian date that will fit into our - // Hebrew conversion limits. - CheckTicksRange(ticks); - - DateTime time = new DateTime(ticks); - - // Save the Gregorian date values. - time.GetDatePart(out gregorianYear, out gregorianMonth, out gregorianDay); - - DateBuffer lunarDate = new DateBuffer(); // lunar month and day for Jan 1 - - // From the table looking-up value of HebrewTable[index] (stored in lunarDate.day), we get the - // lunar month and lunar day where the Gregorian date 1/1 falls. - lunarDate.year = gregorianYear + HebrewYearOf1AD; - hebrewYearType = GetLunarMonthDay(gregorianYear, lunarDate); - - // This is the buffer used to store the result Hebrew date. - DateBuffer result = new DateBuffer(); - - // Store the values for the start of the new year - 1/1. - result.year = lunarDate.year; - result.month = lunarDate.month; - result.day = lunarDate.day; - - // Get the absolute date from 1/1/1600. - AbsoluteDate = GregorianCalendar.GetAbsoluteDate(gregorianYear, gregorianMonth, gregorianDay); - - // If the requested date was 1/1, then we're done. - if ((gregorianMonth == 1) && (gregorianDay == 1)) - { - return GetResult(result, part); - } - - // Calculate the number of days between 1/1 and the requested date. - long numDays = AbsoluteDate - GregorianCalendar.GetAbsoluteDate(gregorianYear, 1, 1); - - // If the requested date is within the current lunar month, then - // we're done. - if ((numDays + (long)lunarDate.day) <= (long)(LunarMonthLen[hebrewYearType * MaxMonthPlusOne + lunarDate.month])) - { - result.day += (int)numDays; - return GetResult(result, part); - } - - // Adjust for the current partial month. - result.month++; - result.day = 1; - - // Adjust the Lunar Month and Year (if necessary) based on the number - // of days between 1/1 and the requested date. - // Assumes Jan 1 can never translate to the last Lunar month, which - // is true. - numDays -= (long)(LunarMonthLen[hebrewYearType * MaxMonthPlusOne + lunarDate.month] - lunarDate.day); - Debug.Assert(numDays >= 1, "NumDays >= 1"); - - // If NumDays is 1, then we are done. Otherwise, find the correct Hebrew month - // and day. - if (numDays > 1) - { - // See if we're on the correct Lunar month. - while (numDays > (long)(LunarMonthLen[hebrewYearType * MaxMonthPlusOne + result.month])) - { - // Adjust the number of days and move to the next month. - numDays -= (long)(LunarMonthLen[hebrewYearType * MaxMonthPlusOne + result.month++]); - - // See if we need to adjust the Year. - // Must handle both 12 and 13 month years. - if ((result.month > 13) || (LunarMonthLen[hebrewYearType * MaxMonthPlusOne + result.month] == 0)) - { - // Adjust the Year. - result.year++; - hebrewYearType = HebrewTable[(gregorianYear + 1 - FirstGregorianTableYear) * 2 + 1]; - - // Adjust the Month. - result.month = 1; - } - } - - // Found the right Lunar month. - result.day += (int)(numDays - 1); - } - - return GetResult(result, part); - } - - public override DateTime AddMonths(DateTime time, int months) - { - try - { - int y = GetDatePart(time.Ticks, DatePartYear); - int m = GetDatePart(time.Ticks, DatePartMonth); - int d = GetDatePart(time.Ticks, DatePartDay); - - int monthsInYear; - int i; - if (months >= 0) - { - i = m + months; - while (i > (monthsInYear = GetMonthsInYear(y, CurrentEra))) - { - y++; - i -= monthsInYear; - } - } - else - { - if ((i = m + months) <= 0) - { - months = -months; - months -= m; - y--; - - while (months > (monthsInYear = GetMonthsInYear(y, CurrentEra))) - { - y--; - months -= monthsInYear; - } - monthsInYear = GetMonthsInYear(y, CurrentEra); - i = monthsInYear - months; - } - } - - int days = GetDaysInMonth(y, i); - if (d > days) - { - d = days; - } - - return new DateTime(ToDateTime(y, i, d, 0, 0, 0, 0).Ticks + (time.Ticks % TicksPerDay)); - } - // We expect ArgumentException and ArgumentOutOfRangeException (which is subclass of ArgumentException) - // If exception is thrown in the calls above, we are out of the supported range of this calendar. - catch (ArgumentException) - { - throw new ArgumentOutOfRangeException(nameof(months), months, SR.ArgumentOutOfRange_AddValue); - } - } - - public override DateTime AddYears(DateTime time, int years) - { - int y = GetDatePart(time.Ticks, DatePartYear); - int m = GetDatePart(time.Ticks, DatePartMonth); - int d = GetDatePart(time.Ticks, DatePartDay); - - y += years; - CheckHebrewYearValue(y, Calendar.CurrentEra, nameof(years)); - - int months = GetMonthsInYear(y, CurrentEra); - if (m > months) - { - m = months; - } - - int days = GetDaysInMonth(y, m); - if (d > days) - { - d = days; - } - - long ticks = ToDateTime(y, m, d, 0, 0, 0, 0).Ticks + (time.Ticks % TicksPerDay); - Calendar.CheckAddResult(ticks, MinSupportedDateTime, MaxSupportedDateTime); - return new DateTime(ticks); - } - - public override int GetDayOfMonth(DateTime time) - { - return GetDatePart(time.Ticks, DatePartDay); - } - - public override DayOfWeek GetDayOfWeek(DateTime time) - { - // If we calculate back, the Hebrew day of week for Gregorian 0001/1/1 is Monday (1). - // Therfore, the fomula is: - return (DayOfWeek)((int)(time.Ticks / TicksPerDay + 1) % 7); - } - - internal static int GetHebrewYearType(int year, int era) - { - CheckHebrewYearValue(year, era, nameof(year)); - // The HebrewTable is indexed by Gregorian year and starts from FirstGregorianYear. - // So we need to convert year (Hebrew year value) to Gregorian Year below. - return HebrewTable[(year - HebrewYearOf1AD - FirstGregorianTableYear) * 2 + 1]; - } - - public override int GetDayOfYear(DateTime time) - { - // Get Hebrew year value of the specified time. - int year = GetYear(time); - DateTime beginOfYearDate; - if (year == 5343) - { - // Gregorian 1583/01/01 corresponds to Hebrew 5343/04/07 (MinSupportedDateTime) - // To figure out the Gregorian date associated with Hebrew 5343/01/01, we need to - // count the days from 5343/01/01 to 5343/04/07 and subtract that from Gregorian - // 1583/01/01. - // 1. Tishri (30 days) - // 2. Heshvan (30 days since 5343 has 355 days) - // 3. Kislev (30 days since 5343 has 355 days) - // 96 days to get from 5343/01/01 to 5343/04/07 - // Gregorian 1583/01/01 - 96 days = 1582/9/27 - - // the beginning of Hebrew year 5343 corresponds to Gregorian September 27, 1582. - beginOfYearDate = new DateTime(1582, 9, 27); - } - else - { - // following line will fail when year is 5343 (first supported year) - beginOfYearDate = ToDateTime(year, 1, 1, 0, 0, 0, 0, CurrentEra); - } - - return (int)((time.Ticks - beginOfYearDate.Ticks) / TicksPerDay) + 1; - } - - public override int GetDaysInMonth(int year, int month, int era) - { - CheckEraRange(era); - int hebrewYearType = GetHebrewYearType(year, era); - CheckHebrewMonthValue(year, month, era); - - Debug.Assert(hebrewYearType >= 1 && hebrewYearType <= 6, - "hebrewYearType should be from 1 to 6, but now hebrewYearType = " + hebrewYearType + " for hebrew year " + year); - int monthDays = LunarMonthLen[hebrewYearType * MaxMonthPlusOne + month]; - if (monthDays == 0) - { - throw new ArgumentOutOfRangeException(nameof(month), month, SR.ArgumentOutOfRange_Month); - } - - return monthDays; - } - - public override int GetDaysInYear(int year, int era) - { - CheckEraRange(era); - // normal years : 1 = 353 days 2 = 354 days 3 = 355 days. - // Leap years : 4 = 383 5 384 6 = 385 days. - - // LunarYearType is from 1 to 6 - int LunarYearType = GetHebrewYearType(year, era); - if (LunarYearType < 4) - { - // common year: LunarYearType = 1, 2, 3 - return 352 + LunarYearType; - } - - return 382 + (LunarYearType - 3); - } - - public override int GetEra(DateTime time) => HebrewEra; - - public override int[] Eras => new int[] { HebrewEra }; - - public override int GetMonth(DateTime time) - { - return GetDatePart(time.Ticks, DatePartMonth); - } - - public override int GetMonthsInYear(int year, int era) - { - return IsLeapYear(year, era) ? 13 : 12; - } - - public override int GetYear(DateTime time) - { - return GetDatePart(time.Ticks, DatePartYear); - } - - public override bool IsLeapDay(int year, int month, int day, int era) - { - if (IsLeapMonth(year, month, era)) - { - // Every day in a leap month is a leap day. - CheckHebrewDayValue(year, month, day, era); - return true; - } - else if (IsLeapYear(year, Calendar.CurrentEra)) - { - // There is an additional day in the 6th month in the leap year (the extra day is the 30th day in the 6th month), - // so we should return true for 6/30 if that's in a leap year. - if (month == 6 && day == 30) - { - return true; - } - } - - CheckHebrewDayValue(year, month, day, era); - return false; - } - - public override int GetLeapMonth(int year, int era) - { - // Year/era values are checked in IsLeapYear(). - if (IsLeapYear(year, era)) - { - // The 7th month in a leap year is a leap month. - return 7; - } - return 0; - } - - public override bool IsLeapMonth(int year, int month, int era) - { - // Year/era values are checked in IsLeapYear(). - bool isLeapYear = IsLeapYear(year, era); - CheckHebrewMonthValue(year, month, era); - - // The 7th month in a leap year is a leap month. - return isLeapYear && month == 7; - } - - public override bool IsLeapYear(int year, int era) - { - CheckHebrewYearValue(year, era, nameof(year)); - return ((7 * (long)year + 1) % 19) < 7; - } - - /// <summary> - /// (month1, day1) - (month2, day2) - /// </summary> - private static int GetDayDifference(int lunarYearType, int month1, int day1, int month2, int day2) - { - if (month1 == month2) - { - return day1 - day2; - } - - // Make sure that (month1, day1) < (month2, day2) - bool swap = (month1 > month2); - if (swap) - { - // (month1, day1) < (month2, day2). Swap the values. - // The result will be a negative number. - int tempMonth, tempDay; - tempMonth = month1; tempDay = day1; - month1 = month2; day1 = day2; - month2 = tempMonth; day2 = tempDay; - } - - // Get the number of days from (month1,day1) to (month1, end of month1) - int days = LunarMonthLen[lunarYearType * MaxMonthPlusOne + month1] - day1; - - // Move to next month. - month1++; - - // Add up the days. - while (month1 < month2) - { - days += LunarMonthLen[lunarYearType * MaxMonthPlusOne + month1++]; - } - days += day2; - - return swap ? days : -days; - } - - /// <summary> - /// Convert Hebrew date to Gregorian date. - /// The algorithm is like this: - /// The hebrew year has an offset to the Gregorian year, so we can guess the Gregorian year for - /// the specified Hebrew year. That is, GreogrianYear = HebrewYear - FirstHebrewYearOf1AD. - /// - /// From the Gregorian year and HebrewTable, we can get the Hebrew month/day value - /// of the Gregorian date January 1st. Let's call this month/day value [hebrewDateForJan1] - /// - /// If the requested Hebrew month/day is less than [hebrewDateForJan1], we know the result - /// Gregorian date falls in previous year. So we decrease the Gregorian year value, and - /// retrieve the Hebrew month/day value of the Gregorian date january 1st again. - /// - /// Now, we get the answer of the Gregorian year. - /// - /// The next step is to get the number of days between the requested Hebrew month/day - /// and [hebrewDateForJan1]. When we get that, we can create the DateTime by adding/subtracting - /// the ticks value of the number of days. - /// </summary> - private static DateTime HebrewToGregorian(int hebrewYear, int hebrewMonth, int hebrewDay, int hour, int minute, int second, int millisecond) - { - // Get the rough Gregorian year for the specified hebrewYear. - int gregorianYear = hebrewYear - HebrewYearOf1AD; - - DateBuffer hebrewDateOfJan1 = new DateBuffer(); // year value is unused. - int lunarYearType = GetLunarMonthDay(gregorianYear, hebrewDateOfJan1); - - if ((hebrewMonth == hebrewDateOfJan1.month) && (hebrewDay == hebrewDateOfJan1.day)) - { - return new DateTime(gregorianYear, 1, 1, hour, minute, second, millisecond); - } - - int days = GetDayDifference(lunarYearType, hebrewMonth, hebrewDay, hebrewDateOfJan1.month, hebrewDateOfJan1.day); - - DateTime gregorianNewYear = new DateTime(gregorianYear, 1, 1); - return new DateTime(gregorianNewYear.Ticks + days * TicksPerDay + TimeToTicks(hour, minute, second, millisecond)); - } - - public override DateTime ToDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int era) - { - CheckHebrewYearValue(year, era, nameof(year)); - CheckHebrewMonthValue(year, month, era); - CheckHebrewDayValue(year, month, day, era); - DateTime dt = HebrewToGregorian(year, month, day, hour, minute, second, millisecond); - CheckTicksRange(dt.Ticks); - return dt; - } - - private const int DefaultTwoDigitYearMax = 5790; - - public override int TwoDigitYearMax - { - get - { - if (_twoDigitYearMax == -1) - { - _twoDigitYearMax = GetSystemTwoDigitYearSetting(ID, DefaultTwoDigitYearMax); - } - - return _twoDigitYearMax; - } - set - { - VerifyWritable(); - if (value == 99) - { - // Do nothing here. Year 99 is allowed so that TwoDitYearMax is disabled. - } - else - { - CheckHebrewYearValue(value, HebrewEra, nameof(value)); - } - - _twoDigitYearMax = value; - } - } - - public override int ToFourDigitYear(int year) - { - if (year < 0) - { - throw new ArgumentOutOfRangeException(nameof(year), year, SR.ArgumentOutOfRange_NeedNonNegNum); - } - - if (year < 100) - { - return base.ToFourDigitYear(year); - } - - if (year > MaxHebrewYear || year < MinHebrewYear) - { - throw new ArgumentOutOfRangeException( - nameof(year), - year, - SR.Format(SR.ArgumentOutOfRange_Range, MinHebrewYear, MaxHebrewYear)); - } - return year; - } - - internal class DateBuffer - { - internal int year; - internal int month; - internal int day; - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/HebrewNumber.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/HebrewNumber.cs deleted file mode 100644 index 41cf1d2bf49..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/HebrewNumber.cs +++ /dev/null @@ -1,447 +0,0 @@ -// 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.Text; -using System.Diagnostics; - -namespace System.Globalization -{ - //////////////////////////////////////////////////////////////////////////// - // - // Used in HebrewNumber.ParseByChar to maintain the context information ( - // the state in the state machine and current Hebrew number values, etc.) - // when parsing Hebrew number character by character. - // - //////////////////////////////////////////////////////////////////////////// - - internal struct HebrewNumberParsingContext - { - // The current state of the state machine for parsing Hebrew numbers. - internal HebrewNumber.HS state; - // The current value of the Hebrew number. - // The final value is determined when state is FoundEndOfHebrewNumber. - internal int result; - - public HebrewNumberParsingContext(int result) - { - // Set the start state of the state machine for parsing Hebrew numbers. - state = HebrewNumber.HS.Start; - this.result = result; - } - } - - //////////////////////////////////////////////////////////////////////////// - // - // Please see ParseByChar() for comments about different states defined here. - // - //////////////////////////////////////////////////////////////////////////// - - internal enum HebrewNumberParsingState - { - InvalidHebrewNumber, - NotHebrewDigit, - FoundEndOfHebrewNumber, - ContinueParsing, - } - - //////////////////////////////////////////////////////////////////////////// - // - // class HebrewNumber - // - // Provides static methods for formatting integer values into - // Hebrew text and parsing Hebrew number text. - // - // Limitations: - // Parse can only handle value 1 ~ 999. - // Append() can only handle 1 ~ 999. If value is greater than 5000, - // 5000 will be subtracted from the value. - // - //////////////////////////////////////////////////////////////////////////// - - internal static class HebrewNumber - { - //////////////////////////////////////////////////////////////////////////// - // - // Append - // - // Converts the given number to Hebrew letters according to the numeric - // value of each Hebrew letter, appending to the supplied StringBuilder. - // Basically, this converts the lunar year and the lunar month to letters. - // - // The character of a year is described by three letters of the Hebrew - // alphabet, the first and third giving, respectively, the days of the - // weeks on which the New Year occurs and Passover begins, while the - // second is the initial of the Hebrew word for defective, normal, or - // complete. - // - // Defective Year : Both Heshvan and Kislev are defective (353 or 383 days) - // Normal Year : Heshvan is defective, Kislev is full (354 or 384 days) - // Complete Year : Both Heshvan and Kislev are full (355 or 385 days) - // - //////////////////////////////////////////////////////////////////////////// - - internal static void Append(StringBuilder outputBuffer, int Number) - { - Debug.Assert(outputBuffer != null); - int outputBufferStartingLength = outputBuffer.Length; - - char cTens = '\x0'; - char cUnits; // tens and units chars - int Hundreds, Tens; // hundreds and tens values - - // - // Adjust the number if greater than 5000. - // - if (Number > 5000) - { - Number -= 5000; - } - - Debug.Assert(Number > 0 && Number <= 999, "Number is out of range."); - - // - // Get the Hundreds. - // - Hundreds = Number / 100; - - if (Hundreds > 0) - { - Number -= Hundreds * 100; - // \x05e7 = 100 - // \x05e8 = 200 - // \x05e9 = 300 - // \x05ea = 400 - // If the number is greater than 400, use the multiples of 400. - for (int i = 0; i < (Hundreds / 4); i++) - { - outputBuffer.Append('\x05ea'); - } - - int remains = Hundreds % 4; - if (remains > 0) - { - outputBuffer.Append((char)((int)'\x05e6' + remains)); - } - } - - // - // Get the Tens. - // - Tens = Number / 10; - Number %= 10; - - switch (Tens) - { - case (0): - cTens = '\x0'; - break; - case (1): - cTens = '\x05d9'; // Hebrew Letter Yod - break; - case (2): - cTens = '\x05db'; // Hebrew Letter Kaf - break; - case (3): - cTens = '\x05dc'; // Hebrew Letter Lamed - break; - case (4): - cTens = '\x05de'; // Hebrew Letter Mem - break; - case (5): - cTens = '\x05e0'; // Hebrew Letter Nun - break; - case (6): - cTens = '\x05e1'; // Hebrew Letter Samekh - break; - case (7): - cTens = '\x05e2'; // Hebrew Letter Ayin - break; - case (8): - cTens = '\x05e4'; // Hebrew Letter Pe - break; - case (9): - cTens = '\x05e6'; // Hebrew Letter Tsadi - break; - } - - // - // Get the Units. - // - cUnits = (char)(Number > 0 ? ((int)'\x05d0' + Number - 1) : 0); - - if ((cUnits == '\x05d4') && // Hebrew Letter He (5) - (cTens == '\x05d9')) - { // Hebrew Letter Yod (10) - cUnits = '\x05d5'; // Hebrew Letter Vav (6) - cTens = '\x05d8'; // Hebrew Letter Tet (9) - } - - if ((cUnits == '\x05d5') && // Hebrew Letter Vav (6) - (cTens == '\x05d9')) - { // Hebrew Letter Yod (10) - cUnits = '\x05d6'; // Hebrew Letter Zayin (7) - cTens = '\x05d8'; // Hebrew Letter Tet (9) - } - - // - // Copy the appropriate info to the given buffer. - // - - if (cTens != '\x0') - { - outputBuffer.Append(cTens); - } - - if (cUnits != '\x0') - { - outputBuffer.Append(cUnits); - } - - if (outputBuffer.Length - outputBufferStartingLength > 1) - { - outputBuffer.Insert(outputBuffer.Length - 1, '"'); - } - else - { - outputBuffer.Append('\''); - } - } - - //////////////////////////////////////////////////////////////////////////// - // - // Token used to tokenize a Hebrew word into tokens so that we can use in the - // state machine. - // - //////////////////////////////////////////////////////////////////////////// - - private enum HebrewToken : short - { - Invalid = -1, - Digit400 = 0, - Digit200_300 = 1, - Digit100 = 2, - Digit10 = 3, // 10 ~ 90 - Digit1 = 4, // 1, 2, 3, 4, 5, 8, - Digit6_7 = 5, - Digit7 = 6, - Digit9 = 7, - SingleQuote = 8, - DoubleQuote = 9, - } - - //////////////////////////////////////////////////////////////////////////// - // - // This class is used to map a token into its Hebrew digit value. - // - //////////////////////////////////////////////////////////////////////////// - - private struct HebrewValue - { - internal HebrewToken token; - internal short value; - internal HebrewValue(HebrewToken token, short value) - { - this.token = token; - this.value = value; - } - } - - // - // Map a Hebrew character from U+05D0 ~ U+05EA to its digit value. - // The value is -1 if the Hebrew character does not have a associated value. - // - private static readonly HebrewValue[] s_hebrewValues = { - new HebrewValue(HebrewToken.Digit1, 1), // '\x05d0 - new HebrewValue(HebrewToken.Digit1, 2), // '\x05d1 - new HebrewValue(HebrewToken.Digit1, 3), // '\x05d2 - new HebrewValue(HebrewToken.Digit1, 4), // '\x05d3 - new HebrewValue(HebrewToken.Digit1, 5), // '\x05d4 - new HebrewValue(HebrewToken.Digit6_7, 6), // '\x05d5 - new HebrewValue(HebrewToken.Digit6_7, 7), // '\x05d6 - new HebrewValue(HebrewToken.Digit1, 8), // '\x05d7 - new HebrewValue(HebrewToken.Digit9, 9), // '\x05d8 - new HebrewValue(HebrewToken.Digit10, 10), // '\x05d9; // Hebrew Letter Yod - new HebrewValue(HebrewToken.Invalid, -1), // '\x05da; - new HebrewValue(HebrewToken.Digit10, 20), // '\x05db; // Hebrew Letter Kaf - new HebrewValue(HebrewToken.Digit10, 30), // '\x05dc; // Hebrew Letter Lamed - new HebrewValue(HebrewToken.Invalid, -1), // '\x05dd; - new HebrewValue(HebrewToken.Digit10, 40), // '\x05de; // Hebrew Letter Mem - new HebrewValue(HebrewToken.Invalid, -1), // '\x05df; - new HebrewValue(HebrewToken.Digit10, 50), // '\x05e0; // Hebrew Letter Nun - new HebrewValue(HebrewToken.Digit10, 60), // '\x05e1; // Hebrew Letter Samekh - new HebrewValue(HebrewToken.Digit10, 70), // '\x05e2; // Hebrew Letter Ayin - new HebrewValue(HebrewToken.Invalid, -1), // '\x05e3; - new HebrewValue(HebrewToken.Digit10, 80), // '\x05e4; // Hebrew Letter Pe - new HebrewValue(HebrewToken.Invalid, -1), // '\x05e5; - new HebrewValue(HebrewToken.Digit10, 90), // '\x05e6; // Hebrew Letter Tsadi - new HebrewValue(HebrewToken.Digit100, 100), // '\x05e7; - new HebrewValue(HebrewToken.Digit200_300, 200), // '\x05e8; - new HebrewValue(HebrewToken.Digit200_300, 300), // '\x05e9; - new HebrewValue(HebrewToken.Digit400, 400), // '\x05ea; - }; - - private const int minHebrewNumberCh = 0x05d0; - private static readonly char s_maxHebrewNumberCh = (char)(minHebrewNumberCh + s_hebrewValues.Length - 1); - - //////////////////////////////////////////////////////////////////////////// - // - // Hebrew number parsing State - // The current state and the next token will lead to the next state in the state machine. - // DQ = Double Quote - // - //////////////////////////////////////////////////////////////////////////// - - internal enum HS : sbyte - { - _err = -1, // an error state - Start = 0, - S400 = 1, // a Hebrew digit 400 - S400_400 = 2, // Two Hebrew digit 400 - S400_X00 = 3, // Two Hebrew digit 400 and followed by 100 - S400_X0 = 4, // Hebrew digit 400 and followed by 10 ~ 90 - X00_DQ = 5, // A hundred number and followed by a double quote. - S400_X00_X0 = 6, - X0_DQ = 7, // A two-digit number and followed by a double quote. - X = 8, // A single digit Hebrew number. - X0 = 9, // A two-digit Hebrew number - X00 = 10, // A three-digit Hebrew number - S400_DQ = 11, // A Hebrew digit 400 and followed by a double quote. - S400_400_DQ = 12, - S400_400_100 = 13, - S9 = 14, // Hebrew digit 9 - X00_S9 = 15, // A hundered number and followed by a digit 9 - S9_DQ = 16, // Hebrew digit 9 and followed by a double quote - END = 100, // A terminial state is reached. - } - - // - // The state machine for Hebrew number pasing. - // - private static readonly HS[] s_numberPasingState = - { - // 400 300/200 100 90~10 8~1 6, 7, 9, ' " - /* 0 */ - HS.S400, HS.X00, HS.X00, HS.X0, HS.X, HS.X, HS.X, HS.S9, HS._err, HS._err, - /* 1: S400 */ - HS.S400_400, HS.S400_X00, HS.S400_X00, HS.S400_X0, HS._err, HS._err, HS._err, HS.X00_S9, HS.END, HS.S400_DQ, - /* 2: S400_400 */ - HS._err, HS._err, HS.S400_400_100, HS.S400_X0, HS._err, HS._err, HS._err, HS.X00_S9, HS._err, HS.S400_400_DQ, - /* 3: S400_X00 */ - HS._err, HS._err, HS._err, HS.S400_X00_X0, HS._err, HS._err, HS._err, HS.X00_S9, HS._err, HS.X00_DQ, - /* 4: S400_X0 */ - HS._err, HS._err, HS._err, HS._err, HS._err, HS._err, HS._err, HS._err, HS._err, HS.X0_DQ, - /* 5: X00_DQ */ - HS._err, HS._err, HS._err, HS.END, HS.END, HS.END, HS.END, HS.END, HS._err, HS._err, - /* 6: S400_X00_X0 */ - HS._err, HS._err, HS._err, HS._err, HS._err, HS._err, HS._err, HS._err, HS._err, HS.X0_DQ, - /* 7: X0_DQ */ - HS._err, HS._err, HS._err, HS._err, HS.END, HS.END, HS.END, HS.END, HS._err, HS._err, - /* 8: X */ - HS._err, HS._err, HS._err, HS._err, HS._err, HS._err, HS._err, HS._err, HS.END, HS._err, - /* 9: X0 */ - HS._err, HS._err, HS._err, HS._err, HS._err, HS._err, HS._err, HS._err, HS.END, HS.X0_DQ, - /* 10: X00 */ - HS._err, HS._err, HS._err, HS.S400_X0, HS._err, HS._err, HS._err, HS.X00_S9, HS.END, HS.X00_DQ, - /* 11: S400_DQ */ - HS.END, HS.END, HS.END, HS.END, HS.END, HS.END, HS.END, HS.END, HS._err, HS._err, - /* 12: S400_400_DQ*/ - HS._err, HS._err, HS.END, HS.END, HS.END, HS.END, HS.END, HS.END, HS._err, HS._err, - /* 13: S400_400_100*/ - HS._err, HS._err, HS._err, HS.S400_X00_X0, HS._err, HS._err, HS._err, HS.X00_S9, HS._err, HS.X00_DQ, - /* 14: S9 */ - HS._err, HS._err, HS._err, HS._err, HS._err, HS._err, HS._err, HS._err, HS.END, HS.S9_DQ, - /* 15: X00_S9 */ - HS._err, HS._err, HS._err, HS._err, HS._err, HS._err, HS._err, HS._err, HS._err, HS.S9_DQ, - /* 16: S9_DQ */ - HS._err, HS._err, HS._err, HS._err, HS._err, HS.END, HS.END, HS._err, HS._err, HS._err - }; - - // Count of valid HebrewToken, column count in the NumberPasingState array - private const int HebrewTokenCount = 10; - - //////////////////////////////////////////////////////////////////////// - // - // Actions: - // Parse the Hebrew number by passing one character at a time. - // The state between characters are maintained at HebrewNumberPasingContext. - // Returns: - // Return a enum of HebrewNumberParsingState. - // NotHebrewDigit: The specified ch is not a valid Hebrew digit. - // InvalidHebrewNumber: After parsing the specified ch, it will lead into - // an invalid Hebrew number text. - // FoundEndOfHebrewNumber: A terminal state is reached. This means that - // we find a valid Hebrew number text after the specified ch is parsed. - // ContinueParsing: The specified ch is a valid Hebrew digit, and - // it will lead into a valid state in the state machine, we should - // continue to parse incoming characters. - // - //////////////////////////////////////////////////////////////////////// - - internal static HebrewNumberParsingState ParseByChar(char ch, ref HebrewNumberParsingContext context) - { - Debug.Assert(s_numberPasingState.Length == HebrewTokenCount * ((int)HS.S9_DQ + 1)); - - HebrewToken token; - if (ch == '\'') - { - token = HebrewToken.SingleQuote; - } - else if (ch == '\"') - { - token = HebrewToken.DoubleQuote; - } - else - { - int index = (int)ch - minHebrewNumberCh; - if (index >= 0 && index < s_hebrewValues.Length) - { - token = s_hebrewValues[index].token; - if (token == HebrewToken.Invalid) - { - return HebrewNumberParsingState.NotHebrewDigit; - } - context.result += s_hebrewValues[index].value; - } - else - { - // Not in valid Hebrew digit range. - return HebrewNumberParsingState.NotHebrewDigit; - } - } - context.state = s_numberPasingState[(int)context.state * (int)HebrewTokenCount + (int)token]; - if (context.state == HS._err) - { - // Invalid Hebrew state. This indicates an incorrect Hebrew number. - return HebrewNumberParsingState.InvalidHebrewNumber; - } - if (context.state == HS.END) - { - // Reach a terminal state. - return HebrewNumberParsingState.FoundEndOfHebrewNumber; - } - // We should continue to parse. - return HebrewNumberParsingState.ContinueParsing; - } - - //////////////////////////////////////////////////////////////////////// - // - // Actions: - // Check if the ch is a valid Hebrew number digit. - // This function will return true if the specified char is a legal Hebrew - // digit character, single quote, or double quote. - // Returns: - // true if the specified character is a valid Hebrew number character. - // - //////////////////////////////////////////////////////////////////////// - - internal static bool IsDigit(char ch) - { - if (ch >= minHebrewNumberCh && ch <= s_maxHebrewNumberCh) - { - return s_hebrewValues[ch - minHebrewNumberCh].value >= 0; - } - return ch == '\'' || ch == '\"'; - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/HijriCalendar.Unix.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/HijriCalendar.Unix.cs deleted file mode 100644 index a6e8f73d3e4..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/HijriCalendar.Unix.cs +++ /dev/null @@ -1,15 +0,0 @@ -// 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 HijriCalendar : Calendar - { - private static int GetHijriDateAdjustment() - { - // this setting is not supported on Unix, so always return 0 - return 0; - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/HijriCalendar.Win32.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/HijriCalendar.Win32.cs deleted file mode 100644 index d8f69fb5bb3..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/HijriCalendar.Win32.cs +++ /dev/null @@ -1,83 +0,0 @@ -// 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.Win32; - -namespace System.Globalization -{ - public partial class HijriCalendar : Calendar - { - private int GetHijriDateAdjustment() - { - if (_hijriAdvance == int.MinValue) - { - // Never been set before. Use the system value from registry. - _hijriAdvance = GetAdvanceHijriDate(); - } - return _hijriAdvance; - } - - private const string InternationalRegKey = "Control Panel\\International"; - private const string HijriAdvanceRegKeyEntry = "AddHijriDate"; - - /*=================================GetAdvanceHijriDate========================== - **Action: Gets the AddHijriDate value from the registry. - **Returns: - **Arguments: None. - **Exceptions: - **Note: - ** The HijriCalendar has a user-overidable calculation. That is, use can set a value from the control - ** panel, so that the calculation of the Hijri Calendar can move ahead or backwards from -2 to +2 days. - ** - ** The valid string values in the registry are: - ** "AddHijriDate-2" => Add -2 days to the current calculated Hijri date. - ** "AddHijriDate" => Add -1 day to the current calculated Hijri date. - ** "" => Add 0 day to the current calculated Hijri date. - ** "AddHijriDate+1" => Add +1 days to the current calculated Hijri date. - ** "AddHijriDate+2" => Add +2 days to the current calculated Hijri date. - ============================================================================*/ - private static int GetAdvanceHijriDate() - { - using (RegistryKey? key = Registry.CurrentUser.OpenSubKey(InternationalRegKey)) - { - // Abort if we didn't find anything - if (key == null) - { - return 0; - } - - object? value = key.GetValue(HijriAdvanceRegKeyEntry); - if (value == null) - { - return 0; - } - - int hijriAdvance = 0; - string? str = value.ToString(); - if (string.Compare(str, 0, HijriAdvanceRegKeyEntry, 0, HijriAdvanceRegKeyEntry.Length, StringComparison.OrdinalIgnoreCase) == 0) - { - if (str!.Length == HijriAdvanceRegKeyEntry.Length) - hijriAdvance = -1; - else - { - try - { - int advance = int.Parse(str.AsSpan(HijriAdvanceRegKeyEntry.Length), provider: CultureInfo.InvariantCulture); - if ((advance >= MinAdvancedHijri) && (advance <= MaxAdvancedHijri)) - { - hijriAdvance = advance; - } - } - // If we got garbage from registry just ignore it. - // hijriAdvance = 0 because of declaraction assignment up above. - catch (ArgumentException) { } - catch (FormatException) { } - catch (OverflowException) { } - } - } - return hijriAdvance; - } - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/HijriCalendar.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/HijriCalendar.cs deleted file mode 100644 index 4a4c667a5d5..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/HijriCalendar.cs +++ /dev/null @@ -1,473 +0,0 @@ -// 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 -{ - /// <remarks> - /// Rules for the Hijri calendar: - /// - The Hijri calendar is a strictly Lunar calendar. - /// - Days begin at sunset. - /// - Islamic Year 1 (Muharram 1, 1 A.H.) is equivalent to absolute date - /// 227015 (Friday, July 16, 622 C.E. - Julian). - /// - Leap Years occur in the 2, 5, 7, 10, 13, 16, 18, 21, 24, 26, & 29th - /// years of a 30-year cycle. Year = leap iff ((11y+14) mod 30 < 11). - /// - There are 12 months which contain alternately 30 and 29 days. - /// - The 12th month, Dhu al-Hijjah, contains 30 days instead of 29 days - /// in a leap year. - /// - Common years have 354 days. Leap years have 355 days. - /// - There are 10,631 days in a 30-year cycle. - /// - The Islamic months are: - /// 1. Muharram (30 days) 7. Rajab (30 days) - /// 2. Safar (29 days) 8. Sha'ban (29 days) - /// 3. Rabi I (30 days) 9. Ramadan (30 days) - /// 4. Rabi II (29 days) 10. Shawwal (29 days) - /// 5. Jumada I (30 days) 11. Dhu al-Qada (30 days) - /// 6. Jumada II (29 days) 12. Dhu al-Hijjah (29 days) {30} - /// - /// NOTENOTE - /// The calculation of the HijriCalendar is based on the absolute date. And the - /// absolute date means the number of days from January 1st, 1 A.D. - /// Therefore, we do not support the days before the January 1st, 1 A.D. - /// - /// Calendar support range: - /// Calendar Minimum Maximum - /// ========== ========== ========== - /// Gregorian 0622/07/18 9999/12/31 - /// Hijri 0001/01/01 9666/04/03 - /// </remarks> - - public partial class HijriCalendar : Calendar - { - public static readonly int HijriEra = 1; - - private const int DatePartYear = 0; - private const int DatePartDayOfYear = 1; - private const int DatePartMonth = 2; - private const int DatePartDay = 3; - - private const int MinAdvancedHijri = -2; - private const int MaxAdvancedHijri = 2; - - private static readonly int[] s_hijriMonthDays = { 0, 30, 59, 89, 118, 148, 177, 207, 236, 266, 295, 325, 355 }; - - private int _hijriAdvance = int.MinValue; - - // DateTime.MaxValue = Hijri calendar (year:9666, month: 4, day: 3). - private const int MaxCalendarYear = 9666; - private const int MaxCalendarMonth = 4; - - // Hijri calendar (year: 1, month: 1, day:1 ) = Gregorian (year: 622, month: 7, day: 18) - // This is the minimal Gregorian date that we support in the HijriCalendar. - private static readonly DateTime s_calendarMinValue = new DateTime(622, 7, 18); - private static readonly DateTime s_calendarMaxValue = DateTime.MaxValue; - - public override DateTime MinSupportedDateTime => s_calendarMinValue; - - public override DateTime MaxSupportedDateTime => s_calendarMaxValue; - - public override CalendarAlgorithmType AlgorithmType => CalendarAlgorithmType.LunarCalendar; - - public HijriCalendar() - { - } - - internal override CalendarId ID => CalendarId.HIJRI; - - protected override int DaysInYearBeforeMinSupportedYear => - // the year before the 1st year of the cycle would have been the 30th year - // of the previous cycle which is not a leap year. Common years have 354 days. - 354; - - private long GetAbsoluteDateHijri(int y, int m, int d) - { - return (long)(DaysUpToHijriYear(y) + s_hijriMonthDays[m - 1] + d - 1 - HijriAdjustment); - } - - private long DaysUpToHijriYear(int HijriYear) - { - // Compute the number of years up to the current 30 year cycle. - int numYear30 = ((HijriYear - 1) / 30) * 30; - - // Compute the number of years left. This is the number of years - // into the 30 year cycle for the given year. - int numYearsLeft = HijriYear - numYear30 - 1; - - // Compute the number of absolute days up to the given year. - long numDays = ((numYear30 * 10631L) / 30L) + 227013L; - while (numYearsLeft > 0) - { - // Common year is 354 days, and leap year is 355 days. - numDays += 354 + (IsLeapYear(numYearsLeft, CurrentEra) ? 1 : 0); - numYearsLeft--; - } - - return numDays; - } - - public int HijriAdjustment - { - get - { - if (_hijriAdvance == int.MinValue) - { - // Never been set before. Use the system value from registry. - _hijriAdvance = GetHijriDateAdjustment(); - } - - return _hijriAdvance; - } - - set - { - if (value < MinAdvancedHijri || value > MaxAdvancedHijri) - { - throw new ArgumentOutOfRangeException( - nameof(value), - value, - SR.Format(SR.ArgumentOutOfRange_Bounds_Lower_Upper, MinAdvancedHijri, MaxAdvancedHijri)); - } - - VerifyWritable(); - _hijriAdvance = value; - } - } - - internal static void CheckTicksRange(long ticks) - { - if (ticks < s_calendarMinValue.Ticks || ticks > s_calendarMaxValue.Ticks) - { - throw new ArgumentOutOfRangeException( - "time", - ticks, - SR.Format( - CultureInfo.InvariantCulture, - SR.ArgumentOutOfRange_CalendarRange, - s_calendarMinValue, - s_calendarMaxValue)); - } - } - - internal static void CheckEraRange(int era) - { - if (era != CurrentEra && era != HijriEra) - { - throw new ArgumentOutOfRangeException(nameof(era), era, SR.ArgumentOutOfRange_InvalidEraValue); - } - } - - internal static void CheckYearRange(int year, int era) - { - CheckEraRange(era); - if (year < 1 || year > MaxCalendarYear) - { - throw new ArgumentOutOfRangeException( - nameof(year), - SR.Format(SR.ArgumentOutOfRange_Range, 1, MaxCalendarYear)); - } - } - - internal static void CheckYearMonthRange(int year, int month, int era) - { - CheckYearRange(year, era); - if (year == MaxCalendarYear) - { - if (month > MaxCalendarMonth) - { - throw new ArgumentOutOfRangeException( - nameof(month), - month, - SR.Format(SR.ArgumentOutOfRange_Range, 1, MaxCalendarMonth)); - } - } - - if (month < 1 || month > 12) - { - throw new ArgumentOutOfRangeException(nameof(month), month, SR.ArgumentOutOfRange_Month); - } - } - - /// <summary> - /// First, we get the absolute date (the number of days from January 1st, 1 A.C) for the given ticks. - /// Use the formula (((AbsoluteDate - 227013) * 30) / 10631) + 1, we can a rough value for the Hijri year. - /// In order to get the exact Hijri year, we compare the exact absolute date for HijriYear and (HijriYear + 1). - /// From here, we can get the correct Hijri year. - /// </summary> - internal virtual int GetDatePart(long ticks, int part) - { - CheckTicksRange(ticks); - - // Get the absolute date. The absolute date is the number of days from January 1st, 1 A.D. - // 1/1/0001 is absolute date 1. - long numDays = ticks / GregorianCalendar.TicksPerDay + 1; - - // See how much we need to backup or advance - numDays += HijriAdjustment; - - // Calculate the appromixate Hijri Year from this magic formula. - int hijriYear = (int)(((numDays - 227013) * 30) / 10631) + 1; - - long daysToHijriYear = DaysUpToHijriYear(hijriYear); // The absolute date for HijriYear - long daysOfHijriYear = GetDaysInYear(hijriYear, CurrentEra); // The number of days for (HijriYear+1) year. - - if (numDays < daysToHijriYear) - { - daysToHijriYear -= daysOfHijriYear; - hijriYear--; - } - else if (numDays == daysToHijriYear) - { - hijriYear--; - daysToHijriYear -= GetDaysInYear(hijriYear, CurrentEra); - } - else - { - if (numDays > daysToHijriYear + daysOfHijriYear) - { - daysToHijriYear += daysOfHijriYear; - hijriYear++; - } - } - if (part == DatePartYear) - { - return hijriYear; - } - - // Calculate the Hijri Month. - int hijriMonth = 1; - numDays -= daysToHijriYear; - - if (part == DatePartDayOfYear) - { - return (int)numDays; - } - - while ((hijriMonth <= 12) && (numDays > s_hijriMonthDays[hijriMonth - 1])) - { - hijriMonth++; - } - hijriMonth--; - - if (part == DatePartMonth) - { - return hijriMonth; - } - - // Calculate the Hijri Day. - int hijriDay = (int)(numDays - s_hijriMonthDays[hijriMonth - 1]); - - if (part == DatePartDay) - { - return hijriDay; - } - - // Incorrect part value. - throw new InvalidOperationException(SR.InvalidOperation_DateTimeParsing); - } - - public override DateTime AddMonths(DateTime time, int months) - { - if (months < -120000 || months > 120000) - { - throw new ArgumentOutOfRangeException( - nameof(months), - months, - SR.Format(SR.ArgumentOutOfRange_Range, -120000, 120000)); - } - - // Get the date in Hijri calendar. - int y = GetDatePart(time.Ticks, DatePartYear); - int m = GetDatePart(time.Ticks, DatePartMonth); - int d = GetDatePart(time.Ticks, DatePartDay); - int i = m - 1 + months; - if (i >= 0) - { - m = i % 12 + 1; - y += i / 12; - } - else - { - m = 12 + (i + 1) % 12; - y += (i - 11) / 12; - } - - int days = GetDaysInMonth(y, m); - if (d > days) - { - d = days; - } - - long ticks = GetAbsoluteDateHijri(y, m, d) * TicksPerDay + (time.Ticks % TicksPerDay); - Calendar.CheckAddResult(ticks, MinSupportedDateTime, MaxSupportedDateTime); - return new DateTime(ticks); - } - - public override DateTime AddYears(DateTime time, int years) - { - return AddMonths(time, years * 12); - } - - public override int GetDayOfMonth(DateTime time) - { - return GetDatePart(time.Ticks, DatePartDay); - } - - public override DayOfWeek GetDayOfWeek(DateTime time) - { - return (DayOfWeek)((int)(time.Ticks / TicksPerDay + 1) % 7); - } - - public override int GetDayOfYear(DateTime time) - { - return GetDatePart(time.Ticks, DatePartDayOfYear); - } - - public override int GetDaysInMonth(int year, int month, int era) - { - CheckYearMonthRange(year, month, era); - if (month == 12) - { - // For the 12th month, leap year has 30 days, and common year has 29 days. - return IsLeapYear(year, CurrentEra) ? 30 : 29; - } - - // Other months contain 30 and 29 days alternatively. The 1st month has 30 days. - return ((month % 2) == 1) ? 30 : 29; - } - - public override int GetDaysInYear(int year, int era) - { - CheckYearRange(year, era); - // Common years have 354 days. Leap years have 355 days. - return IsLeapYear(year, CurrentEra) ? 355 : 354; - } - - public override int GetEra(DateTime time) - { - CheckTicksRange(time.Ticks); - return HijriEra; - } - - public override int[] Eras => new int[] { HijriEra }; - - public override int GetMonth(DateTime time) - { - return GetDatePart(time.Ticks, DatePartMonth); - } - - public override int GetMonthsInYear(int year, int era) - { - CheckYearRange(year, era); - return 12; - } - - public override int GetYear(DateTime time) - { - return GetDatePart(time.Ticks, DatePartYear); - } - - public override bool IsLeapDay(int year, int month, int day, int era) - { - // The year/month/era value checking is done in GetDaysInMonth(). - int daysInMonth = GetDaysInMonth(year, month, era); - if (day < 1 || day > daysInMonth) - { - throw new ArgumentOutOfRangeException( - nameof(day), - day, - SR.Format(SR.ArgumentOutOfRange_Day, daysInMonth, month)); - } - - return IsLeapYear(year, era) && month == 12 && day == 30; - } - - public override int GetLeapMonth(int year, int era) - { - CheckYearRange(year, era); - return 0; - } - - public override bool IsLeapMonth(int year, int month, int era) - { - CheckYearMonthRange(year, month, era); - return false; - } - - public override bool IsLeapYear(int year, int era) - { - CheckYearRange(year, era); - return (((year * 11) + 14) % 30) < 11; - } - - public override DateTime ToDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int era) - { - // The year/month/era checking is done in GetDaysInMonth(). - int daysInMonth = GetDaysInMonth(year, month, era); - if (day < 1 || day > daysInMonth) - { - throw new ArgumentOutOfRangeException( - nameof(day), - day, - SR.Format(SR.ArgumentOutOfRange_Day, daysInMonth, month)); - } - - long lDate = GetAbsoluteDateHijri(year, month, day); - if (lDate < 0) - { - throw new ArgumentOutOfRangeException(null, SR.ArgumentOutOfRange_BadYearMonthDay); - } - - return new DateTime(lDate * GregorianCalendar.TicksPerDay + TimeToTicks(hour, minute, second, millisecond)); - } - - private const int DefaultTwoDigitYearMax = 1451; - - public override int TwoDigitYearMax - { - get - { - if (_twoDigitYearMax == -1) - { - _twoDigitYearMax = GetSystemTwoDigitYearSetting(ID, DefaultTwoDigitYearMax); - } - - return _twoDigitYearMax; - } - set - { - VerifyWritable(); - if (value < 99 || value > MaxCalendarYear) - { - throw new ArgumentOutOfRangeException( - nameof(value), - value, - SR.Format(SR.ArgumentOutOfRange_Range, 99, MaxCalendarYear)); - } - - _twoDigitYearMax = value; - } - } - - public override int ToFourDigitYear(int year) - { - if (year < 0) - { - throw new ArgumentOutOfRangeException(nameof(year), year, SR.ArgumentOutOfRange_NeedNonNegNum); - } - - if (year < 100) - { - return base.ToFourDigitYear(year); - } - - if (year > MaxCalendarYear) - { - throw new ArgumentOutOfRangeException( - nameof(year), - year, - SR.Format(SR.ArgumentOutOfRange_Range, 1, MaxCalendarYear)); - } - return year; - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/ISOWeek.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/ISOWeek.cs deleted file mode 100644 index 1c0a909abbc..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/ISOWeek.cs +++ /dev/null @@ -1,162 +0,0 @@ -// 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 static System.Globalization.GregorianCalendar; - -namespace System.Globalization -{ - public static class ISOWeek - { - private const int WeeksInLongYear = 53; - private const int WeeksInShortYear = 52; - - private const int MinWeek = 1; - private const int MaxWeek = WeeksInLongYear; - - public static int GetWeekOfYear(DateTime date) - { - int week = GetWeekNumber(date); - - if (week < MinWeek) - { - // If the week number obtained equals 0, it means that the - // given date belongs to the preceding (week-based) year. - return GetWeeksInYear(date.Year - 1); - } - - if (week > GetWeeksInYear(date.Year)) - { - // If a week number of 53 is obtained, one must check that - // the date is not actually in week 1 of the following year. - return MinWeek; - } - - return week; - } - - public static int GetYear(DateTime date) - { - int week = GetWeekNumber(date); - - if (week < MinWeek) - { - // If the week number obtained equals 0, it means that the - // given date belongs to the preceding (week-based) year. - return date.Year - 1; - } - - if (week > GetWeeksInYear(date.Year)) - { - // If a week number of 53 is obtained, one must check that - // the date is not actually in week 1 of the following year. - return date.Year + 1; - } - - return date.Year; - } - - // The year parameter represents an ISO week-numbering year (also called ISO year informally). - // Each week's year is the Gregorian year in which the Thursday falls. - // The first week of the year, hence, always contains 4 January. - // ISO week year numbering therefore slightly deviates from the Gregorian for some days close to 1 January. - public static DateTime GetYearStart(int year) - { - return ToDateTime(year, MinWeek, DayOfWeek.Monday); - } - - // The year parameter represents an ISO week-numbering year (also called ISO year informally). - // Each week's year is the Gregorian year in which the Thursday falls. - // The first week of the year, hence, always contains 4 January. - // ISO week year numbering therefore slightly deviates from the Gregorian for some days close to 1 January. - public static DateTime GetYearEnd(int year) - { - return ToDateTime(year, GetWeeksInYear(year), DayOfWeek.Sunday); - } - - // From https://en.wikipedia.org/wiki/ISO_week_date#Weeks_per_year: - // - // The long years, with 53 weeks in them, can be described by any of the following equivalent definitions: - // - // - Any year starting on Thursday and any leap year starting on Wednesday. - // - Any year ending on Thursday and any leap year ending on Friday. - // - Years in which 1 January and 31 December (in common years) or either (in leap years) are Thursdays. - // - // All other week-numbering years are short years and have 52 weeks. - public static int GetWeeksInYear(int year) - { - if (year < MinYear || year > MaxYear) - { - throw new ArgumentOutOfRangeException(nameof(year), SR.ArgumentOutOfRange_Year); - } - - static int P(int y) => (y + (y / 4) - (y / 100) + (y / 400)) % 7; - - if (P(year) == 4 || P(year - 1) == 3) - { - return WeeksInLongYear; - } - - return WeeksInShortYear; - } - - // From https://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year,_week_number_and_weekday: - // - // This method requires that one know the weekday of 4 January of the year in question. - // Add 3 to the number of this weekday, giving a correction to be used for dates within this year. - // - // Multiply the week number by 7, then add the weekday. From this sum subtract the correction for the year. - // The result is the ordinal date, which can be converted into a calendar date. - // - // If the ordinal date thus obtained is zero or negative, the date belongs to the previous calendar year. - // If greater than the number of days in the year, to the following year. - public static DateTime ToDateTime(int year, int week, DayOfWeek dayOfWeek) - { - if (year < MinYear || year > MaxYear) - { - throw new ArgumentOutOfRangeException(nameof(year), SR.ArgumentOutOfRange_Year); - } - - if (week < MinWeek || week > MaxWeek) - { - throw new ArgumentOutOfRangeException(nameof(week), SR.ArgumentOutOfRange_Week_ISO); - } - - // We allow 7 for convenience in cases where a user already has a valid ISO - // day of week value for Sunday. This means that both 0 and 7 will map to Sunday. - // The GetWeekday method will normalize this into the 1-7 range required by ISO. - if ((int)dayOfWeek < 0 || (int)dayOfWeek > 7) - { - throw new ArgumentOutOfRangeException(nameof(dayOfWeek), SR.ArgumentOutOfRange_DayOfWeek); - } - - var jan4 = new DateTime(year, month: 1, day: 4); - - int correction = GetWeekday(jan4.DayOfWeek) + 3; - - int ordinal = (week * 7) + GetWeekday(dayOfWeek) - correction; - - return new DateTime(year, month: 1, day: 1).AddDays(ordinal - 1); - } - - // From https://en.wikipedia.org/wiki/ISO_week_date#Calculating_the_week_number_of_a_given_date: - // - // Using ISO weekday numbers (running from 1 for Monday to 7 for Sunday), - // subtract the weekday from the ordinal date, then add 10. Divide the result by 7. - // Ignore the remainder; the quotient equals the week number. - // - // If the week number thus obtained equals 0, it means that the given date belongs to the preceding (week-based) year. - // If a week number of 53 is obtained, one must check that the date is not actually in week 1 of the following year. - private static int GetWeekNumber(DateTime date) - { - return (date.DayOfYear - GetWeekday(date.DayOfWeek) + 10) / 7; - } - - // Day of week in ISO is represented by an integer from 1 through 7, beginning with Monday and ending with Sunday. - // This matches the underlying values of the DayOfWeek enum, except for Sunday, which needs to be converted. - private static int GetWeekday(DayOfWeek dayOfWeek) - { - return dayOfWeek == DayOfWeek.Sunday ? 7 : (int)dayOfWeek; - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/IdnMapping.Unix.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/IdnMapping.Unix.cs deleted file mode 100644 index 4c6ee2c4041..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/IdnMapping.Unix.cs +++ /dev/null @@ -1,145 +0,0 @@ -// 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; - -namespace System.Globalization -{ - public sealed partial class IdnMapping - { - private unsafe string GetAsciiCore(string unicodeString, char* unicode, int count) - { - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert(unicodeString != null && unicodeString.Length >= count); - - uint flags = Flags; - CheckInvalidIdnCharacters(unicode, count, flags, nameof(unicode)); - - const int StackallocThreshold = 512; - // Each unicode character is represented by up to 3 ASCII chars - // and the whole string is prefixed by "xn--" (length 4) - int estimatedLength = (int)Math.Min(count * 3L + 4, StackallocThreshold); - int actualLength; - if (estimatedLength < StackallocThreshold) - { - char* outputStack = stackalloc char[estimatedLength]; - actualLength = Interop.Globalization.ToAscii(flags, unicode, count, outputStack, estimatedLength); - if (actualLength > 0 && actualLength <= estimatedLength) - { - return GetStringForOutput(unicodeString, unicode, count, outputStack, actualLength); - } - } - else - { - actualLength = Interop.Globalization.ToAscii(flags, unicode, count, null, 0); - } - if (actualLength == 0) - { - throw new ArgumentException(SR.Argument_IdnIllegalName, nameof(unicode)); - } - - char[] outputHeap = new char[actualLength]; - fixed (char* pOutputHeap = &outputHeap[0]) - { - actualLength = Interop.Globalization.ToAscii(flags, unicode, count, pOutputHeap, actualLength); - if (actualLength == 0 || actualLength > outputHeap.Length) - { - throw new ArgumentException(SR.Argument_IdnIllegalName, nameof(unicode)); - } - return GetStringForOutput(unicodeString, unicode, count, pOutputHeap, actualLength); - } - } - - private unsafe string GetUnicodeCore(string asciiString, char* ascii, int count) - { - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert(asciiString != null && asciiString.Length >= count); - - uint flags = Flags; - CheckInvalidIdnCharacters(ascii, count, flags, nameof(ascii)); - - const int StackAllocThreshold = 512; - if (count < StackAllocThreshold) - { - char* output = stackalloc char[count]; - return GetUnicodeCore(asciiString, ascii, count, flags, output, count, reattempt: true); - } - else - { - char[] output = new char[count]; - fixed (char* pOutput = &output[0]) - { - return GetUnicodeCore(asciiString, ascii, count, flags, pOutput, count, reattempt: true); - } - } - } - - private unsafe string GetUnicodeCore(string asciiString, char* ascii, int count, uint flags, char* output, int outputLength, bool reattempt) - { - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert(asciiString != null && asciiString.Length >= count); - - int realLen = Interop.Globalization.ToUnicode(flags, ascii, count, output, outputLength); - - if (realLen == 0) - { - throw new ArgumentException(SR.Argument_IdnIllegalName, nameof(ascii)); - } - else if (realLen <= outputLength) - { - return GetStringForOutput(asciiString, ascii, count, output, realLen); - } - else if (reattempt) - { - char[] newOutput = new char[realLen]; - fixed (char* pNewOutput = newOutput) - { - return GetUnicodeCore(asciiString, ascii, count, flags, pNewOutput, realLen, reattempt: false); - } - } - - throw new ArgumentException(SR.Argument_IdnIllegalName, nameof(ascii)); - } - - // ----------------------------- - // ---- PAL layer ends here ---- - // ----------------------------- - - private uint Flags - { - get - { - int flags = - (AllowUnassigned ? Interop.Globalization.AllowUnassigned : 0) | - (UseStd3AsciiRules ? Interop.Globalization.UseStd3AsciiRules : 0); - return (uint)flags; - } - } - - /// <summary> - /// ICU doesn't check for invalid characters unless the STD3 rules option - /// is enabled. - /// - /// To match Windows behavior, we walk the string ourselves looking for these - /// bad characters so we can continue to throw ArgumentException in these cases. - /// </summary> - private static unsafe void CheckInvalidIdnCharacters(char* s, int count, uint flags, string paramName) - { - if ((flags & Interop.Globalization.UseStd3AsciiRules) == 0) - { - for (int i = 0; i < count; i++) - { - char c = s[i]; - - // These characters are prohibited regardless of the UseStd3AsciiRules property. - // See https://msdn.microsoft.com/en-us/library/system.globalization.idnmapping.usestd3asciirules(v=vs.110).aspx - if (c <= 0x1F || c == 0x7F) - { - throw new ArgumentException(SR.Argument_IdnIllegalName, paramName); - } - } - } - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/IdnMapping.Windows.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/IdnMapping.Windows.cs deleted file mode 100644 index 6a97c04ebf6..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/IdnMapping.Windows.cs +++ /dev/null @@ -1,129 +0,0 @@ -// 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; -using System.Diagnostics.CodeAnalysis; -using System.Runtime.InteropServices; - -namespace System.Globalization -{ - public sealed partial class IdnMapping - { - private unsafe string GetAsciiCore(string unicodeString, char* unicode, int count) - { - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert(unicodeString != null && unicodeString.Length >= count); - - uint flags = Flags; - - // Determine the required length - int length = Interop.Normaliz.IdnToAscii(flags, unicode, count, null, 0); - if (length == 0) - { - ThrowForZeroLength(unicode: true); - } - - // Do the conversion - const int StackAllocThreshold = 512; // arbitrary limit to switch from stack to heap allocation - if (length < StackAllocThreshold) - { - char* output = stackalloc char[length]; - return GetAsciiCore(unicodeString, unicode, count, flags, output, length); - } - else - { - char[] output = new char[length]; - fixed (char* pOutput = &output[0]) - { - return GetAsciiCore(unicodeString, unicode, count, flags, pOutput, length); - } - } - } - - private unsafe string GetAsciiCore(string unicodeString, char* unicode, int count, uint flags, char* output, int outputLength) - { - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert(unicodeString != null && unicodeString.Length >= count); - - int length = Interop.Normaliz.IdnToAscii(flags, unicode, count, output, outputLength); - if (length == 0) - { - ThrowForZeroLength(unicode: true); - } - Debug.Assert(length == outputLength); - return GetStringForOutput(unicodeString, unicode, count, output, length); - } - - private unsafe string GetUnicodeCore(string asciiString, char* ascii, int count) - { - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert(asciiString != null && asciiString.Length >= count); - - uint flags = Flags; - - // Determine the required length - int length = Interop.Normaliz.IdnToUnicode(flags, ascii, count, null, 0); - if (length == 0) - { - ThrowForZeroLength(unicode: false); - } - - // Do the conversion - const int StackAllocThreshold = 512; // arbitrary limit to switch from stack to heap allocation - if (length < StackAllocThreshold) - { - char* output = stackalloc char[length]; - return GetUnicodeCore(asciiString, ascii, count, flags, output, length); - } - else - { - char[] output = new char[length]; - fixed (char* pOutput = &output[0]) - { - return GetUnicodeCore(asciiString, ascii, count, flags, pOutput, length); - } - } - } - - private unsafe string GetUnicodeCore(string asciiString, char* ascii, int count, uint flags, char* output, int outputLength) - { - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert(asciiString != null && asciiString.Length >= count); - - int length = Interop.Normaliz.IdnToUnicode(flags, ascii, count, output, outputLength); - if (length == 0) - { - ThrowForZeroLength(unicode: false); - } - Debug.Assert(length == outputLength); - return GetStringForOutput(asciiString, ascii, count, output, length); - } - - // ----------------------------- - // ---- PAL layer ends here ---- - // ----------------------------- - - private uint Flags - { - get - { - int flags = - (AllowUnassigned ? Interop.Normaliz.IDN_ALLOW_UNASSIGNED : 0) | - (UseStd3AsciiRules ? Interop.Normaliz.IDN_USE_STD3_ASCII_RULES : 0); - return (uint)flags; - } - } - - [DoesNotReturn] - private static void ThrowForZeroLength(bool unicode) - { - int lastError = Marshal.GetLastWin32Error(); - - throw new ArgumentException( - lastError == Interop.Errors.ERROR_INVALID_NAME ? SR.Argument_IdnIllegalName : - (unicode ? SR.Argument_InvalidCharSequenceNoIndex : SR.Argument_IdnBadPunycode), - unicode ? "unicode" : "ascii"); - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/IdnMapping.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/IdnMapping.cs deleted file mode 100644 index 2035932a82e..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/IdnMapping.cs +++ /dev/null @@ -1,871 +0,0 @@ -// 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. - -// This file contains the IDN functions and implementation. -// -// This allows encoding of non-ASCII domain names in a "punycode" form, -// for example: -// -// \u5B89\u5BA4\u5948\u7F8E\u6075-with-SUPER-MONKEYS -// -// is encoded as: -// -// xn---with-SUPER-MONKEYS-pc58ag80a8qai00g7n9n -// -// Additional options are provided to allow unassigned IDN characters and -// to validate according to the Std3ASCII Rules (like DNS names). -// -// There are also rules regarding bidirectionality of text and the length -// of segments. -// -// For additional rules see also: -// RFC 3490 - Internationalizing Domain Names in Applications (IDNA) -// RFC 3491 - Nameprep: A Stringprep Profile for Internationalized Domain Names (IDN) -// RFC 3492 - Punycode: A Bootstring encoding of Unicode for Internationalized Domain Names in Applications (IDNA) - -using System.Diagnostics; -using System.Runtime.CompilerServices; -using System.Text; - -namespace System.Globalization -{ - // IdnMapping class used to map names to Punycode - public sealed partial class IdnMapping - { - private bool _allowUnassigned; - private bool _useStd3AsciiRules; - - public IdnMapping() - { - } - - public bool AllowUnassigned - { - get => _allowUnassigned; - set => _allowUnassigned = value; - } - - public bool UseStd3AsciiRules - { - get => _useStd3AsciiRules; - set => _useStd3AsciiRules = value; - } - - // Gets ASCII (Punycode) version of the string - public string GetAscii(string unicode) => - GetAscii(unicode, 0); - - public string GetAscii(string unicode, int index) - { - if (unicode == null) - throw new ArgumentNullException(nameof(unicode)); - return GetAscii(unicode, index, unicode.Length - index); - } - - public string GetAscii(string unicode, int index, int count) - { - if (unicode == null) - throw new ArgumentNullException(nameof(unicode)); - if (index < 0 || count < 0) - throw new ArgumentOutOfRangeException((index < 0) ? nameof(index) : nameof(count), SR.ArgumentOutOfRange_NeedNonNegNum); - if (index > unicode.Length) - throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_Index); - if (index > unicode.Length - count) - throw new ArgumentOutOfRangeException(nameof(unicode), SR.ArgumentOutOfRange_IndexCountBuffer); - - if (count == 0) - { - throw new ArgumentException(SR.Argument_IdnBadLabelSize, nameof(unicode)); - } - if (unicode[index + count - 1] == 0) - { - throw new ArgumentException(SR.Format(SR.Argument_InvalidCharSequence, index + count - 1), nameof(unicode)); - } - - if (GlobalizationMode.Invariant) - { - return GetAsciiInvariant(unicode, index, count); - } - - unsafe - { - fixed (char* pUnicode = unicode) - { - return GetAsciiCore(unicode, pUnicode + index, count); - } - } - } - - // Gets Unicode version of the string. Normalized and limited to IDNA characters. - public string GetUnicode(string ascii) => - GetUnicode(ascii, 0); - - public string GetUnicode(string ascii, int index) - { - if (ascii == null) - throw new ArgumentNullException(nameof(ascii)); - return GetUnicode(ascii, index, ascii.Length - index); - } - - public string GetUnicode(string ascii, int index, int count) - { - if (ascii == null) - throw new ArgumentNullException(nameof(ascii)); - if (index < 0 || count < 0) - throw new ArgumentOutOfRangeException((index < 0) ? nameof(index) : nameof(count), SR.ArgumentOutOfRange_NeedNonNegNum); - if (index > ascii.Length) - throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_Index); - if (index > ascii.Length - count) - throw new ArgumentOutOfRangeException(nameof(ascii), SR.ArgumentOutOfRange_IndexCountBuffer); - - // This is a case (i.e. explicitly null-terminated input) where behavior in .NET and Win32 intentionally differ. - // The .NET APIs should (and did in v4.0 and earlier) throw an ArgumentException on input that includes a terminating null. - // The Win32 APIs fail on an embedded null, but not on a terminating null. - if (count > 0 && ascii[index + count - 1] == (char)0) - throw new ArgumentException(SR.Argument_IdnBadPunycode, nameof(ascii)); - - if (GlobalizationMode.Invariant) - { - return GetUnicodeInvariant(ascii, index, count); - } - - unsafe - { - fixed (char* pAscii = ascii) - { - return GetUnicodeCore(ascii, pAscii + index, count); - } - } - } - - public override bool Equals(object? obj) => - obj is IdnMapping that && - _allowUnassigned == that._allowUnassigned && - _useStd3AsciiRules == that._useStd3AsciiRules; - - public override int GetHashCode() => - (_allowUnassigned ? 100 : 200) + (_useStd3AsciiRules ? 1000 : 2000); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static unsafe string GetStringForOutput(string originalString, char* input, int inputLength, char* output, int outputLength) => - originalString.Length == inputLength && new ReadOnlySpan<char>(input, inputLength).SequenceEqual(new ReadOnlySpan<char>(output, outputLength)) ? - originalString : - new string(output, 0, outputLength); - - // - // Invariant implementation - // - - private const char c_delimiter = '-'; - private const string c_strAcePrefix = "xn--"; - private const int c_labelLimit = 63; // Not including dots - private const int c_defaultNameLimit = 255; // Including dots - private const int c_initialN = 0x80; - private const int c_maxint = 0x7ffffff; - private const int c_initialBias = 72; - private const int c_punycodeBase = 36; - private const int c_tmin = 1; - private const int c_tmax = 26; - private const int c_skew = 38; - private const int c_damp = 700; - - // Legal "dot" separators (i.e: . in www.microsoft.com) - private static readonly char[] s_dotSeparators = { '.', '\u3002', '\uFF0E', '\uFF61' }; - - private string GetAsciiInvariant(string unicode, int index, int count) - { - if (index > 0 || count < unicode.Length) - { - unicode = unicode.Substring(index, count); - } - - // Check for ASCII only string, which will be unchanged - if (ValidateStd3AndAscii(unicode, UseStd3AsciiRules, true)) - { - return unicode; - } - - // Cannot be null terminated (normalization won't help us with this one, and - // may have returned false before checking the whole string above) - Debug.Assert(count >= 1, "[IdnMapping.GetAscii] Expected 0 length strings to fail before now."); - if (unicode[^1] <= 0x1f) - { - throw new ArgumentException(SR.Format(SR.Argument_InvalidCharSequence, unicode.Length - 1), nameof(unicode)); - } - - // May need to check Std3 rules again for non-ascii - if (UseStd3AsciiRules) - { - ValidateStd3AndAscii(unicode, true, false); - } - - // Go ahead and encode it - return PunycodeEncode(unicode); - } - - // See if we're only ASCII - private static bool ValidateStd3AndAscii(string unicode, bool bUseStd3, bool bCheckAscii) - { - // If its empty, then its too small - if (unicode.Length == 0) - throw new ArgumentException(SR.Argument_IdnBadLabelSize, nameof(unicode)); - - int iLastDot = -1; - - // Loop the whole string - for (int i = 0; i < unicode.Length; i++) - { - // Aren't allowing control chars (or 7f, but idn tables catch that, they don't catch \0 at end though) - if (unicode[i] <= 0x1f) - { - throw new ArgumentException(SR.Format(SR.Argument_InvalidCharSequence, i), nameof(unicode)); - } - - // If its Unicode or a control character, return false (non-ascii) - if (bCheckAscii && unicode[i] >= 0x7f) - return false; - - // Check for dots - if (IsDot(unicode[i])) - { - // Can't have 2 dots in a row - if (i == iLastDot + 1) - throw new ArgumentException(SR.Argument_IdnBadLabelSize, nameof(unicode)); - - // If its too far between dots then fail - if (i - iLastDot > c_labelLimit + 1) - throw new ArgumentException(SR.Argument_IdnBadLabelSize, nameof(unicode)); - - // If validating Std3, then char before dot can't be - char - if (bUseStd3 && i > 0) - ValidateStd3(unicode[i - 1], true); - - // Remember where the last dot is - iLastDot = i; - continue; - } - - // If necessary, make sure its a valid std3 character - if (bUseStd3) - { - ValidateStd3(unicode[i], i == iLastDot + 1); - } - } - - // If we never had a dot, then we need to be shorter than the label limit - if (iLastDot == -1 && unicode.Length > c_labelLimit) - throw new ArgumentException(SR.Argument_IdnBadLabelSize, nameof(unicode)); - - // Need to validate entire string length, 1 shorter if last char wasn't a dot - if (unicode.Length > c_defaultNameLimit - (IsDot(unicode[^1]) ? 0 : 1)) - throw new ArgumentException(SR.Format(SR.Argument_IdnBadNameSize, - c_defaultNameLimit - (IsDot(unicode[^1]) ? 0 : 1)), nameof(unicode)); - - // If last char wasn't a dot we need to check for trailing - - if (bUseStd3 && !IsDot(unicode[^1])) - ValidateStd3(unicode[^1], true); - - return true; - } - - /* PunycodeEncode() converts Unicode to Punycode. The input */ - /* is represented as an array of Unicode code points (not code */ - /* units; surrogate pairs are not allowed), and the output */ - /* will be represented as an array of ASCII code points. The */ - /* output string is *not* null-terminated; it will contain */ - /* zeros if and only if the input contains zeros. (Of course */ - /* the caller can leave room for a terminator and add one if */ - /* needed.) The input_length is the number of code points in */ - /* the input. The output_length is an in/out argument: the */ - /* caller passes in the maximum number of code points that it */ - - /* can receive, and on successful return it will contain the */ - /* number of code points actually output. The case_flags array */ - /* holds input_length boolean values, where nonzero suggests that */ - /* the corresponding Unicode character be forced to uppercase */ - /* after being decoded (if possible), and zero suggests that */ - /* it be forced to lowercase (if possible). ASCII code points */ - /* are encoded literally, except that ASCII letters are forced */ - /* to uppercase or lowercase according to the corresponding */ - /* uppercase flags. If case_flags is a null pointer then ASCII */ - /* letters are left as they are, and other code points are */ - /* treated as if their uppercase flags were zero. The return */ - /* value can be any of the punycode_status values defined above */ - /* except punycode_bad_input; if not punycode_success, then */ - /* output_size and output might contain garbage. */ - private static string PunycodeEncode(string unicode) - { - // 0 length strings aren't allowed - if (unicode.Length == 0) - throw new ArgumentException(SR.Argument_IdnBadLabelSize, nameof(unicode)); - - StringBuilder output = new StringBuilder(unicode.Length); - int iNextDot = 0; - int iAfterLastDot = 0; - int iOutputAfterLastDot = 0; - - // Find the next dot - while (iNextDot < unicode.Length) - { - // Find end of this segment - iNextDot = unicode.IndexOfAny(s_dotSeparators, iAfterLastDot); - Debug.Assert(iNextDot <= unicode.Length, "[IdnMapping.punycode_encode]IndexOfAny is broken"); - if (iNextDot < 0) - iNextDot = unicode.Length; - - // Only allowed to have empty . section at end (www.microsoft.com.) - if (iNextDot == iAfterLastDot) - { - // Only allowed to have empty sections as trailing . - if (iNextDot != unicode.Length) - throw new ArgumentException(SR.Argument_IdnBadLabelSize, nameof(unicode)); - // Last dot, stop - break; - } - - // We'll need an Ace prefix - output.Append(c_strAcePrefix); - - // Everything resets every segment. - bool bRightToLeft = false; - - // Check for RTL. If right-to-left, then 1st & last chars must be RTL - BidiCategory eBidi = CharUnicodeInfo.GetBidiCategory(unicode, iAfterLastDot); - if (eBidi == BidiCategory.RightToLeft || eBidi == BidiCategory.RightToLeftArabic) - { - // It has to be right to left. - bRightToLeft = true; - - // Check last char - int iTest = iNextDot - 1; - if (char.IsLowSurrogate(unicode, iTest)) - { - iTest--; - } - - eBidi = CharUnicodeInfo.GetBidiCategory(unicode, iTest); - if (eBidi != BidiCategory.RightToLeft && eBidi != BidiCategory.RightToLeftArabic) - { - // Oops, last wasn't RTL, last should be RTL if first is RTL - throw new ArgumentException(SR.Argument_IdnBadBidi, nameof(unicode)); - } - } - - // Handle the basic code points - int basicCount; - int numProcessed = 0; // Num code points that have been processed so far (this segment) - for (basicCount = iAfterLastDot; basicCount < iNextDot; basicCount++) - { - // Can't be lonely surrogate because it would've thrown in normalization - Debug.Assert(!char.IsLowSurrogate(unicode, basicCount), "[IdnMapping.punycode_encode]Unexpected low surrogate"); - - // Double check our bidi rules - BidiCategory testBidi = CharUnicodeInfo.GetBidiCategory(unicode, basicCount); - - // If we're RTL, we can't have LTR chars - if (bRightToLeft && testBidi == BidiCategory.LeftToRight) - { - // Oops, throw error - throw new ArgumentException(SR.Argument_IdnBadBidi, nameof(unicode)); - } - - // If we're not RTL we can't have RTL chars - if (!bRightToLeft && (testBidi == BidiCategory.RightToLeft || testBidi == BidiCategory.RightToLeftArabic)) - { - // Oops, throw error - throw new ArgumentException(SR.Argument_IdnBadBidi, nameof(unicode)); - } - - // If its basic then add it - if (Basic(unicode[basicCount])) - { - output.Append(EncodeBasic(unicode[basicCount])); - numProcessed++; - } - // If its a surrogate, skip the next since our bidi category tester doesn't handle it. - else if (char.IsSurrogatePair(unicode, basicCount)) - basicCount++; - } - - int numBasicCodePoints = numProcessed; // number of basic code points - - // Stop if we ONLY had basic code points - if (numBasicCodePoints == iNextDot - iAfterLastDot) - { - // Get rid of xn-- and this segments done - output.Remove(iOutputAfterLastDot, c_strAcePrefix.Length); - } - else - { - // If it has some non-basic code points the input cannot start with xn-- - if (unicode.Length - iAfterLastDot >= c_strAcePrefix.Length && - unicode.Substring(iAfterLastDot, c_strAcePrefix.Length).Equals( - c_strAcePrefix, StringComparison.OrdinalIgnoreCase)) - throw new ArgumentException(SR.Argument_IdnBadPunycode, nameof(unicode)); - - // Need to do ACE encoding - int numSurrogatePairs = 0; // number of surrogate pairs so far - - // Add a delimiter (-) if we had any basic code points (between basic and encoded pieces) - if (numBasicCodePoints > 0) - { - output.Append(c_delimiter); - } - - // Initialize the state - int n = c_initialN; - int delta = 0; - int bias = c_initialBias; - - // Main loop - while (numProcessed < (iNextDot - iAfterLastDot)) - { - /* All non-basic code points < n have been */ - /* handled already. Find the next larger one: */ - int j; - int m; - int test = 0; - for (m = c_maxint, j = iAfterLastDot; - j < iNextDot; - j += IsSupplementary(test) ? 2 : 1) - { - test = char.ConvertToUtf32(unicode, j); - if (test >= n && test < m) m = test; - } - - /* Increase delta enough to advance the decoder's */ - /* <n,i> state to <m,0>, but guard against overflow: */ - delta += (int)((m - n) * ((numProcessed - numSurrogatePairs) + 1)); - Debug.Assert(delta > 0, "[IdnMapping.cs]1 punycode_encode - delta overflowed int"); - n = m; - - for (j = iAfterLastDot; j < iNextDot; j += IsSupplementary(test) ? 2 : 1) - { - // Make sure we're aware of surrogates - test = char.ConvertToUtf32(unicode, j); - - // Adjust for character position (only the chars in our string already, some - // haven't been processed. - - if (test < n) - { - delta++; - Debug.Assert(delta > 0, "[IdnMapping.cs]2 punycode_encode - delta overflowed int"); - } - - if (test == n) - { - // Represent delta as a generalized variable-length integer: - int q, k; - for (q = delta, k = c_punycodeBase; ; k += c_punycodeBase) - { - int t = k <= bias ? c_tmin : k >= bias + c_tmax ? c_tmax : k - bias; - if (q < t) break; - Debug.Assert(c_punycodeBase != t, "[IdnMapping.punycode_encode]Expected c_punycodeBase (36) to be != t"); - output.Append(EncodeDigit(t + (q - t) % (c_punycodeBase - t))); - q = (q - t) / (c_punycodeBase - t); - } - - output.Append(EncodeDigit(q)); - bias = Adapt(delta, (numProcessed - numSurrogatePairs) + 1, numProcessed == numBasicCodePoints); - delta = 0; - numProcessed++; - - if (IsSupplementary(m)) - { - numProcessed++; - numSurrogatePairs++; - } - } - } - ++delta; - ++n; - Debug.Assert(delta > 0, "[IdnMapping.cs]3 punycode_encode - delta overflowed int"); - } - } - - // Make sure its not too big - if (output.Length - iOutputAfterLastDot > c_labelLimit) - throw new ArgumentException(SR.Argument_IdnBadLabelSize, nameof(unicode)); - - // Done with this segment, add dot if necessary - if (iNextDot != unicode.Length) - output.Append('.'); - - iAfterLastDot = iNextDot + 1; - iOutputAfterLastDot = output.Length; - } - - // Throw if we're too long - if (output.Length > c_defaultNameLimit - (IsDot(unicode[^1]) ? 0 : 1)) - throw new ArgumentException(SR.Format(SR.Argument_IdnBadNameSize, - c_defaultNameLimit - (IsDot(unicode[^1]) ? 0 : 1)), nameof(unicode)); - // Return our output string - return output.ToString(); - } - - // Is it a dot? - // are we U+002E (., full stop), U+3002 (ideographic full stop), U+FF0E (fullwidth full stop), or - // U+FF61 (halfwidth ideographic full stop). - // Note: IDNA Normalization gets rid of dots now, but testing for last dot is before normalization - private static bool IsDot(char c) => - c == '.' || c == '\u3002' || c == '\uFF0E' || c == '\uFF61'; - - private static bool IsSupplementary(int cTest) => - cTest >= 0x10000; - - private static bool Basic(uint cp) => - // Is it in ASCII range? - cp < 0x80; - - // Validate Std3 rules for a character - private static void ValidateStd3(char c, bool bNextToDot) - { - // Check for illegal characters - if (c <= ',' || c == '/' || (c >= ':' && c <= '@') || // Lots of characters not allowed - (c >= '[' && c <= '`') || (c >= '{' && c <= (char)0x7F) || - (c == '-' && bNextToDot)) - throw new ArgumentException(SR.Format(SR.Argument_IdnBadStd3, c), nameof(c)); - } - - private string GetUnicodeInvariant(string ascii, int index, int count) - { - if (index > 0 || count < ascii.Length) - { - // We're only using part of the string - ascii = ascii.Substring(index, count); - } - // Convert Punycode to Unicode - string strUnicode = PunycodeDecode(ascii); - - // Output name MUST obey IDNA rules & round trip (casing differences are allowed) - if (!ascii.Equals(GetAscii(strUnicode), StringComparison.OrdinalIgnoreCase)) - throw new ArgumentException(SR.Argument_IdnIllegalName, nameof(ascii)); - - return strUnicode; - } - - /* PunycodeDecode() converts Punycode to Unicode. The input is */ - /* represented as an array of ASCII code points, and the output */ - /* will be represented as an array of Unicode code points. The */ - /* input_length is the number of code points in the input. The */ - /* output_length is an in/out argument: the caller passes in */ - /* the maximum number of code points that it can receive, and */ - /* on successful return it will contain the actual number of */ - /* code points output. The case_flags array needs room for at */ - /* least output_length values, or it can be a null pointer if the */ - /* case information is not needed. A nonzero flag suggests that */ - /* the corresponding Unicode character be forced to uppercase */ - /* by the caller (if possible), while zero suggests that it be */ - /* forced to lowercase (if possible). ASCII code points are */ - /* output already in the proper case, but their flags will be set */ - /* appropriately so that applying the flags would be harmless. */ - /* The return value can be any of the punycode_status values */ - /* defined above; if not punycode_success, then output_length, */ - /* output, and case_flags might contain garbage. On success, the */ - /* decoder will never need to write an output_length greater than */ - /* input_length, because of how the encoding is defined. */ - - private static string PunycodeDecode(string ascii) - { - // 0 length strings aren't allowed - if (ascii.Length == 0) - throw new ArgumentException(SR.Argument_IdnBadLabelSize, nameof(ascii)); - - // Throw if we're too long - if (ascii.Length > c_defaultNameLimit - (IsDot(ascii[^1]) ? 0 : 1)) - throw new ArgumentException(SR.Format(SR.Argument_IdnBadNameSize, - c_defaultNameLimit - (IsDot(ascii[^1]) ? 0 : 1)), nameof(ascii)); - - // output stringbuilder - StringBuilder output = new StringBuilder(ascii.Length); - - // Dot searching - int iNextDot = 0; - int iAfterLastDot = 0; - int iOutputAfterLastDot = 0; - - while (iNextDot < ascii.Length) - { - // Find end of this segment - iNextDot = ascii.IndexOf('.', iAfterLastDot); - if (iNextDot < 0 || iNextDot > ascii.Length) - iNextDot = ascii.Length; - - // Only allowed to have empty . section at end (www.microsoft.com.) - if (iNextDot == iAfterLastDot) - { - // Only allowed to have empty sections as trailing . - if (iNextDot != ascii.Length) - throw new ArgumentException(SR.Argument_IdnBadLabelSize, nameof(ascii)); - - // Last dot, stop - break; - } - - // In either case it can't be bigger than segment size - if (iNextDot - iAfterLastDot > c_labelLimit) - throw new ArgumentException(SR.Argument_IdnBadLabelSize, nameof(ascii)); - - // See if this section's ASCII or ACE - if (ascii.Length < c_strAcePrefix.Length + iAfterLastDot || - string.Compare(ascii, iAfterLastDot, c_strAcePrefix, 0, c_strAcePrefix.Length, StringComparison.OrdinalIgnoreCase) != 0) - { - // Its ASCII, copy it - output.Append(ascii, iAfterLastDot, iNextDot - iAfterLastDot); - } - else - { - // Not ASCII, bump up iAfterLastDot to be after ACE Prefix - iAfterLastDot += c_strAcePrefix.Length; - - // Get number of basic code points (where delimiter is) - // numBasicCodePoints < 0 if there're no basic code points - int iTemp = ascii.LastIndexOf(c_delimiter, iNextDot - 1); - - // Trailing - not allowed - if (iTemp == iNextDot - 1) - throw new ArgumentException(SR.Argument_IdnBadPunycode, nameof(ascii)); - - int numBasicCodePoints; - if (iTemp <= iAfterLastDot) - numBasicCodePoints = 0; - else - { - numBasicCodePoints = iTemp - iAfterLastDot; - - // Copy all the basic code points, making sure they're all in the allowed range, - // and losing the casing for all of them. - for (int copyAscii = iAfterLastDot; copyAscii < iAfterLastDot + numBasicCodePoints; copyAscii++) - { - // Make sure we don't allow unicode in the ascii part - if (ascii[copyAscii] > 0x7f) - throw new ArgumentException(SR.Argument_IdnBadPunycode, nameof(ascii)); - - // When appending make sure they get lower cased - output.Append((char)(ascii[copyAscii] >= 'A' && ascii[copyAscii] <= 'Z' ? ascii[copyAscii] - 'A' + 'a' : ascii[copyAscii])); - } - } - - // Get ready for main loop. Start at beginning if we didn't have any - // basic code points, otherwise start after the -. - // asciiIndex will be next character to read from ascii - int asciiIndex = iAfterLastDot + (numBasicCodePoints > 0 ? numBasicCodePoints + 1 : 0); - - // initialize our state - int n = c_initialN; - int bias = c_initialBias; - int i = 0; - - int w, k; - - // no Supplementary characters yet - int numSurrogatePairs = 0; - - // Main loop, read rest of ascii - while (asciiIndex < iNextDot) - { - /* Decode a generalized variable-length integer into delta, */ - /* which gets added to i. The overflow checking is easier */ - /* if we increase i as we go, then subtract off its starting */ - /* value at the end to obtain delta. */ - int oldi = i; - - for (w = 1, k = c_punycodeBase; ; k += c_punycodeBase) - { - // Check to make sure we aren't overrunning our ascii string - if (asciiIndex >= iNextDot) - throw new ArgumentException(SR.Argument_IdnBadPunycode, nameof(ascii)); - - // decode the digit from the next char - int digit = DecodeDigit(ascii[asciiIndex++]); - - Debug.Assert(w > 0, "[IdnMapping.punycode_decode]Expected w > 0"); - if (digit > (c_maxint - i) / w) - throw new ArgumentException(SR.Argument_IdnBadPunycode, nameof(ascii)); - - i += (int)(digit * w); - int t = k <= bias ? c_tmin : k >= bias + c_tmax ? c_tmax : k - bias; - if (digit < t) - break; - Debug.Assert(c_punycodeBase != t, "[IdnMapping.punycode_decode]Expected t != c_punycodeBase (36)"); - if (w > c_maxint / (c_punycodeBase - t)) - throw new ArgumentException(SR.Argument_IdnBadPunycode, nameof(ascii)); - w *= (c_punycodeBase - t); - } - - bias = Adapt(i - oldi, (output.Length - iOutputAfterLastDot - numSurrogatePairs) + 1, oldi == 0); - - /* i was supposed to wrap around from output.Length to 0, */ - /* incrementing n each time, so we'll fix that now: */ - Debug.Assert((output.Length - iOutputAfterLastDot - numSurrogatePairs) + 1 > 0, - "[IdnMapping.punycode_decode]Expected to have added > 0 characters this segment"); - if (i / ((output.Length - iOutputAfterLastDot - numSurrogatePairs) + 1) > c_maxint - n) - throw new ArgumentException(SR.Argument_IdnBadPunycode, nameof(ascii)); - n += (int)(i / (output.Length - iOutputAfterLastDot - numSurrogatePairs + 1)); - i %= (output.Length - iOutputAfterLastDot - numSurrogatePairs + 1); - - // Make sure n is legal - if (n < 0 || n > 0x10ffff || (n >= 0xD800 && n <= 0xDFFF)) - throw new ArgumentException(SR.Argument_IdnBadPunycode, nameof(ascii)); - - // insert n at position i of the output: Really tricky if we have surrogates - int iUseInsertLocation; - string strTemp = char.ConvertFromUtf32(n); - - // If we have supplimentary characters - if (numSurrogatePairs > 0) - { - // Hard way, we have supplimentary characters - int iCount; - for (iCount = i, iUseInsertLocation = iOutputAfterLastDot; iCount > 0; iCount--, iUseInsertLocation++) - { - // If its a surrogate, we have to go one more - if (iUseInsertLocation >= output.Length) - throw new ArgumentException(SR.Argument_IdnBadPunycode, nameof(ascii)); - if (char.IsSurrogate(output[iUseInsertLocation])) - iUseInsertLocation++; - } - } - else - { - // No Supplementary chars yet, just add i - iUseInsertLocation = iOutputAfterLastDot + i; - } - - // Insert it - output.Insert(iUseInsertLocation, strTemp); - - // If it was a surrogate increment our counter - if (IsSupplementary(n)) - numSurrogatePairs++; - - // Index gets updated - i++; - } - - // Do BIDI testing - bool bRightToLeft = false; - - // Check for RTL. If right-to-left, then 1st & last chars must be RTL - BidiCategory eBidi = CharUnicodeInfo.GetBidiCategory(output, iOutputAfterLastDot); - if (eBidi == BidiCategory.RightToLeft || eBidi == BidiCategory.RightToLeftArabic) - { - // It has to be right to left. - bRightToLeft = true; - } - - // Check the rest of them to make sure RTL/LTR is consistent - for (int iTest = iOutputAfterLastDot; iTest < output.Length; iTest++) - { - // This might happen if we run into a pair - if (char.IsLowSurrogate(output[iTest])) - continue; - - // Check to see if its LTR - eBidi = CharUnicodeInfo.GetBidiCategory(output, iTest); - if ((bRightToLeft && eBidi == BidiCategory.LeftToRight) || - (!bRightToLeft && (eBidi == BidiCategory.RightToLeft || eBidi == BidiCategory.RightToLeftArabic))) - throw new ArgumentException(SR.Argument_IdnBadBidi, nameof(ascii)); - } - - // Its also a requirement that the last one be RTL if 1st is RTL - if (bRightToLeft && eBidi != BidiCategory.RightToLeft && eBidi != BidiCategory.RightToLeftArabic) - { - // Oops, last wasn't RTL, last should be RTL if first is RTL - throw new ArgumentException(SR.Argument_IdnBadBidi, nameof(ascii)); - } - } - - // See if this label was too long - if (iNextDot - iAfterLastDot > c_labelLimit) - throw new ArgumentException(SR.Argument_IdnBadLabelSize, nameof(ascii)); - - // Done with this segment, add dot if necessary - if (iNextDot != ascii.Length) - output.Append('.'); - - iAfterLastDot = iNextDot + 1; - iOutputAfterLastDot = output.Length; - } - - // Throw if we're too long - if (output.Length > c_defaultNameLimit - (IsDot(output[output.Length - 1]) ? 0 : 1)) - throw new ArgumentException(SR.Format(SR.Argument_IdnBadNameSize, c_defaultNameLimit - (IsDot(output[output.Length - 1]) ? 0 : 1)), nameof(ascii)); - - // Return our output string - return output.ToString(); - } - - // DecodeDigit(cp) returns the numeric value of a basic code */ - // point (for use in representing integers) in the range 0 to */ - // c_punycodeBase-1, or <0 if cp is does not represent a value. */ - - private static int DecodeDigit(char cp) - { - if (cp >= '0' && cp <= '9') - return cp - '0' + 26; - - // Two flavors for case differences - if (cp >= 'a' && cp <= 'z') - return cp - 'a'; - - if (cp >= 'A' && cp <= 'Z') - return cp - 'A'; - - // Expected 0-9, A-Z or a-z, everything else is illegal - throw new ArgumentException(SR.Argument_IdnBadPunycode, nameof(cp)); - } - - private static int Adapt(int delta, int numpoints, bool firsttime) - { - uint k; - - delta = firsttime ? delta / c_damp : delta / 2; - Debug.Assert(numpoints != 0, "[IdnMapping.adapt]Expected non-zero numpoints."); - delta += delta / numpoints; - - for (k = 0; delta > ((c_punycodeBase - c_tmin) * c_tmax) / 2; k += c_punycodeBase) - { - delta /= c_punycodeBase - c_tmin; - } - - Debug.Assert(delta + c_skew != 0, "[IdnMapping.adapt]Expected non-zero delta+skew."); - return (int)(k + (c_punycodeBase - c_tmin + 1) * delta / (delta + c_skew)); - } - - /* EncodeBasic(bcp,flag) forces a basic code point to lowercase */ - /* if flag is false, uppercase if flag is true, and returns */ - /* the resulting code point. The code point is unchanged if it */ - /* is caseless. The behavior is undefined if bcp is not a basic */ - /* code point. */ - - private static char EncodeBasic(char bcp) - { - if (HasUpperCaseFlag(bcp)) - bcp += (char)('a' - 'A'); - - return bcp; - } - - // Return whether a punycode code point is flagged as being upper case. - private static bool HasUpperCaseFlag(char punychar) => - punychar >= 'A' && punychar <= 'Z'; - - /* EncodeDigit(d,flag) returns the basic code point whose value */ - /* (when used for representing integers) is d, which needs to be in */ - /* the range 0 to punycodeBase-1. The lowercase form is used unless flag is */ - /* true, in which case the uppercase form is used. */ - - private static char EncodeDigit(int d) - { - Debug.Assert(d >= 0 && d < c_punycodeBase, "[IdnMapping.encode_digit]Expected 0 <= d < punycodeBase"); - // 26-35 map to ASCII 0-9 - if (d > 25) return (char)(d - 26 + '0'); - - // 0-25 map to a-z or A-Z - return (char)(d + 'a'); - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/InternalGlobalizationHelper.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/InternalGlobalizationHelper.cs deleted file mode 100644 index c49b34accd7..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/InternalGlobalizationHelper.cs +++ /dev/null @@ -1,48 +0,0 @@ -// 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 -{ - internal static class InternalGlobalizationHelper - { - // Copied from the TimeSpan to be used inside the globalization code and avoid internal dependency on TimeSpan class - internal static long TimeToTicks(int hour, int minute, int second) - { - // totalSeconds is bounded by 2^31 * 2^12 + 2^31 * 2^8 + 2^31, - // which is less than 2^44, meaning we won't overflow totalSeconds. - long totalSeconds = (long)hour * 3600 + (long)minute * 60 + (long)second; - if (totalSeconds > MaxSeconds || totalSeconds < MinSeconds) - throw new ArgumentOutOfRangeException(null, SR.Overflow_TimeSpanTooLong); - return totalSeconds * TicksPerSecond; - } - - - // - // Define needed constants so globalization code can be independant from any other types - // - - internal const long TicksPerMillisecond = 10000; - internal const long TicksPerTenthSecond = TicksPerMillisecond * 100; - internal const long TicksPerSecond = TicksPerMillisecond * 1000; // 10,000,000 - internal const long MaxSeconds = long.MaxValue / TicksPerSecond; - internal const long MinSeconds = long.MinValue / TicksPerSecond; - private const int DaysPerYear = 365; - private const int DaysPer4Years = DaysPerYear * 4 + 1; // 1461 - private const int DaysPer100Years = DaysPer4Years * 25 - 1; // 36524 - private const int DaysPer400Years = DaysPer100Years * 4 + 1; // 146097 - private const int DaysTo10000 = DaysPer400Years * 25 - 366; // 3652059 - private const long TicksPerMinute = TicksPerSecond * 60; - private const long TicksPerHour = TicksPerMinute * 60; - private const long TicksPerDay = TicksPerHour * 24; - internal const long MaxTicks = DaysTo10000 * TicksPerDay - 1; - internal const long MinTicks = 0; - internal const long MaxMilliSeconds = long.MaxValue / TicksPerMillisecond; - internal const long MinMilliSeconds = long.MinValue / TicksPerMillisecond; - - internal const int StringBuilderDefaultCapacity = 16; - - internal const long MaxOffset = TimeSpan.TicksPerHour * 14; - internal const long MinOffset = -MaxOffset; - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/JapaneseCalendar.Unix.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/JapaneseCalendar.Unix.cs deleted file mode 100644 index 0bbebba7742..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/JapaneseCalendar.Unix.cs +++ /dev/null @@ -1,96 +0,0 @@ -// 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; - -namespace System.Globalization -{ - public partial class JapaneseCalendar : Calendar - { - private static EraInfo[]? GetJapaneseEras() - { - if (GlobalizationMode.Invariant) - { - return null; - } - - string[]? eraNames; - if (!CalendarData.EnumCalendarInfo("ja-JP", CalendarId.JAPAN, CalendarDataType.EraNames, out eraNames)) - { - return null; - } - - string[]? abbrevEnglishEraNames; - if (!CalendarData.EnumCalendarInfo("en", CalendarId.JAPAN, CalendarDataType.AbbrevEraNames, out abbrevEnglishEraNames)) - { - return null; - } - - List<EraInfo> eras = new List<EraInfo>(); - int lastMaxYear = GregorianCalendar.MaxYear; - - int latestEra = Interop.Globalization.GetLatestJapaneseEra(); - for (int i = latestEra; i >= 0; i--) - { - DateTime dt; - if (!GetJapaneseEraStartDate(i, out dt)) - { - return null; - } - - if (dt < s_calendarMinValue) - { - // only populate the Eras that are valid JapaneseCalendar date times - break; - } - - eras.Add(new EraInfo(i, dt.Year, dt.Month, dt.Day, dt.Year - 1, 1, lastMaxYear - dt.Year + 1, - eraNames![i], GetAbbreviatedEraName(eraNames, i), abbrevEnglishEraNames![i])); - - lastMaxYear = dt.Year; - } - - // remap the Era numbers, now that we know how many there will be - for (int i = 0; i < eras.Count; i++) - { - eras[i].era = eras.Count - i; - } - - return eras.ToArray(); - } - - // PAL Layer ends here - - private static string GetAbbreviatedEraName(string[] eraNames, int eraIndex) - { - // This matches the behavior on Win32 - only returning the first character of the era name. - // See Calendar.EraAsString(Int32) - https://msdn.microsoft.com/en-us/library/windows/apps/br206751.aspx - return eraNames[eraIndex].Substring(0, 1); - } - - private static bool GetJapaneseEraStartDate(int era, out DateTime dateTime) - { - Debug.Assert(!GlobalizationMode.Invariant); - - dateTime = default(DateTime); - - int startYear; - int startMonth; - int startDay; - bool result = Interop.Globalization.GetJapaneseEraStartDate( - era, - out startYear, - out startMonth, - out startDay); - - if (result) - { - dateTime = new DateTime(startYear, startMonth, startDay); - } - - return result; - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/JapaneseCalendar.Win32.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/JapaneseCalendar.Win32.cs deleted file mode 100644 index e70dc510804..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/JapaneseCalendar.Win32.cs +++ /dev/null @@ -1,198 +0,0 @@ -// 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.Win32; - -namespace System.Globalization -{ - public partial class JapaneseCalendar : Calendar - { - private const string JapaneseErasHive = @"System\CurrentControlSet\Control\Nls\Calendars\Japanese\Eras"; - - // We know about 5 built-in eras, however users may add additional era(s) from the - // registry, by adding values to HKLM\SYSTEM\CurrentControlSet\Control\Nls\Calendars\Japanese\Eras - // - // Registry values look like: - // yyyy.mm.dd=era_abbrev_english_englishabbrev - // - // Where yyyy.mm.dd is the registry value name, and also the date of the era start. - // yyyy, mm, and dd are the year, month & day the era begins (4, 2 & 2 digits long) - // era is the Japanese Era name - // abbrev is the Abbreviated Japanese Era Name - // english is the English name for the Era (unused) - // englishabbrev is the Abbreviated English name for the era. - // . is a delimiter, but the value of . doesn't matter. - // '_' marks the space between the japanese era name, japanese abbreviated era name - // english name, and abbreviated english names. - private static EraInfo[]? GetJapaneseEras() - { - // Look in the registry key and see if we can find any ranges - int iFoundEras = 0; - EraInfo[]? registryEraRanges = null; - - try - { - // Need to access registry - using (RegistryKey? key = Registry.LocalMachine.OpenSubKey(JapaneseErasHive)) - { - // Abort if we didn't find anything - if (key == null) return null; - - // Look up the values in our reg key - string[] valueNames = key.GetValueNames(); - if (valueNames != null && valueNames.Length > 0) - { - registryEraRanges = new EraInfo[valueNames.Length]; - - // Loop through the registry and read in all the values - for (int i = 0; i < valueNames.Length; i++) - { - // See if the era is a valid date - EraInfo? era = GetEraFromValue(valueNames[i], key.GetValue(valueNames[i])?.ToString()); - - // continue if not valid - if (era == null) continue; - - // Remember we found one. - registryEraRanges[iFoundEras] = era; - iFoundEras++; - } - } - } - } - catch (System.Security.SecurityException) - { - // If we weren't allowed to read, then just ignore the error - return null; - } - catch (System.IO.IOException) - { - // If key is being deleted just ignore the error - return null; - } - catch (System.UnauthorizedAccessException) - { - // Registry access rights permissions, just ignore the error - return null; - } - - // - // If we didn't have valid eras, then fail - // should have at least 5 eras - // - if (iFoundEras < 5) return null; - - // - // Now we have eras, clean them up. - // - // Clean up array length - Array.Resize(ref registryEraRanges, iFoundEras); - - // Sort them - Array.Sort(registryEraRanges, CompareEraRanges); - - // Clean up era information - for (int i = 0; i < registryEraRanges.Length; i++) - { - // eras count backwards from length to 1 (and are 1 based indexes into string arrays) - registryEraRanges[i].era = registryEraRanges.Length - i; - - // update max era year - if (i == 0) - { - // First range is 'til the end of the calendar - registryEraRanges[0].maxEraYear = GregorianCalendar.MaxYear - registryEraRanges[0].yearOffset; - } - else - { - // Rest are until the next era (remember most recent era is first in array) - registryEraRanges[i].maxEraYear = registryEraRanges[i - 1].yearOffset + 1 - registryEraRanges[i].yearOffset; - } - } - - // Return our ranges - return registryEraRanges; - } - - // - // Compare two era ranges, eg just the ticks - // Remember the era array is supposed to be in reverse chronological order - // - private static int CompareEraRanges(EraInfo a, EraInfo b) - { - return b.ticks.CompareTo(a.ticks); - } - - // - // GetEraFromValue - // - // Parse the registry value name/data pair into an era - // - // Registry values look like: - // yyyy.mm.dd=era_abbrev_english_englishabbrev - // - // Where yyyy.mm.dd is the registry value name, and also the date of the era start. - // yyyy, mm, and dd are the year, month & day the era begins (4, 2 & 2 digits long) - // era is the Japanese Era name - // abbrev is the Abbreviated Japanese Era Name - // english is the English name for the Era (unused) - // englishabbrev is the Abbreviated English name for the era. - // . is a delimiter, but the value of . doesn't matter. - // '_' marks the space between the japanese era name, japanese abbreviated era name - // english name, and abbreviated english names. - private static EraInfo? GetEraFromValue(string? value, string? data) - { - // Need inputs - if (value == null || data == null) return null; - - // - // Get Date - // - // Need exactly 10 characters in name for date - // yyyy.mm.dd although the . can be any character - if (value.Length != 10) return null; - - int year; - int month; - int day; - - ReadOnlySpan<char> valueSpan = value.AsSpan(); - if (!int.TryParse(valueSpan.Slice(0, 4), NumberStyles.None, NumberFormatInfo.InvariantInfo, out year) || - !int.TryParse(valueSpan.Slice(5, 2), NumberStyles.None, NumberFormatInfo.InvariantInfo, out month) || - !int.TryParse(valueSpan.Slice(8, 2), NumberStyles.None, NumberFormatInfo.InvariantInfo, out day)) - { - // Couldn't convert integer, fail - return null; - } - - // - // Get Strings - // - // Needs to be a certain length e_a_E_A at least (7 chars, exactly 4 groups) - string[] names = data.Split('_'); - - // Should have exactly 4 parts - // 0 - Era Name - // 1 - Abbreviated Era Name - // 2 - English Era Name - // 3 - Abbreviated English Era Name - if (names.Length != 4) return null; - - // Each part should have data in it - if (names[0].Length == 0 || - names[1].Length == 0 || - names[2].Length == 0 || - names[3].Length == 0) - return null; - - // - // Now we have an era we can build - // Note that the era # and max era year need cleaned up after sorting - // Don't use the full English Era Name (names[2]) - // - return new EraInfo(0, year, month, day, year - 1, 1, 0, - names[0], names[1], names[3]); - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/JapaneseCalendar.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/JapaneseCalendar.cs deleted file mode 100644 index eae8fa0bc87..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/JapaneseCalendar.cs +++ /dev/null @@ -1,294 +0,0 @@ -// 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 -{ - /// <summary> - /// JapaneseCalendar is based on Gregorian calendar. The month and day values are the same as - /// Gregorian calendar. However, the year value is an offset to the Gregorian - /// year based on the era. - /// - /// This system is adopted by Emperor Meiji in 1868. The year value is counted based on the reign of an emperor, - /// and the era begins on the day an emperor ascends the throne and continues until his death or his abdication. - /// The era changes at 12:00AM. - /// - /// For example, the current era is Reiwa. It started on 2019/5/1 A.D. Therefore, Gregorian year 2019 is also Reiwa 1st. - /// 2019/5/1 A.D. is also Reiwa 1st 5/1. - /// - /// Any date in the year during which era is changed can be reckoned in either era. For example, - /// 2019/1/1 can be 1/1 Reiwa 1st year or 1/1 Heisei 31st year. - /// - /// Note: - /// The DateTime can be represented by the JapaneseCalendar are limited to two factors: - /// 1. The min value and max value of DateTime class. - /// 2. The available era information. - /// </summary> - /// <remarks> - /// Calendar support range: - /// Calendar Minimum Maximum - /// ========== ========== ========== - /// Gregorian 1868/09/08 9999/12/31 - /// Japanese Meiji 01/01 Reiwa 7981/12/31 - /// </remarks> - public partial class JapaneseCalendar : Calendar - { - private static readonly DateTime s_calendarMinValue = new DateTime(1868, 9, 8); - - public override DateTime MinSupportedDateTime => s_calendarMinValue; - - public override DateTime MaxSupportedDateTime => DateTime.MaxValue; - - public override CalendarAlgorithmType AlgorithmType => CalendarAlgorithmType.SolarCalendar; - - // Using a field initializer rather than a static constructor so that the whole class can be lazy - // init. - private static volatile EraInfo[]? s_japaneseEraInfo; - - // m_EraInfo must be listed in reverse chronological order. The most recent era - // should be the first element. - // That is, m_EraInfo[0] contains the most recent era. - // - // We know about 4 built-in eras, however users may add additional era(s) from the - // registry, by adding values to HKLM\SYSTEM\CurrentControlSet\Control\Nls\Calendars\Japanese\Eras - // we don't read the registry and instead we call WinRT to get the needed informatio - // - // Registry values look like: - // yyyy.mm.dd=era_abbrev_english_englishabbrev - // - // Where yyyy.mm.dd is the registry value name, and also the date of the era start. - // yyyy, mm, and dd are the year, month & day the era begins (4, 2 & 2 digits long) - // era is the Japanese Era name - // abbrev is the Abbreviated Japanese Era Name - // english is the English name for the Era (unused) - // englishabbrev is the Abbreviated English name for the era. - // . is a delimiter, but the value of . doesn't matter. - // '_' marks the space between the japanese era name, japanese abbreviated era name - // english name, and abbreviated english names. - internal static EraInfo[] GetEraInfo() - { - // See if we need to build it - return s_japaneseEraInfo ?? - (s_japaneseEraInfo = GetJapaneseEras()) ?? - // See if we have to use the built-in eras - (s_japaneseEraInfo = new EraInfo[] - { - new EraInfo(5, 2019, 5, 1, 2018, 1, GregorianCalendar.MaxYear - 2018, "\x4ee4\x548c", "\x4ee4", "R"), - new EraInfo(4, 1989, 1, 8, 1988, 1, 2019 - 1988, "\x5e73\x6210", "\x5e73", "H"), - new EraInfo(3, 1926, 12, 25, 1925, 1, 1989 - 1925, "\x662d\x548c", "\x662d", "S"), - new EraInfo(2, 1912, 7, 30, 1911, 1, 1926 - 1911, "\x5927\x6b63", "\x5927", "T"), - new EraInfo(1, 1868, 1, 1, 1867, 1, 1912 - 1867, "\x660e\x6cbb", "\x660e", "M") - }); - } - - internal static volatile Calendar? s_defaultInstance; - internal GregorianCalendarHelper _helper; - - internal static Calendar GetDefaultInstance() => s_defaultInstance ??= new JapaneseCalendar(); - - public JapaneseCalendar() - { - try - { - new CultureInfo("ja-JP"); - } - catch (ArgumentException e) - { - throw new TypeInitializationException(this.GetType().ToString(), e); - } - - _helper = new GregorianCalendarHelper(this, GetEraInfo()); - } - - internal override CalendarId ID => CalendarId.JAPAN; - - public override DateTime AddMonths(DateTime time, int months) - { - return _helper.AddMonths(time, months); - } - - public override DateTime AddYears(DateTime time, int years) - { - return _helper.AddYears(time, years); - } - - public override int GetDaysInMonth(int year, int month, int era) - { - return _helper.GetDaysInMonth(year, month, era); - } - - public override int GetDaysInYear(int year, int era) - { - return _helper.GetDaysInYear(year, era); - } - - public override int GetDayOfMonth(DateTime time) - { - return _helper.GetDayOfMonth(time); - } - - public override DayOfWeek GetDayOfWeek(DateTime time) - { - return _helper.GetDayOfWeek(time); - } - - public override int GetDayOfYear(DateTime time) - { - return _helper.GetDayOfYear(time); - } - - public override int GetMonthsInYear(int year, int era) - { - return _helper.GetMonthsInYear(year, era); - } - - public override int GetWeekOfYear(DateTime time, CalendarWeekRule rule, DayOfWeek firstDayOfWeek) - { - return _helper.GetWeekOfYear(time, rule, firstDayOfWeek); - } - - public override int GetEra(DateTime time) - { - return _helper.GetEra(time); - } - - public override int GetMonth(DateTime time) - { - return _helper.GetMonth(time); - } - - public override int GetYear(DateTime time) - { - return _helper.GetYear(time); - } - - public override bool IsLeapDay(int year, int month, int day, int era) - { - return _helper.IsLeapDay(year, month, day, era); - } - - public override bool IsLeapYear(int year, int era) - { - return _helper.IsLeapYear(year, era); - } - - public override int GetLeapMonth(int year, int era) - { - return _helper.GetLeapMonth(year, era); - } - - public override bool IsLeapMonth(int year, int month, int era) - { - return _helper.IsLeapMonth(year, month, era); - } - - - public override DateTime ToDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int era) - { - return _helper.ToDateTime(year, month, day, hour, minute, second, millisecond, era); - } - - /// <summary> - /// For Japanese calendar, four digit year is not used. Few emperors will live for more than one hundred years. - /// Therefore, for any two digit number, we just return the original number. - /// </summary> - public override int ToFourDigitYear(int year) - { - if (year <= 0) - { - throw new ArgumentOutOfRangeException(nameof(year), year, SR.ArgumentOutOfRange_NeedPosNum); - } - if (year > _helper.MaxYear) - { - throw new ArgumentOutOfRangeException( - nameof(year), - year, - SR.Format(SR.ArgumentOutOfRange_Range, 1, _helper.MaxYear)); - } - - return year; - } - - - public override int[] Eras => _helper.Eras; - - /// <summary> - /// Return the various era strings - /// Note: The arrays are backwards of the eras - /// </summary> - internal static string[] EraNames() - { - EraInfo[] eras = GetEraInfo(); - string[] eraNames = new string[eras.Length]; - - for (int i = 0; i < eras.Length; i++) - { - // Strings are in chronological order, eras are backwards order. - eraNames[i] = eras[eras.Length - i - 1].eraName!; - } - - return eraNames; - } - - internal static string[] AbbrevEraNames() - { - EraInfo[] eras = GetEraInfo(); - string[] erasAbbrev = new string[eras.Length]; - - for (int i = 0; i < eras.Length; i++) - { - // Strings are in chronological order, eras are backwards order. - erasAbbrev[i] = eras[eras.Length - i - 1].abbrevEraName!; - } - - return erasAbbrev; - } - - internal static string[] EnglishEraNames() - { - EraInfo[] eras = GetEraInfo(); - string[] erasEnglish = new string[eras.Length]; - - for (int i = 0; i < eras.Length; i++) - { - // Strings are in chronological order, eras are backwards order. - erasEnglish[i] = eras[eras.Length - i - 1].englishEraName!; - } - - return erasEnglish; - } - - private const int DefaultTwoDigitYearMax = 99; - - internal override bool IsValidYear(int year, int era) - { - return _helper.IsValidYear(year, era); - } - - public override int TwoDigitYearMax - { - get - { - if (_twoDigitYearMax == -1) - { - _twoDigitYearMax = GetSystemTwoDigitYearSetting(ID, DefaultTwoDigitYearMax); - } - - return _twoDigitYearMax; - } - set - { - VerifyWritable(); - if (value < 99 || value > _helper.MaxYear) - { - throw new ArgumentOutOfRangeException( - nameof(value), - value, - SR.Format(SR.ArgumentOutOfRange_Range, 99, _helper.MaxYear)); - } - - _twoDigitYearMax = value; - } - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/JapaneseLunisolarCalendar.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/JapaneseLunisolarCalendar.cs deleted file mode 100644 index 67162a8c541..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/JapaneseLunisolarCalendar.cs +++ /dev/null @@ -1,216 +0,0 @@ -// 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 -{ - /// <remarks> - /// Calendar support range: - /// Calendar Minimum Maximum - /// ========== ========== ========== - /// Gregorian 1960/01/28 2050/01/22 - /// JapaneseLunisolar 1960/01/01 2049/12/29 - /// </remarks> - public class JapaneseLunisolarCalendar : EastAsianLunisolarCalendar - { - public const int JapaneseEra = 1; - - private readonly GregorianCalendarHelper _helper; - - private const int MinLunisolarYear = 1960; - private const int MaxLunisolarYear = 2049; - - private static readonly DateTime s_minDate = new DateTime(1960, 1, 28); - private static readonly DateTime s_maxDate = new DateTime((new DateTime(2050, 1, 22, 23, 59, 59, 999)).Ticks + 9999); - - public override DateTime MinSupportedDateTime => s_minDate; - - public override DateTime MaxSupportedDateTime => s_maxDate; - - protected override int DaysInYearBeforeMinSupportedYear => - // 1959 from ChineseLunisolarCalendar - 354; - - // Data for years 1960-2049 matches output of Calendrical Calculations [1] and published calendar tables [2]. - // [1] Reingold, Edward M, and Nachum Dershowitz. Calendrical Calculations: The Ultimate Edition. Cambridge [etc.: Cambridge University Press, 2018. Print. - // [2] Nishizawa, Yūsō. Rekijitsu Taikan: Meiji Kaireki 1873-Nen-2100-Nen Shinkyūreki, Kanshi Kyūsei Rokuyō Taishō. Tōkyō: Shin Jinbutsu Ōraisha, 1994. Print. - 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 -1960 */ { 06, 01, 28, 0b1010110101010000 }, /* 30 29 30 29 30 30 29 30 29 30 29 30 29 384 -1961 */ { 00, 02, 15, 0b1010101101010000 }, /* 30 29 30 29 30 29 30 30 29 30 29 30 355 -1962 */ { 00, 02, 05, 0b0100101101100000 }, /* 29 30 29 29 30 29 30 30 29 30 30 29 354 -1963 */ { 04, 01, 25, 0b1010010101110000 }, /* 30 29 30 29 29 30 29 30 29 30 30 30 29 384 -1964 */ { 00, 02, 13, 0b1010010101110000 }, /* 30 29 30 29 29 30 29 30 29 30 30 30 355 -1965 */ { 00, 02, 02, 0b0101001001110000 }, /* 29 30 29 30 29 29 30 29 29 30 30 30 354 -1966 */ { 03, 01, 22, 0b0110100100110000 }, /* 29 30 30 29 30 29 29 30 29 29 30 30 29 383 -1967 */ { 00, 02, 09, 0b1101100101010000 }, /* 30 30 29 30 30 29 29 30 29 30 29 30 355 -1968 */ { 07, 01, 30, 0b0110101010101000 }, /* 29 30 30 29 30 29 30 29 30 29 30 29 30 384 -1969 */ { 00, 02, 17, 0b0101011010100000 }, /* 29 30 29 30 29 30 30 29 30 29 30 29 354 -1970 */ { 00, 02, 06, 0b1001101011010000 }, /* 30 29 29 30 30 29 30 29 30 30 29 30 355 -1971 */ { 05, 01, 27, 0b0100101011101000 }, /* 29 30 29 29 30 29 30 29 30 30 30 29 30 384 -1972 */ { 00, 02, 15, 0b0100101011100000 }, /* 29 30 29 29 30 29 30 29 30 30 30 29 354 -1973 */ { 00, 02, 03, 0b1010010011100000 }, /* 30 29 30 29 29 30 29 29 30 30 30 29 354 -1974 */ { 04, 01, 23, 0b1101001001101000 }, /* 30 30 29 30 29 29 30 29 29 30 30 29 30 384 -1975 */ { 00, 02, 11, 0b1101001001010000 }, /* 30 30 29 30 29 29 30 29 29 30 29 30 354 -1976 */ { 08, 01, 31, 0b1101010101001000 }, /* 30 30 29 30 29 30 29 30 29 30 29 29 30 384 -1977 */ { 00, 02, 18, 0b1011010101000000 }, /* 30 29 30 30 29 30 29 30 29 30 29 29 354 -1978 */ { 00, 02, 07, 0b1101011010100000 }, /* 30 30 29 30 29 30 30 29 30 29 30 29 355 -1979 */ { 06, 01, 28, 0b1001011011010000 }, /* 30 29 29 30 29 30 30 29 30 30 29 30 29 384 -1980 */ { 00, 02, 16, 0b1001010110110000 }, /* 30 29 29 30 29 30 29 30 30 29 30 30 355 -1981 */ { 00, 02, 05, 0b0100100110110000 }, /* 29 30 29 29 30 29 29 30 30 29 30 30 354 -1982 */ { 04, 01, 25, 0b1010010011011000 }, /* 30 29 30 29 29 30 29 29 30 30 29 30 30 384 -1983 */ { 00, 02, 13, 0b1010010010110000 }, /* 30 29 30 29 29 30 29 29 30 29 30 30 354 -1984 */ { 10, 02, 02, 0b1011001001011000 }, /* 30 29 30 30 29 29 30 29 29 30 29 30 30 384 -1985 */ { 00, 02, 20, 0b0110101001010000 }, /* 29 30 30 29 30 29 30 29 29 30 29 30 354 -1986 */ { 00, 02, 09, 0b0110110101000000 }, /* 29 30 30 29 30 30 29 30 29 30 29 29 354 -1987 */ { 06, 01, 29, 0b1011010110101000 }, /* 30 29 30 30 29 30 29 30 30 29 30 29 30 385 -1988 */ { 00, 02, 18, 0b0010101101100000 }, /* 29 29 30 29 30 29 30 30 29 30 30 29 354 -1989 */ { 00, 02, 06, 0b1001010110110000 }, /* 30 29 29 30 29 30 29 30 30 29 30 30 355 -1990 */ { 05, 01, 27, 0b0100100110111000 }, /* 29 30 29 29 30 29 29 30 30 29 30 30 30 384 -1991 */ { 00, 02, 15, 0b0100100101110000 }, /* 29 30 29 29 30 29 29 30 29 30 30 30 354 -1992 */ { 00, 02, 04, 0b0110010010110000 }, /* 29 30 30 29 29 30 29 29 30 29 30 30 354 -1993 */ { 03, 01, 23, 0b0110101001010000 }, /* 29 30 30 29 30 29 30 29 29 30 29 30 29 383 -1994 */ { 00, 02, 10, 0b1110101001010000 }, /* 30 30 30 29 30 29 30 29 29 30 29 30 355 -1995 */ { 08, 01, 31, 0b0110110101001000 }, /* 29 30 30 29 30 30 29 30 29 30 29 29 30 384 -1996 */ { 00, 02, 19, 0b0101101011010000 }, /* 29 30 29 30 30 29 30 29 30 30 29 30 355 -1997 */ { 00, 02, 08, 0b0010101101100000 }, /* 29 29 30 29 30 29 30 30 29 30 30 29 354 -1998 */ { 05, 01, 28, 0b1001001101110000 }, /* 30 29 29 30 29 29 30 30 29 30 30 30 29 384 -1999 */ { 00, 02, 16, 0b1001001011100000 }, /* 30 29 29 30 29 29 30 29 30 30 30 29 354 -2000 */ { 00, 02, 05, 0b1100100101100000 }, /* 30 30 29 29 30 29 29 30 29 30 30 29 354 -2001 */ { 04, 01, 24, 0b1110010010101000 }, /* 30 30 30 29 29 30 29 29 30 29 30 29 30 384 -2002 */ { 00, 02, 12, 0b1101010010100000 }, /* 30 30 29 30 29 30 29 29 30 29 30 29 354 -2003 */ { 00, 02, 01, 0b1101101001010000 }, /* 30 30 29 30 30 29 30 29 29 30 29 30 355 -2004 */ { 02, 01, 22, 0b0101101010101000 }, /* 29 30 29 30 30 29 30 29 30 29 30 29 30 384 -2005 */ { 00, 02, 09, 0b0101011011000000 }, /* 29 30 29 30 29 30 30 29 30 30 29 29 354 -2006 */ { 07, 01, 29, 0b1010101011011000 }, /* 30 29 30 29 30 29 30 29 30 30 29 30 30 385 -2007 */ { 00, 02, 18, 0b0010010111010000 }, /* 29 29 30 29 29 30 29 30 30 30 29 30 354 -2008 */ { 00, 02, 07, 0b1001001011010000 }, /* 30 29 29 30 29 29 30 29 30 30 29 30 354 -2009 */ { 05, 01, 26, 0b1100100101011000 }, /* 30 30 29 29 30 29 29 30 29 30 29 30 30 384 -2010 */ { 00, 02, 14, 0b1010100101010000 }, /* 30 29 30 29 30 29 29 30 29 30 29 30 354 -2011 */ { 00, 02, 03, 0b1011010010100000 }, /* 30 29 30 30 29 30 29 29 30 29 30 29 354 -2012 */ { 03, 01, 23, 0b1011101001010000 }, /* 30 29 30 30 30 29 30 29 29 30 29 30 29 384 -2013 */ { 00, 02, 10, 0b1011010101010000 }, /* 30 29 30 30 29 30 29 30 29 30 29 30 355 -2014 */ { 09, 01, 31, 0b0101010110101000 }, /* 29 30 29 30 29 30 29 30 30 29 30 29 30 384 -2015 */ { 00, 02, 19, 0b0100101110100000 }, /* 29 30 29 29 30 29 30 30 30 29 30 29 354 -2016 */ { 00, 02, 08, 0b1010010110110000 }, /* 30 29 30 29 29 30 29 30 30 29 30 30 355 -2017 */ { 05, 01, 28, 0b0101001010111000 }, /* 29 30 29 30 29 29 30 29 30 29 30 30 30 384 -2018 */ { 00, 02, 16, 0b0101001010110000 }, /* 29 30 29 30 29 29 30 29 30 29 30 30 354 -2019 */ { 00, 02, 05, 0b1010100101010000 }, /* 30 29 30 29 30 29 29 30 29 30 29 30 354 -2020 */ { 04, 01, 25, 0b1011010010101000 }, /* 30 29 30 30 29 30 29 29 30 29 30 29 30 384 -2021 */ { 00, 02, 12, 0b0110101010100000 }, /* 29 30 30 29 30 29 30 29 30 29 30 29 354 -2022 */ { 00, 02, 01, 0b1010110101010000 }, /* 30 29 30 29 30 30 29 30 29 30 29 30 355 -2023 */ { 02, 01, 22, 0b0101010110101000 }, /* 29 30 29 30 29 30 29 30 30 29 30 29 30 384 -2024 */ { 00, 02, 10, 0b0100101101100000 }, /* 29 30 29 29 30 29 30 30 29 30 30 29 354 -2025 */ { 06, 01, 29, 0b1010010101110000 }, /* 30 29 30 29 29 30 29 30 29 30 30 30 29 384 -2026 */ { 00, 02, 17, 0b1010010101110000 }, /* 30 29 30 29 29 30 29 30 29 30 30 30 355 -2027 */ { 00, 02, 07, 0b0101001001110000 }, /* 29 30 29 30 29 29 30 29 29 30 30 30 354 -2028 */ { 05, 01, 27, 0b0110100100110000 }, /* 29 30 30 29 30 29 29 30 29 29 30 30 29 383 -2029 */ { 00, 02, 13, 0b1101100100110000 }, /* 30 30 29 30 30 29 29 30 29 29 30 30 355 -2030 */ { 00, 02, 03, 0b0101101010100000 }, /* 29 30 29 30 30 29 30 29 30 29 30 29 354 -2031 */ { 03, 01, 23, 0b1010101101010000 }, /* 30 29 30 29 30 29 30 30 29 30 29 30 29 384 -2032 */ { 00, 02, 11, 0b1001011011010000 }, /* 30 29 29 30 29 30 30 29 30 30 29 30 355 -2033 */ { 11, 01, 31, 0b0100101011101000 }, /* 29 30 29 29 30 29 30 29 30 30 30 29 30 384 -2034 */ { 00, 02, 19, 0b0100101011100000 }, /* 29 30 29 29 30 29 30 29 30 30 30 29 354 -2035 */ { 00, 02, 08, 0b1010010011010000 }, /* 30 29 30 29 29 30 29 29 30 30 29 30 354 -2036 */ { 06, 01, 28, 0b1101001001101000 }, /* 30 30 29 30 29 29 30 29 29 30 30 29 30 384 -2037 */ { 00, 02, 15, 0b1101001001010000 }, /* 30 30 29 30 29 29 30 29 29 30 29 30 354 -2038 */ { 00, 02, 04, 0b1101010100100000 }, /* 30 30 29 30 29 30 29 30 29 29 30 29 354 -2039 */ { 05, 01, 24, 0b1101101010100000 }, /* 30 30 29 30 30 29 30 29 30 29 30 29 29 384 -2040 */ { 00, 02, 12, 0b1011011010100000 }, /* 30 29 30 30 29 30 30 29 30 29 30 29 355 -2041 */ { 00, 02, 01, 0b1001011011010000 }, /* 30 29 29 30 29 30 30 29 30 30 29 30 355 -2042 */ { 02, 01, 22, 0b0100101011011000 }, /* 29 30 29 29 30 29 30 29 30 30 29 30 30 384 -2043 */ { 00, 02, 10, 0b0100100110110000 }, /* 29 30 29 29 30 29 29 30 30 29 30 30 354 -2044 */ { 07, 01, 30, 0b1010010010111000 }, /* 30 29 30 29 29 30 29 29 30 29 30 30 30 384 -2045 */ { 00, 02, 17, 0b1010010010110000 }, /* 30 29 30 29 29 30 29 29 30 29 30 30 354 -2046 */ { 00, 02, 06, 0b1011001001010000 }, /* 30 29 30 30 29 29 30 29 29 30 29 30 354 -2047 */ { 05, 01, 26, 0b1011010100101000 }, /* 30 29 30 30 29 30 29 30 29 29 30 29 30 384 -2048 */ { 00, 02, 14, 0b0110110101000000 }, /* 29 30 30 29 30 30 29 30 29 30 29 29 354 -2049 */ { 00, 02, 02, 0b1010110110100000 }, /* 30 29 30 29 30 30 29 30 30 29 30 29 355 - */ }; - - internal override int MinCalendarYear => MinLunisolarYear; - - internal override int MaxCalendarYear => MaxLunisolarYear; - - internal override DateTime MinDate => s_minDate; - - internal override DateTime MaxDate => s_maxDate; - - internal override EraInfo[]? CalEraInfo => JapaneseCalendar.GetEraInfo(); - - internal override int GetYearInfo(int lunarYear, int index) - { - if (lunarYear < MinLunisolarYear || lunarYear > MaxLunisolarYear) - { - throw new ArgumentOutOfRangeException( - "year", - lunarYear, - SR.Format(SR.ArgumentOutOfRange_Range, MinLunisolarYear, MaxLunisolarYear)); - } - - return s_yinfo[lunarYear - MinLunisolarYear, index]; - } - - internal override int GetYear(int year, DateTime time) - { - return _helper.GetYear(year, time); - } - - internal override int GetGregorianYear(int year, int era) - { - return _helper.GetGregorianYear(year, era); - } - - /// <summary> - /// Trim off the eras that are before our date range - /// </summary> - private static EraInfo[] TrimEras(EraInfo[] baseEras) - { - EraInfo[] newEras = new EraInfo[baseEras.Length]; - int newIndex = 0; - - // Eras have most recent first, so start with that - for (int i = 0; i < baseEras.Length; i++) - { - // If this one's minimum year is bigger than our maximum year - // then we can't use it. - if (baseEras[i].yearOffset + baseEras[i].minEraYear >= MaxLunisolarYear) - { - // skip this one. - continue; - } - - // If this one's maximum era is less than our minimum era - // then we've gotten too low in the era #s, so we're done - if (baseEras[i].yearOffset + baseEras[i].maxEraYear < MinLunisolarYear) - { - break; - } - - // Wasn't too large or too small, can use this one - newEras[newIndex] = baseEras[i]; - newIndex++; - } - - // If we didn't copy any then something was wrong, just return base - if (newIndex == 0) return baseEras; - - Array.Resize(ref newEras!, newIndex); - return newEras; - } - - public JapaneseLunisolarCalendar() - { - _helper = new GregorianCalendarHelper(this, TrimEras(JapaneseCalendar.GetEraInfo())); - } - - public override int GetEra(DateTime time) => _helper.GetEra(time); - - internal override CalendarId BaseCalendarID => CalendarId.JAPAN; - - internal override CalendarId ID => CalendarId.JAPANESELUNISOLAR; - - public override int[] Eras => _helper.Eras; - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/JulianCalendar.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/JulianCalendar.cs deleted file mode 100644 index fca11fe43c8..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/JulianCalendar.cs +++ /dev/null @@ -1,371 +0,0 @@ -// 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 -{ - /// <summary> - /// This class implements the Julian calendar. In 48 B.C. Julius Caesar - /// ordered a calendar reform, and this calendar is called Julian calendar. - /// It consisted of a solar year of twelve months and of 365 days with an - /// extra day every fourth year. - /// </summary> - /// <remarks> - /// Calendar support range: - /// Calendar Minimum Maximum - /// ========== ========== ========== - /// Gregorian 0001/01/01 9999/12/31 - /// Julia 0001/01/03 9999/10/19 - /// </remarks> - public class JulianCalendar : Calendar - { - public static readonly int JulianEra = 1; - - private const int DatePartYear = 0; - private const int DatePartDayOfYear = 1; - private const int DatePartMonth = 2; - private const int DatePartDay = 3; - - // Number of days in a non-leap year - private const int JulianDaysPerYear = 365; - - // Number of days in 4 years - private const int JulianDaysPer4Years = JulianDaysPerYear * 4 + 1; - - private static readonly int[] s_daysToMonth365 = - { - 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 - }; - - private static readonly int[] s_daysToMonth366 = - { - 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 - }; - - // Gregorian Calendar 9999/12/31 = Julian Calendar 9999/10/19 - // keep it as variable field for serialization compat. - internal int MaxYear = 9999; - - public override DateTime MinSupportedDateTime => DateTime.MinValue; - - public override DateTime MaxSupportedDateTime => DateTime.MaxValue; - - public override CalendarAlgorithmType AlgorithmType => CalendarAlgorithmType.SolarCalendar; - - public JulianCalendar() - { - // There is no system setting of TwoDigitYear max, so set the value here. - _twoDigitYearMax = 2029; - } - - internal override CalendarId ID => CalendarId.JULIAN; - - internal static void CheckEraRange(int era) - { - if (era != CurrentEra && era != JulianEra) - { - throw new ArgumentOutOfRangeException(nameof(era), era, SR.ArgumentOutOfRange_InvalidEraValue); - } - } - - internal void CheckYearEraRange(int year, int era) - { - CheckEraRange(era); - if (year <= 0 || year > MaxYear) - { - throw new ArgumentOutOfRangeException( - nameof(year), - year, - SR.Format(SR.ArgumentOutOfRange_Range, 1, MaxYear)); - } - } - - internal static void CheckMonthRange(int month) - { - if (month < 1 || month > 12) - { - throw new ArgumentOutOfRangeException(nameof(month), month, SR.ArgumentOutOfRange_Month); - } - } - - /// <summary> - /// Check for if the day value is valid. - /// </summary> - /// <remarks> - /// Before calling this method, call CheckYearEraRange()/CheckMonthRange() to make - /// sure year/month values are correct. - /// </remarks> - internal static void CheckDayRange(int year, int month, int day) - { - if (year == 1 && month == 1) - { - // The minimum supported Julia date is Julian 0001/01/03. - if (day < 3) - { - throw new ArgumentOutOfRangeException(null, SR.ArgumentOutOfRange_BadYearMonthDay); - } - } - - bool isLeapYear = (year % 4) == 0; - int[] days = isLeapYear ? s_daysToMonth366 : s_daysToMonth365; - int monthDays = days[month] - days[month - 1]; - if (day < 1 || day > monthDays) - { - throw new ArgumentOutOfRangeException( - nameof(day), - day, - SR.Format(SR.ArgumentOutOfRange_Range, 1, monthDays)); - } - } - - /// <summary> - /// Returns a given date part of this DateTime. This method is used - /// to compute the year, day-of-year, month, or day part. - /// </summary> - internal static int GetDatePart(long ticks, int part) - { - // Gregorian 1/1/0001 is Julian 1/3/0001. Remember DateTime(0) is refered to Gregorian 1/1/0001. - // The following line convert Gregorian ticks to Julian ticks. - long julianTicks = ticks + TicksPerDay * 2; - // n = number of days since 1/1/0001 - int n = (int)(julianTicks / TicksPerDay); - // y4 = number of whole 4-year periods within 100-year period - int y4 = n / JulianDaysPer4Years; - // n = day number within 4-year period - n -= y4 * JulianDaysPer4Years; - // y1 = number of whole years within 4-year period - int y1 = n / JulianDaysPerYear; - // Last year has an extra day, so decrement result if 4 - if (y1 == 4) y1 = 3; - // If year was requested, compute and return it - if (part == DatePartYear) - { - return y4 * 4 + y1 + 1; - } - - // n = day number within year - n -= y1 * JulianDaysPerYear; - // If day-of-year was requested, return it - if (part == DatePartDayOfYear) - { - return n + 1; - } - - // Leap year calculation looks different from IsLeapYear since y1, y4, - // and y100 are relative to year 1, not year 0 - bool leapYear = (y1 == 3); - int[] days = leapYear ? s_daysToMonth366 : s_daysToMonth365; - // All months have less than 32 days, so n >> 5 is a good conservative - // estimate for the month - int m = (n >> 5) + 1; - // m = 1-based month number - while (n >= days[m]) - { - m++; - } - - // If month was requested, return it - if (part == DatePartMonth) - { - return m; - } - - // Return 1-based day-of-month - return n - days[m - 1] + 1; - } - - /// <summary> - /// Returns the tick count corresponding to the given year, month, and day. - /// </summary> - internal static long DateToTicks(int year, int month, int day) - { - int[] days = (year % 4 == 0) ? s_daysToMonth366 : s_daysToMonth365; - int y = year - 1; - int n = y * 365 + y / 4 + days[month - 1] + day - 1; - // Gregorian 1/1/0001 is Julian 1/3/0001. n * TicksPerDay is the ticks in JulianCalendar. - // Therefore, we subtract two days in the following to convert the ticks in JulianCalendar - // to ticks in Gregorian calendar. - return (n - 2) * TicksPerDay; - } - - public override DateTime AddMonths(DateTime time, int months) - { - if (months < -120000 || months > 120000) - { - throw new ArgumentOutOfRangeException( - nameof(months), - months, - SR.Format(SR.ArgumentOutOfRange_Range, -120000, 120000)); - } - - int y = GetDatePart(time.Ticks, DatePartYear); - int m = GetDatePart(time.Ticks, DatePartMonth); - int d = GetDatePart(time.Ticks, DatePartDay); - int i = m - 1 + months; - if (i >= 0) - { - m = i % 12 + 1; - y += i / 12; - } - else - { - m = 12 + (i + 1) % 12; - y += (i - 11) / 12; - } - - int[] daysArray = (y % 4 == 0 && (y % 100 != 0 || y % 400 == 0)) ? s_daysToMonth366 : s_daysToMonth365; - int days = daysArray[m] - daysArray[m - 1]; - if (d > days) - { - d = days; - } - - long ticks = DateToTicks(y, m, d) + time.Ticks % TicksPerDay; - Calendar.CheckAddResult(ticks, MinSupportedDateTime, MaxSupportedDateTime); - return new DateTime(ticks); - } - - public override DateTime AddYears(DateTime time, int years) - { - return AddMonths(time, years * 12); - } - - public override int GetDayOfMonth(DateTime time) - { - return GetDatePart(time.Ticks, DatePartDay); - } - - public override DayOfWeek GetDayOfWeek(DateTime time) - { - return (DayOfWeek)((int)(time.Ticks / TicksPerDay + 1) % 7); - } - - public override int GetDayOfYear(DateTime time) - { - return GetDatePart(time.Ticks, DatePartDayOfYear); - } - - public override int GetDaysInMonth(int year, int month, int era) - { - CheckYearEraRange(year, era); - CheckMonthRange(month); - int[] days = (year % 4 == 0) ? s_daysToMonth366 : s_daysToMonth365; - return days[month] - days[month - 1]; - } - - public override int GetDaysInYear(int year, int era) - { - // Year/Era range is done in IsLeapYear(). - return IsLeapYear(year, era) ? 366 : 365; - } - - public override int GetEra(DateTime time) => JulianEra; - - public override int GetMonth(DateTime time) - { - return GetDatePart(time.Ticks, DatePartMonth); - } - - public override int[] Eras => new int[] { JulianEra }; - - public override int GetMonthsInYear(int year, int era) - { - CheckYearEraRange(year, era); - return 12; - } - - public override int GetYear(DateTime time) - { - return GetDatePart(time.Ticks, DatePartYear); - } - - public override bool IsLeapDay(int year, int month, int day, int era) - { - CheckMonthRange(month); - // Year/Era range check is done in IsLeapYear(). - if (IsLeapYear(year, era)) - { - CheckDayRange(year, month, day); - return month == 2 && day == 29; - } - - CheckDayRange(year, month, day); - return false; - } - - public override int GetLeapMonth(int year, int era) - { - CheckYearEraRange(year, era); - return 0; - } - - public override bool IsLeapMonth(int year, int month, int era) - { - CheckYearEraRange(year, era); - CheckMonthRange(month); - return false; - } - - public override bool IsLeapYear(int year, int era) - { - CheckYearEraRange(year, era); - return year % 4 == 0; - } - - public override DateTime ToDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int era) - { - CheckYearEraRange(year, era); - CheckMonthRange(month); - CheckDayRange(year, month, day); - if (millisecond < 0 || millisecond >= MillisPerSecond) - { - throw new ArgumentOutOfRangeException( - nameof(millisecond), - millisecond, - SR.Format(SR.ArgumentOutOfRange_Range, 0, MillisPerSecond - 1)); - } - - if (hour < 0 || hour >= 24 || minute < 0 || minute >= 60 || second < 0 || second >= 60) - { - throw new ArgumentOutOfRangeException(null, SR.ArgumentOutOfRange_BadHourMinuteSecond); - } - - return new DateTime(DateToTicks(year, month, day) + (new TimeSpan(0, hour, minute, second, millisecond)).Ticks); - } - - public override int TwoDigitYearMax - { - get => _twoDigitYearMax; - set - { - VerifyWritable(); - if (value < 99 || value > MaxYear) - { - throw new ArgumentOutOfRangeException( - nameof(value), - value, - SR.Format(SR.ArgumentOutOfRange_Range, 99, MaxYear)); - } - - _twoDigitYearMax = value; - } - } - - public override int ToFourDigitYear(int year) - { - if (year < 0) - { - throw new ArgumentOutOfRangeException(nameof(year), year, SR.ArgumentOutOfRange_NeedNonNegNum); - } - if (year > MaxYear) - { - throw new ArgumentOutOfRangeException( - nameof(year), - year, - SR.Format(SR.ArgumentOutOfRange_Bounds_Lower_Upper, 1, MaxYear)); - } - - return base.ToFourDigitYear(year); - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/KoreanCalendar.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/KoreanCalendar.cs deleted file mode 100644 index d9ded694d88..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/KoreanCalendar.cs +++ /dev/null @@ -1,187 +0,0 @@ -// 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 -{ - /// <summary> - /// Korean calendar is based on the Gregorian calendar. And the year is an offset to Gregorian calendar. - /// That is, - /// Korean year = Gregorian year + 2333. So 2000/01/01 A.D. is Korean 4333/01/01 - /// - /// 0001/1/1 A.D. is Korean year 2334. - /// </summary> - /// <remarks> - /// Calendar support range: - /// Calendar Minimum Maximum - /// ========== ========== ========== - /// Gregorian 0001/01/01 9999/12/31 - /// Korean 2334/01/01 12332/12/31 - /// </remarks> - public class KoreanCalendar : Calendar - { - public const int KoreanEra = 1; - - // Since - // Gregorian Year = Era Year + yearOffset - // Gregorian Year 1 is Korean year 2334, so that - // 1 = 2334 + yearOffset - // So yearOffset = -2333 - // Gregorian year 2001 is Korean year 4334. - private static readonly EraInfo[] s_koreanEraInfo = new EraInfo[] - { - new EraInfo(1, 1, 1, 1, -2333, 2334, GregorianCalendar.MaxYear + 2333) // era #, start year/month/day, yearOffset, minEraYear - }; - - private readonly GregorianCalendarHelper _helper; - - public override DateTime MinSupportedDateTime => DateTime.MinValue; - - public override DateTime MaxSupportedDateTime => DateTime.MaxValue; - - public override CalendarAlgorithmType AlgorithmType => CalendarAlgorithmType.SolarCalendar; - - public KoreanCalendar() - { - try - { - new CultureInfo("ko-KR"); - } - catch (ArgumentException e) - { - throw new TypeInitializationException(GetType().ToString(), e); - } - - _helper = new GregorianCalendarHelper(this, s_koreanEraInfo); - } - - internal override CalendarId ID => CalendarId.KOREA; - - - public override DateTime AddMonths(DateTime time, int months) - { - return _helper.AddMonths(time, months); - } - - public override DateTime AddYears(DateTime time, int years) - { - return _helper.AddYears(time, years); - } - - public override int GetDaysInMonth(int year, int month, int era) - { - return _helper.GetDaysInMonth(year, month, era); - } - - public override int GetDaysInYear(int year, int era) - { - return _helper.GetDaysInYear(year, era); - } - - public override int GetDayOfMonth(DateTime time) - { - return _helper.GetDayOfMonth(time); - } - - public override DayOfWeek GetDayOfWeek(DateTime time) - { - return _helper.GetDayOfWeek(time); - } - - public override int GetDayOfYear(DateTime time) - { - return _helper.GetDayOfYear(time); - } - - public override int GetMonthsInYear(int year, int era) - { - return _helper.GetMonthsInYear(year, era); - } - - public override int GetWeekOfYear(DateTime time, CalendarWeekRule rule, DayOfWeek firstDayOfWeek) - { - return _helper.GetWeekOfYear(time, rule, firstDayOfWeek); - } - - public override int GetEra(DateTime time) - { - return _helper.GetEra(time); - } - - public override int GetMonth(DateTime time) - { - return _helper.GetMonth(time); - } - - public override int GetYear(DateTime time) - { - return _helper.GetYear(time); - } - - public override bool IsLeapDay(int year, int month, int day, int era) - { - return _helper.IsLeapDay(year, month, day, era); - } - - public override bool IsLeapYear(int year, int era) - { - return _helper.IsLeapYear(year, era); - } - - public override int GetLeapMonth(int year, int era) - { - return _helper.GetLeapMonth(year, era); - } - - public override bool IsLeapMonth(int year, int month, int era) - { - return _helper.IsLeapMonth(year, month, era); - } - - public override DateTime ToDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int era) - { - return _helper.ToDateTime(year, month, day, hour, minute, second, millisecond, era); - } - - public override int[] Eras => _helper.Eras; - - private const int DefaultTwoDigitYearMax = 4362; - - - public override int TwoDigitYearMax - { - get - { - if (_twoDigitYearMax == -1) - { - _twoDigitYearMax = GetSystemTwoDigitYearSetting(ID, DefaultTwoDigitYearMax); - } - - return _twoDigitYearMax; - } - set - { - VerifyWritable(); - if (value < 99 || value > _helper.MaxYear) - { - throw new ArgumentOutOfRangeException( - nameof(value), - value, - SR.Format(SR.ArgumentOutOfRange_Range, 99, _helper.MaxYear)); - } - - _twoDigitYearMax = value; - } - } - - public override int ToFourDigitYear(int year) - { - if (year < 0) - { - throw new ArgumentOutOfRangeException(nameof(year), year, SR.ArgumentOutOfRange_NeedNonNegNum); - } - - return _helper.ToFourDigitYear(year, TwoDigitYearMax); - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/KoreanLunisolarCalendar.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/KoreanLunisolarCalendar.cs deleted file mode 100644 index 1d632cdc4fa..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/KoreanLunisolarCalendar.cs +++ /dev/null @@ -1,1235 +0,0 @@ -// 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 -{ - /// <remarks> - /// Calendar support range: - /// Calendar Minimum Maximum - /// ========== ========== ========== - /// Gregorian 918/02/19 2051/02/10 - /// KoreanLunisolar 918/01/01 2050/13/29 - /// </remarks> - public class KoreanLunisolarCalendar : EastAsianLunisolarCalendar - { - public const int GregorianEra = 1; - - private const int MinLunisolarYear = 918; - private const int MaxLunisolarYear = 2050; - - private static readonly DateTime s_minDate = new DateTime(918, 2, 19); - private static readonly DateTime s_maxDate = new DateTime((new DateTime(2051, 2, 10, 23, 59, 59, 999)).Ticks + 9999); - - public override DateTime MinSupportedDateTime => s_minDate; - - public override DateTime MaxSupportedDateTime => s_maxDate; - - protected override int DaysInYearBeforeMinSupportedYear => - // 917 -- From http://emr.cs.iit.edu/home/reingold/calendar-book/Calendrica.html - // using ChineseLunisolar - 384; - - // Data for years 1391-2050 matches that available from - // Korea Astronomy and Space Science Institute (KASI) - // https://astro.kasi.re.kr:444/life/pageView/5 - 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 -0918 */ { 00, 02, 19, 0b0101010110110000 }, /* 29 30 29 30 29 30 29 30 30 29 30 30 355 -0919 */ { 00, 02, 09, 0b0100010111010000 }, /* 29 30 29 29 29 30 29 30 30 30 29 30 354 -0920 */ { 06, 01, 29, 0b1010001011011000 }, /* 30 29 30 29 29 29 30 29 30 30 29 30 30 384 -0921 */ { 00, 02, 16, 0b1010001010110000 }, /* 30 29 30 29 29 29 30 29 30 29 30 30 354 -0922 */ { 00, 02, 05, 0b1010100101010000 }, /* 30 29 30 29 30 29 29 30 29 30 29 30 354 -0923 */ { 04, 01, 25, 0b1011010010101000 }, /* 30 29 30 30 29 30 29 29 30 29 30 29 30 384 -0924 */ { 00, 02, 13, 0b0110110100100000 }, /* 29 30 30 29 30 30 29 30 29 29 30 29 354 -0925 */ { 12, 02, 01, 0b1010110101100000 }, /* 30 29 30 29 30 30 29 30 29 30 30 29 29 384 -0926 */ { 00, 02, 20, 0b1010101101100000 }, /* 30 29 30 29 30 29 30 30 29 30 30 29 355 -0927 */ { 00, 02, 10, 0b0101010110110000 }, /* 29 30 29 30 29 30 29 30 30 29 30 30 355 -0928 */ { 08, 01, 31, 0b0100010110111000 }, /* 29 30 29 29 29 30 29 30 30 29 30 30 30 384 -0929 */ { 00, 02, 18, 0b0100010101110000 }, /* 29 30 29 29 29 30 29 30 29 30 30 30 354 -0930 */ { 00, 02, 07, 0b0101001010110000 }, /* 29 30 29 30 29 29 30 29 30 29 30 30 354 -0931 */ { 05, 01, 27, 0b0110100101010000 }, /* 29 30 30 29 30 29 29 30 29 30 29 30 29 383 -0932 */ { 00, 02, 14, 0b1110100101010000 }, /* 30 30 30 29 30 29 29 30 29 30 29 30 355 -0933 */ { 00, 02, 03, 0b0110101010100000 }, /* 29 30 30 29 30 29 30 29 30 29 30 29 354 -0934 */ { 01, 01, 23, 0b1010110101010000 }, /* 30 29 30 29 30 30 29 30 29 30 29 30 29 384 -0935 */ { 00, 02, 11, 0b1010101101010000 }, /* 30 29 30 29 30 29 30 30 29 30 29 30 355 -0936 */ { 11, 02, 01, 0b0101001101100000 }, /* 29 30 29 30 29 29 30 30 29 30 30 29 29 383 -0937 */ { 00, 02, 18, 0b1100101011000000 }, /* 30 30 29 29 30 29 30 29 30 30 29 29 354 -0938 */ { 00, 02, 07, 0b1110010101100000 }, /* 30 30 30 29 29 30 29 30 29 30 30 29 355 -0939 */ { 07, 01, 28, 0b1101001010101000 }, /* 30 30 29 30 29 29 30 29 30 29 30 29 30 384 -0940 */ { 00, 02, 16, 0b1101001010100000 }, /* 30 30 29 30 29 29 30 29 30 29 30 29 354 -0941 */ { 00, 02, 04, 0b1101100101010000 }, /* 30 30 29 30 30 29 29 30 29 30 29 30 355 -0942 */ { 03, 01, 25, 0b0101101010101000 }, /* 29 30 29 30 30 29 30 29 30 29 30 29 30 384 -0943 */ { 00, 02, 13, 0b0101011010100000 }, /* 29 30 29 30 29 30 30 29 30 29 30 29 354 -0944 */ { 12, 02, 02, 0b1010011011010000 }, /* 30 29 30 29 29 30 30 29 30 30 29 30 29 384 -0945 */ { 00, 02, 20, 0b1001010111010000 }, /* 30 29 29 30 29 30 29 30 30 30 29 30 355 -0946 */ { 00, 02, 10, 0b0100101011010000 }, /* 29 30 29 29 30 29 30 29 30 30 29 30 354 -0947 */ { 07, 01, 30, 0b1010010011011000 }, /* 30 29 30 29 29 30 29 29 30 30 29 30 30 384 -0948 */ { 00, 02, 18, 0b1010010011010000 }, /* 30 29 30 29 29 30 29 29 30 30 29 30 354 -0949 */ { 00, 02, 06, 0b1011001001100000 }, /* 30 29 30 30 29 29 30 29 29 30 30 29 354 -0950 */ { 05, 01, 26, 0b1011010101010000 }, /* 30 29 30 30 29 30 29 30 29 30 29 30 29 384 -0951 */ { 00, 02, 14, 0b1011001101110000 }, /* 30 29 30 30 29 29 30 30 29 30 30 30 356 -0953 */ { 00, 01, 05, 0b1010101011010000 }, /* 30 29 30 29 30 29 30 29 30 30 29 30 355 -0953 */ { 01, 01, 23, 0b1001010111010000 }, /* 30 29 29 30 29 30 29 30 30 30 29 30 29 384 -0954 */ { 00, 02, 11, 0b1001010110110000 }, /* 30 29 29 30 29 30 29 30 30 29 30 30 355 -0955 */ { 09, 02, 01, 0b0100101010111000 }, /* 29 30 29 29 30 29 30 29 30 29 30 30 30 384 -0956 */ { 00, 02, 20, 0b0100100110110000 }, /* 29 30 29 29 30 29 29 30 30 29 30 30 354 -0957 */ { 00, 02, 08, 0b1010010010110000 }, /* 30 29 30 29 29 30 29 29 30 29 30 30 354 -0958 */ { 07, 01, 28, 0b1010101010011000 }, /* 30 29 30 29 30 29 30 29 30 29 29 30 30 384 -0959 */ { 00, 02, 16, 0b0110101010100000 }, /* 29 30 30 29 30 29 30 29 30 29 30 29 354 -0960 */ { 00, 02, 05, 0b1010110101010000 }, /* 30 29 30 29 30 30 29 30 29 30 29 30 355 -0961 */ { 03, 01, 25, 0b0100110110101000 }, /* 29 30 29 29 30 30 29 30 30 29 30 29 30 384 -0962 */ { 00, 02, 13, 0b0010101101100000 }, /* 29 29 30 29 30 29 30 30 29 30 30 29 354 -0963 */ { 12, 02, 02, 0b1001010101110000 }, /* 30 29 29 30 29 30 29 30 29 30 30 30 29 384 -0964 */ { 00, 02, 21, 0b1010001101110000 }, /* 30 29 30 29 29 29 30 30 29 30 30 30 355 -0965 */ { 00, 02, 10, 0b0101000101110000 }, /* 29 30 29 30 29 29 29 30 29 30 30 30 354 -0966 */ { 08, 01, 30, 0b0110010010110000 }, /* 29 30 30 29 29 30 29 29 30 29 30 30 29 383 -0967 */ { 00, 02, 17, 0b1101010010110000 }, /* 30 30 29 30 29 30 29 29 30 29 30 30 355 -0968 */ { 00, 02, 07, 0b0101101010010000 }, /* 29 30 29 30 30 29 30 29 30 29 29 30 354 -0969 */ { 05, 01, 26, 0b0110101101010000 }, /* 29 30 30 29 30 29 30 30 29 30 29 30 29 384 -0970 */ { 00, 02, 14, 0b0101011011010000 }, /* 29 30 29 30 29 30 30 29 30 30 29 30 355 -0971 */ { 00, 02, 04, 0b0010101011100000 }, /* 29 29 30 29 30 29 30 29 30 30 30 29 354 -0972 */ { 02, 01, 24, 0b1001001101110000 }, /* 30 29 29 30 29 29 30 30 29 30 30 30 29 384 -0973 */ { 00, 02, 11, 0b1010001011100000 }, /* 30 29 30 29 29 29 30 29 30 30 30 29 354 -0974 */ { 10, 01, 31, 0b1100100101101000 }, /* 30 30 29 29 30 29 29 30 29 30 30 29 30 384 -0975 */ { 00, 02, 19, 0b1010100101010000 }, /* 30 29 30 29 30 29 29 30 29 30 29 30 354 -0976 */ { 00, 02, 08, 0b1101010010100000 }, /* 30 30 29 30 29 30 29 29 30 29 30 29 354 -0977 */ { 07, 01, 27, 0b1101101010010000 }, /* 30 30 29 30 30 29 30 29 30 29 29 30 29 384 -0978 */ { 00, 02, 15, 0b1011010110100000 }, /* 30 29 30 30 29 30 29 30 30 29 30 29 355 -0979 */ { 00, 02, 05, 0b0101011011010000 }, /* 29 30 29 30 29 30 30 29 30 30 29 30 355 -0980 */ { 03, 01, 26, 0b0010101011011000 }, /* 29 29 30 29 30 29 30 29 30 30 29 30 30 384 -0981 */ { 00, 02, 13, 0b0010010111010000 }, /* 29 29 30 29 29 30 29 30 30 30 29 30 354 -0982 */ { 12, 02, 02, 0b1001001011011000 }, /* 30 29 29 30 29 29 30 29 30 30 29 30 30 384 -0983 */ { 00, 02, 21, 0b1001001010110000 }, /* 30 29 29 30 29 29 30 29 30 29 30 30 354 -0984 */ { 00, 02, 10, 0b1010100101010000 }, /* 30 29 30 29 30 29 29 30 29 30 29 30 354 -0985 */ { 09, 01, 29, 0b1011010010101000 }, /* 30 29 30 30 29 30 29 29 30 29 30 29 30 384 -0986 */ { 00, 02, 17, 0b1010110010100000 }, /* 30 29 30 29 30 30 29 29 30 29 30 29 354 -0987 */ { 00, 02, 06, 0b1010110101010000 }, /* 30 29 30 29 30 30 29 30 29 30 29 30 355 -0988 */ { 05, 01, 27, 0b0101010110110000 }, /* 29 30 29 30 29 30 29 30 30 29 30 30 29 384 -0989 */ { 00, 02, 14, 0b0100101110110000 }, /* 29 30 29 29 30 29 30 30 30 29 30 30 355 -0990 */ { 00, 02, 04, 0b0010010110110000 }, /* 29 29 30 29 29 30 29 30 30 29 30 30 354 -0991 */ { 02, 01, 24, 0b1001001010111000 }, /* 30 29 29 30 29 29 30 29 30 29 30 30 30 384 -0992 */ { 00, 02, 12, 0b0101001010110000 }, /* 29 30 29 30 29 29 30 29 30 29 30 30 354 -0993 */ { 10, 01, 31, 0b0110100101011000 }, /* 29 30 30 29 30 29 29 30 29 30 29 30 30 384 -0994 */ { 00, 02, 19, 0b0101100101010000 }, /* 29 30 29 30 30 29 29 30 29 30 29 30 354 -0995 */ { 00, 02, 08, 0b0110101010100000 }, /* 29 30 30 29 30 29 30 29 30 29 30 29 354 -0996 */ { 07, 01, 28, 0b1010101101010000 }, /* 30 29 30 29 30 29 30 30 29 30 29 30 29 384 -0997 */ { 00, 02, 15, 0b1010101101100000 }, /* 30 29 30 29 30 29 30 30 29 30 30 29 355 -0998 */ { 00, 02, 05, 0b0100101101100000 }, /* 29 30 29 29 30 29 30 30 29 30 30 29 354 -0999 */ { 03, 01, 25, 0b1010010101110000 }, /* 30 29 30 29 29 30 29 30 29 30 30 30 29 384 -1000 */ { 00, 02, 13, 0b0010010101110000 }, /* 29 29 30 29 29 30 29 30 29 30 30 30 354 -1001 */ { 12, 02, 03, 0b0101001010110000 }, /* 29 30 29 30 29 29 30 29 30 29 30 30 29 383 -1002 */ { 00, 02, 21, 0b1101001010100000 }, /* 30 30 29 30 29 29 30 29 30 29 30 29 354 -1003 */ { 00, 02, 10, 0b1101010101010000 }, /* 30 30 29 30 29 30 29 30 29 30 29 30 355 -1004 */ { 09, 01, 31, 0b0101101010101000 }, /* 29 30 29 30 30 29 30 29 30 29 30 29 30 384 -1005 */ { 00, 02, 18, 0b0101011010100000 }, /* 29 30 29 30 29 30 30 29 30 29 30 29 354 -1006 */ { 00, 02, 07, 0b1001011011010000 }, /* 30 29 29 30 29 30 30 29 30 30 29 30 355 -1007 */ { 05, 01, 28, 0b0100101011101000 }, /* 29 30 29 29 30 29 30 29 30 30 30 29 30 384 -1008 */ { 00, 02, 16, 0b0100101011010000 }, /* 29 30 29 29 30 29 30 29 30 30 29 30 354 -1009 */ { 00, 02, 04, 0b1010010011010000 }, /* 30 29 30 29 29 30 29 29 30 30 29 30 354 -1010 */ { 02, 01, 24, 0b1101001001101000 }, /* 30 30 29 30 29 29 30 29 29 30 30 29 30 384 -1011 */ { 00, 02, 12, 0b1011001001100000 }, /* 30 29 30 30 29 29 30 29 29 30 30 29 354 -1012 */ { 10, 02, 01, 0b1011010101010000 }, /* 30 29 30 30 29 30 29 30 29 30 29 30 29 384 -1013 */ { 00, 02, 19, 0b1010110101010000 }, /* 30 29 30 29 30 30 29 30 29 30 29 30 355 -1014 */ { 00, 02, 09, 0b0011010110100000 }, /* 29 29 30 30 29 30 29 30 30 29 30 29 354 -1015 */ { 06, 01, 29, 0b1001010111010000 }, /* 30 29 29 30 29 30 29 30 30 30 29 30 29 384 -1016 */ { 00, 02, 17, 0b1001010110110000 }, /* 30 29 29 30 29 30 29 30 30 29 30 30 355 -1017 */ { 00, 02, 06, 0b0100100110110000 }, /* 29 30 29 29 30 29 29 30 30 29 30 30 354 -1018 */ { 04, 01, 26, 0b1010010011011000 }, /* 30 29 30 29 29 30 29 29 30 30 29 30 30 384 -1019 */ { 00, 02, 14, 0b1010010010110000 }, /* 30 29 30 29 29 30 29 29 30 29 30 30 354 -1020 */ { 12, 02, 03, 0b1010101001011000 }, /* 30 29 30 29 30 29 30 29 29 30 29 30 30 384 -1021 */ { 00, 02, 21, 0b0110101010100000 }, /* 29 30 30 29 30 29 30 29 30 29 30 29 354 -1022 */ { 00, 02, 10, 0b1010110101010000 }, /* 30 29 30 29 30 30 29 30 29 30 29 30 355 -1023 */ { 09, 01, 31, 0b0010110110101000 }, /* 29 29 30 29 30 30 29 30 30 29 30 29 30 384 -1024 */ { 00, 02, 19, 0b0010101101010000 }, /* 29 29 30 29 30 29 30 30 29 30 29 30 354 -1025 */ { 00, 02, 07, 0b1001010101110000 }, /* 30 29 29 30 29 30 29 30 29 30 30 30 355 -1026 */ { 05, 01, 28, 0b0100100101110000 }, /* 29 30 29 29 30 29 29 30 29 30 30 30 29 383 -1027 */ { 00, 02, 15, 0b1100100101110000 }, /* 30 30 29 29 30 29 29 30 29 30 30 30 355 -1028 */ { 00, 02, 05, 0b0110010010110000 }, /* 29 30 30 29 29 30 29 29 30 29 30 30 354 -1029 */ { 02, 01, 24, 0b0110101001010000 }, /* 29 30 30 29 30 29 30 29 29 30 29 30 29 383 -1030 */ { 00, 02, 11, 0b1101101010010000 }, /* 30 30 29 30 30 29 30 29 30 29 29 30 355 -1031 */ { 10, 02, 01, 0b0110101101010000 }, /* 29 30 30 29 30 29 30 30 29 30 29 30 29 384 -1032 */ { 00, 02, 20, 0b0110011011010000 }, /* 29 30 30 29 29 30 30 29 30 30 29 30 355 -1033 */ { 00, 02, 09, 0b0010011011100000 }, /* 29 29 30 29 29 30 30 29 30 30 30 29 354 -1034 */ { 06, 01, 29, 0b1001001101110000 }, /* 30 29 29 30 29 29 30 30 29 30 30 30 29 384 -1035 */ { 00, 02, 17, 0b1001001011100000 }, /* 30 29 29 30 29 29 30 29 30 30 30 29 354 -1036 */ { 00, 02, 06, 0b1100100101100000 }, /* 30 30 29 29 30 29 29 30 29 30 30 29 354 -1037 */ { 04, 01, 25, 0b1101010010101000 }, /* 30 30 29 30 29 30 29 29 30 29 30 29 30 384 -1038 */ { 00, 02, 13, 0b1101010010100000 }, /* 30 30 29 30 29 30 29 29 30 29 30 29 354 -1039 */ { 12, 02, 02, 0b1101011010010000 }, /* 30 30 29 30 29 30 30 29 30 29 29 30 29 384 -1040 */ { 00, 02, 21, 0b1011010110000000 }, /* 30 29 30 30 29 30 29 30 30 29 29 29 354 -1041 */ { 00, 02, 09, 0b1101011010110000 }, /* 30 30 29 30 29 30 30 29 30 29 30 30 356 -1042 */ { 09, 01, 31, 0b0010011011011000 }, /* 29 29 30 29 29 30 30 29 30 30 29 30 30 384 -1043 */ { 00, 02, 19, 0b0010010111010000 }, /* 29 29 30 29 29 30 29 30 30 30 29 30 354 -1044 */ { 00, 02, 08, 0b1001001010110000 }, /* 30 29 29 30 29 29 30 29 30 29 30 30 354 -1045 */ { 05, 01, 27, 0b1010100101011000 }, /* 30 29 30 29 30 29 29 30 29 30 29 30 30 384 -1046 */ { 00, 02, 15, 0b1010100101010000 }, /* 30 29 30 29 30 29 29 30 29 30 29 30 354 -1047 */ { 00, 02, 04, 0b1011010010100000 }, /* 30 29 30 30 29 30 29 29 30 29 30 29 354 -1048 */ { 01, 01, 24, 0b1011010101011000 }, /* 30 29 30 30 29 30 29 30 29 30 29 30 30 385 -1049 */ { 00, 02, 12, 0b0010110101010000 }, /* 29 29 30 29 30 30 29 30 29 30 29 30 354 -1050 */ { 11, 02, 01, 0b0101010110110000 }, /* 29 30 29 30 29 30 29 30 30 29 30 30 29 384 -1051 */ { 00, 02, 20, 0b0100101110110000 }, /* 29 30 29 29 30 29 30 30 30 29 30 30 355 -1052 */ { 00, 02, 10, 0b0010010110110000 }, /* 29 29 30 29 29 30 29 30 30 29 30 30 354 -1053 */ { 07, 01, 29, 0b0101001010111000 }, /* 29 30 29 30 29 29 30 29 30 29 30 30 30 384 -1054 */ { 00, 02, 17, 0b0101001010110000 }, /* 29 30 29 30 29 29 30 29 30 29 30 30 354 -1055 */ { 00, 02, 06, 0b0110100101010000 }, /* 29 30 30 29 30 29 29 30 29 30 29 30 354 -1056 */ { 03, 01, 26, 0b0110101010101000 }, /* 29 30 30 29 30 29 30 29 30 29 30 29 30 384 -1057 */ { 00, 02, 13, 0b0110101010100000 }, /* 29 30 30 29 30 29 30 29 30 29 30 29 354 -1058 */ { 12, 02, 02, 0b1010101101011000 }, /* 30 29 30 29 30 29 30 30 29 30 29 30 30 385 -1059 */ { 00, 02, 22, 0b0010011101010000 }, /* 29 29 30 29 29 30 30 30 29 30 29 30 354 -1060 */ { 00, 02, 11, 0b0100101101100000 }, /* 29 30 29 29 30 29 30 30 29 30 30 29 354 -1061 */ { 08, 01, 30, 0b1010010101110000 }, /* 30 29 30 29 29 30 29 30 29 30 30 30 29 384 -1062 */ { 00, 02, 18, 0b1010010101100000 }, /* 30 29 30 29 29 30 29 30 29 30 30 29 354 -1063 */ { 00, 02, 07, 0b1101001001100000 }, /* 30 30 29 30 29 29 30 29 29 30 30 29 354 -1064 */ { 05, 01, 27, 0b1110100100110000 }, /* 30 30 30 29 30 29 29 30 29 29 30 30 29 384 -1065 */ { 00, 02, 14, 0b1101010101010000 }, /* 30 30 29 30 29 30 29 30 29 30 29 30 355 -1066 */ { 00, 02, 04, 0b0101101010100000 }, /* 29 30 29 30 30 29 30 29 30 29 30 29 354 -1067 */ { 01, 01, 24, 0b1010101101010000 }, /* 30 29 30 29 30 29 30 30 29 30 29 30 29 384 -1068 */ { 00, 02, 12, 0b1001011011010000 }, /* 30 29 29 30 29 30 30 29 30 30 29 30 355 -1069 */ { 11, 02, 01, 0b0100101011101000 }, /* 29 30 29 29 30 29 30 29 30 30 30 29 30 384 -1070 */ { 00, 02, 20, 0b0100100111010000 }, /* 29 30 29 29 30 29 29 30 30 30 29 30 354 -1071 */ { 00, 02, 09, 0b1010010011010000 }, /* 30 29 30 29 29 30 29 29 30 30 29 30 354 -1072 */ { 07, 01, 29, 0b1101001001101000 }, /* 30 30 29 30 29 29 30 29 29 30 30 29 30 384 -1073 */ { 00, 02, 16, 0b1010101001100000 }, /* 30 29 30 29 30 29 30 29 29 30 30 29 354 -1074 */ { 00, 02, 05, 0b1011010101010000 }, /* 30 29 30 30 29 30 29 30 29 30 29 30 355 -1075 */ { 04, 01, 26, 0b0101011010101000 }, /* 29 30 29 30 29 30 30 29 30 29 30 29 30 384 -1076 */ { 00, 02, 14, 0b0011010110100000 }, /* 29 29 30 30 29 30 29 30 30 29 30 29 354 -1077 */ { 00, 02, 02, 0b1001010111010000 }, /* 30 29 29 30 29 30 29 30 30 30 29 30 355 -1078 */ { 01, 01, 23, 0b0100101110011000 }, /* 29 30 29 29 30 29 30 30 30 29 29 30 30 384 -1079 */ { 00, 02, 11, 0b0100010110110000 }, /* 29 30 29 29 29 30 29 30 30 29 30 30 354 -1080 */ { 09, 01, 31, 0b1010010010111000 }, /* 30 29 30 29 29 30 29 29 30 29 30 30 30 384 -1081 */ { 00, 02, 18, 0b0110010010110000 }, /* 29 30 30 29 29 30 29 29 30 29 30 30 354 -1082 */ { 00, 02, 07, 0b1010101001010000 }, /* 30 29 30 29 30 29 30 29 29 30 29 30 354 -1083 */ { 06, 01, 27, 0b1011010101001000 }, /* 30 29 30 30 29 30 29 30 29 30 29 29 30 384 -1084 */ { 00, 02, 15, 0b0110101101010000 }, /* 29 30 30 29 30 29 30 30 29 30 29 30 355 -1085 */ { 00, 02, 04, 0b0010110110100000 }, /* 29 29 30 29 30 30 29 30 30 29 30 29 354 -1086 */ { 02, 01, 24, 0b1001010110110000 }, /* 30 29 29 30 29 30 29 30 30 29 30 30 29 384 -1087 */ { 00, 02, 12, 0b1001001101110000 }, /* 30 29 29 30 29 29 30 30 29 30 30 30 355 -1088 */ { 12, 02, 02, 0b0100100101110000 }, /* 29 30 29 29 30 29 29 30 29 30 30 30 29 383 -1089 */ { 00, 02, 19, 0b1100100101110000 }, /* 30 30 29 29 30 29 29 30 29 30 30 30 355 -1090 */ { 00, 02, 09, 0b0110010010110000 }, /* 29 30 30 29 29 30 29 29 30 29 30 30 354 -1091 */ { 08, 01, 29, 0b0110101001010000 }, /* 29 30 30 29 30 29 30 29 29 30 29 30 29 383 -1092 */ { 00, 02, 16, 0b1101101001010000 }, /* 30 30 29 30 30 29 30 29 29 30 29 30 355 -1093 */ { 00, 02, 05, 0b0101101101000000 }, /* 29 30 29 30 30 29 30 30 29 30 29 29 354 -1094 */ { 04, 01, 25, 0b1010101101101000 }, /* 30 29 30 29 30 29 30 30 29 30 30 29 30 385 -1095 */ { 00, 02, 14, 0b0010101011100000 }, /* 29 29 30 29 30 29 30 29 30 30 30 29 354 -1096 */ { 00, 02, 03, 0b1110011000010000 }, /* 30 30 30 29 29 30 30 29 29 29 29 30 354 -1097 */ { 02, 01, 22, 0b1100100101110000 }, /* 30 30 29 29 30 29 29 30 29 30 30 30 29 384 -1098 */ { 00, 02, 10, 0b1100100101100000 }, /* 30 30 29 29 30 29 29 30 29 30 30 29 354 -1099 */ { 09, 01, 30, 0b1101010010101000 }, /* 30 30 29 30 29 30 29 29 30 29 30 29 30 384 -1100 */ { 00, 02, 18, 0b0101010010100000 }, /* 29 30 29 30 29 30 29 29 30 29 30 29 353 -1101 */ { 00, 02, 07, 0b1101011001010000 }, /* 30 30 29 30 29 30 30 29 29 30 29 30 355 -1102 */ { 06, 01, 28, 0b0101101010101000 }, /* 29 30 29 30 30 29 30 29 30 29 30 29 30 384 -1103 */ { 00, 02, 16, 0b0101010111010000 }, /* 29 30 29 30 29 30 29 30 30 30 29 30 355 -1104 */ { 00, 02, 06, 0b0010011011010000 }, /* 29 29 30 29 29 30 30 29 30 30 29 30 354 -1105 */ { 02, 01, 25, 0b1001001011101000 }, /* 30 29 29 30 29 29 30 29 30 30 30 29 30 384 -1106 */ { 00, 02, 13, 0b1001001010110000 }, /* 30 29 29 30 29 29 30 29 30 29 30 30 354 -1107 */ { 10, 02, 02, 0b1010100101011000 }, /* 30 29 30 29 30 29 29 30 29 30 29 30 30 384 -1108 */ { 00, 02, 21, 0b1010100101010000 }, /* 30 29 30 29 30 29 29 30 29 30 29 30 354 -1109 */ { 00, 02, 09, 0b1011010010100000 }, /* 30 29 30 30 29 30 29 29 30 29 30 29 354 -1110 */ { 08, 01, 29, 0b1011010101010000 }, /* 30 29 30 30 29 30 29 30 29 30 29 30 29 384 -1111 */ { 00, 02, 17, 0b1010110101010000 }, /* 30 29 30 29 30 30 29 30 29 30 29 30 355 -1112 */ { 00, 02, 07, 0b0101010110110000 }, /* 29 30 29 30 29 30 29 30 30 29 30 30 355 -1113 */ { 04, 01, 27, 0b0010010110111000 }, /* 29 29 30 29 29 30 29 30 30 29 30 30 30 384 -1114 */ { 00, 02, 15, 0b0100010101110000 }, /* 29 30 29 29 29 30 29 30 29 30 30 30 354 -1115 */ { 00, 02, 04, 0b0101001010110000 }, /* 29 30 29 30 29 29 30 29 30 29 30 30 354 -1116 */ { 01, 01, 24, 0b1010100101011000 }, /* 30 29 30 29 30 29 29 30 29 30 29 30 30 384 -1117 */ { 00, 02, 11, 0b0110100101010000 }, /* 29 30 30 29 30 29 29 30 29 30 29 30 354 -1118 */ { 09, 01, 31, 0b0111001010101000 }, /* 29 30 30 30 29 29 30 29 30 29 30 29 30 384 -1119 */ { 00, 02, 19, 0b0101101010100000 }, /* 29 30 29 30 30 29 30 29 30 29 30 29 354 -1120 */ { 00, 02, 08, 0b1010101101010000 }, /* 30 29 30 29 30 29 30 30 29 30 29 30 355 -1121 */ { 05, 01, 28, 0b0100101101101000 }, /* 29 30 29 29 30 29 30 30 29 30 30 29 30 384 -1122 */ { 00, 02, 16, 0b0100101101100000 }, /* 29 30 29 29 30 29 30 30 29 30 30 29 354 -1123 */ { 00, 02, 05, 0b1010010101110000 }, /* 30 29 30 29 29 30 29 30 29 30 30 30 355 -1124 */ { 03, 01, 26, 0b0101001001110000 }, /* 29 30 29 30 29 29 30 29 29 30 30 30 29 383 -1125 */ { 00, 02, 12, 0b1101001001100000 }, /* 30 30 29 30 29 29 30 29 29 30 30 29 354 -1126 */ { 11, 02, 01, 0b1110100100110000 }, /* 30 30 30 29 30 29 29 30 29 29 30 30 29 384 -1127 */ { 00, 02, 20, 0b1101010101010000 }, /* 30 30 29 30 29 30 29 30 29 30 29 30 355 -1128 */ { 00, 02, 10, 0b0101101010100000 }, /* 29 30 29 30 30 29 30 29 30 29 30 29 354 -1129 */ { 08, 01, 29, 0b1001101110010000 }, /* 30 29 29 30 30 29 30 30 30 29 29 30 29 384 -1130 */ { 00, 02, 17, 0b1001011011010000 }, /* 30 29 29 30 29 30 30 29 30 30 29 30 355 -1131 */ { 00, 02, 07, 0b0100101011100000 }, /* 29 30 29 29 30 29 30 29 30 30 30 29 354 -1132 */ { 04, 01, 27, 0b1010010011101000 }, /* 30 29 30 29 29 30 29 29 30 30 30 29 30 384 -1133 */ { 00, 02, 14, 0b1010010011010000 }, /* 30 29 30 29 29 30 29 29 30 30 29 30 354 -1134 */ { 00, 02, 03, 0b1101001001010000 }, /* 30 30 29 30 29 29 30 29 29 30 29 30 354 -1135 */ { 02, 01, 23, 0b1101100100101000 }, /* 30 30 29 30 30 29 29 30 29 29 30 29 30 384 -1136 */ { 00, 02, 11, 0b1011010101000000 }, /* 30 29 30 30 29 30 29 30 29 30 29 29 354 -1137 */ { 10, 01, 30, 0b1101011010101000 }, /* 30 30 29 30 29 30 30 29 30 29 30 29 30 385 -1138 */ { 00, 02, 19, 0b0010110110100000 }, /* 29 29 30 29 30 30 29 30 30 29 30 29 354 -1139 */ { 00, 02, 08, 0b1001010111010000 }, /* 30 29 29 30 29 30 29 30 30 30 29 30 355 -1140 */ { 06, 01, 29, 0b0100101011011000 }, /* 29 30 29 29 30 29 30 29 30 30 29 30 30 384 -1141 */ { 00, 02, 16, 0b0100100110110000 }, /* 29 30 29 29 30 29 29 30 30 29 30 30 354 -1142 */ { 00, 02, 05, 0b1010010010110000 }, /* 30 29 30 29 29 30 29 29 30 29 30 30 354 -1143 */ { 04, 01, 25, 0b1011001001011000 }, /* 30 29 30 30 29 29 30 29 29 30 29 30 30 384 -1144 */ { 00, 02, 13, 0b0110101001010000 }, /* 29 30 30 29 30 29 30 29 29 30 29 30 354 -1145 */ { 11, 02, 01, 0b1011010100101000 }, /* 30 29 30 30 29 30 29 30 29 29 30 29 30 384 -1146 */ { 00, 02, 20, 0b0110101101000000 }, /* 29 30 30 29 30 29 30 30 29 30 29 29 354 -1147 */ { 00, 02, 09, 0b1010101101100000 }, /* 30 29 30 29 30 29 30 30 29 30 30 29 355 -1148 */ { 08, 01, 30, 0b1001010110110000 }, /* 30 29 29 30 29 30 29 30 30 29 30 30 29 384 -1149 */ { 00, 02, 17, 0b1001100101110000 }, /* 30 29 29 30 30 29 29 30 29 30 30 30 355 -1150 */ { 00, 02, 07, 0b0100100101110000 }, /* 29 30 29 29 30 29 29 30 29 30 30 30 354 -1151 */ { 04, 01, 27, 0b0110010010111000 }, /* 29 30 30 29 29 30 29 29 30 29 30 30 30 384 -1152 */ { 00, 02, 15, 0b0101010010110000 }, /* 29 30 29 30 29 30 29 29 30 29 30 30 354 -1153 */ { 12, 02, 03, 0b0110101001010000 }, /* 29 30 30 29 30 29 30 29 29 30 29 30 29 383 -1154 */ { 00, 02, 21, 0b1101101001010000 }, /* 30 30 29 30 30 29 30 29 29 30 29 30 355 -1155 */ { 00, 02, 11, 0b0101101011000000 }, /* 29 30 29 30 30 29 30 29 30 30 29 29 354 -1156 */ { 10, 01, 31, 0b1010101101101000 }, /* 30 29 30 29 30 29 30 30 29 30 30 29 30 385 -1157 */ { 00, 02, 19, 0b0010011011100000 }, /* 29 29 30 29 29 30 30 29 30 30 30 29 354 -1158 */ { 00, 02, 08, 0b1001001011100000 }, /* 30 29 29 30 29 29 30 29 30 30 30 29 354 -1159 */ { 06, 01, 28, 0b1100100101110000 }, /* 30 30 29 29 30 29 29 30 29 30 30 30 29 384 -1160 */ { 00, 02, 16, 0b1100100101100000 }, /* 30 30 29 29 30 29 29 30 29 30 30 29 354 -1161 */ { 00, 02, 04, 0b1101010010100000 }, /* 30 30 29 30 29 30 29 29 30 29 30 29 354 -1162 */ { 02, 01, 24, 0b1101101001010000 }, /* 30 30 29 30 30 29 30 29 29 30 29 30 29 384 -1163 */ { 00, 02, 12, 0b1101010101010000 }, /* 30 30 29 30 29 30 29 30 29 30 29 30 355 -1164 */ { 11, 02, 02, 0b0101011010101000 }, /* 29 30 29 30 29 30 30 29 30 29 30 29 30 384 -1165 */ { 00, 02, 20, 0b0101010110110000 }, /* 29 30 29 30 29 30 29 30 30 29 30 30 355 -1166 */ { 00, 02, 10, 0b0010010111010000 }, /* 29 29 30 29 29 30 29 30 30 30 29 30 354 -1167 */ { 07, 01, 30, 0b1001001011101000 }, /* 30 29 29 30 29 29 30 29 30 30 30 29 30 384 -1168 */ { 00, 02, 18, 0b1001001001110000 }, /* 30 29 29 30 29 29 30 29 29 30 30 30 354 -1169 */ { 00, 02, 06, 0b1010100101010000 }, /* 30 29 30 29 30 29 29 30 29 30 29 30 354 -1170 */ { 05, 01, 26, 0b1101010010101000 }, /* 30 30 29 30 29 30 29 29 30 29 30 29 30 384 -1171 */ { 00, 02, 14, 0b1011010010100000 }, /* 30 29 30 30 29 30 29 29 30 29 30 29 354 -1172 */ { 00, 02, 03, 0b1011010101010000 }, /* 30 29 30 30 29 30 29 30 29 30 29 30 355 -1173 */ { 01, 01, 23, 0b0101011010101000 }, /* 29 30 29 30 29 30 30 29 30 29 30 29 30 384 -1174 */ { 00, 02, 11, 0b0100110110110000 }, /* 29 30 29 29 30 30 29 30 30 29 30 30 355 -1175 */ { 09, 02, 01, 0b0010010110110000 }, /* 29 29 30 29 29 30 29 30 30 29 30 30 29 383 -1176 */ { 00, 02, 19, 0b1010010101110000 }, /* 30 29 30 29 29 30 29 30 29 30 30 30 355 -1177 */ { 00, 02, 08, 0b0101001010110000 }, /* 29 30 29 30 29 29 30 29 30 29 30 30 354 -1178 */ { 06, 01, 28, 0b1010100101011000 }, /* 30 29 30 29 30 29 29 30 29 30 29 30 30 384 -1179 */ { 00, 02, 16, 0b0110100101010000 }, /* 29 30 30 29 30 29 29 30 29 30 29 30 354 -1180 */ { 00, 02, 05, 0b0110101010100000 }, /* 29 30 30 29 30 29 30 29 30 29 30 29 354 -1181 */ { 03, 01, 24, 0b1010110101010000 }, /* 30 29 30 29 30 30 29 30 29 30 29 30 29 384 -1182 */ { 00, 02, 12, 0b1010101101010000 }, /* 30 29 30 29 30 29 30 30 29 30 29 30 355 -1183 */ { 11, 02, 02, 0b0100101101101000 }, /* 29 30 29 29 30 29 30 30 29 30 30 29 30 384 -1184 */ { 00, 02, 21, 0b0100101011100000 }, /* 29 30 29 29 30 29 30 29 30 30 30 29 354 -1185 */ { 00, 02, 09, 0b1010010101110000 }, /* 30 29 30 29 29 30 29 30 29 30 30 30 355 -1186 */ { 07, 01, 30, 0b0101001001110000 }, /* 29 30 29 30 29 29 30 29 29 30 30 30 29 383 -1187 */ { 00, 02, 17, 0b1101000010010000 }, /* 30 30 29 30 29 29 29 29 30 29 29 30 353 -1188 */ { 00, 01, 08, 0b0111010010011000 }, /* 29 30 30 30 29 30 29 29 30 29 29 30 354 -1189 */ { 05, 01, 26, 0b0110101010101000 }, /* 29 30 30 29 30 29 30 29 30 29 30 29 30 384 -1190 */ { 00, 02, 14, 0b0101101010100000 }, /* 29 30 29 30 30 29 30 29 30 29 30 29 354 -1191 */ { 00, 02, 03, 0b1001101101010000 }, /* 30 29 29 30 30 29 30 30 29 30 29 30 355 -1192 */ { 02, 01, 24, 0b0100101101101000 }, /* 29 30 29 29 30 29 30 30 29 30 30 29 30 384 -1193 */ { 00, 02, 11, 0b0100101011100000 }, /* 29 30 29 29 30 29 30 29 30 30 30 29 354 -1194 */ { 10, 01, 31, 0b1010010011101000 }, /* 30 29 30 29 29 30 29 29 30 30 30 29 30 384 -1195 */ { 00, 02, 19, 0b1010010011010000 }, /* 30 29 30 29 29 30 29 29 30 30 29 30 354 -1196 */ { 00, 02, 08, 0b1101001001100000 }, /* 30 30 29 30 29 29 30 29 29 30 30 29 354 -1197 */ { 06, 01, 27, 0b1101010100101000 }, /* 30 30 29 30 29 30 29 30 29 29 30 29 30 384 -1198 */ { 00, 02, 15, 0b1011010100100000 }, /* 30 29 30 30 29 30 29 30 29 29 30 29 354 -1199 */ { 00, 02, 04, 0b1101011010100000 }, /* 30 30 29 30 29 30 30 29 30 29 30 29 355 -1200 */ { 02, 01, 25, 0b0101011011010000 }, /* 29 30 29 30 29 30 30 29 30 30 29 30 29 384 -1201 */ { 00, 02, 12, 0b1001010111010000 }, /* 30 29 29 30 29 30 29 30 30 30 29 30 355 -1202 */ { 12, 02, 02, 0b0100100111011000 }, /* 29 30 29 29 30 29 29 30 30 30 29 30 30 384 -1203 */ { 00, 02, 21, 0b0100100110110000 }, /* 29 30 29 29 30 29 29 30 30 29 30 30 354 -1204 */ { 00, 02, 10, 0b1010010010110000 }, /* 30 29 30 29 29 30 29 29 30 29 30 30 354 -1205 */ { 08, 01, 29, 0b1010101001011000 }, /* 30 29 30 29 30 29 30 29 29 30 29 30 30 384 -1206 */ { 00, 02, 17, 0b0110101001010000 }, /* 29 30 30 29 30 29 30 29 29 30 29 30 354 -1207 */ { 00, 02, 06, 0b1011010101000000 }, /* 30 29 30 30 29 30 29 30 29 30 29 29 354 -1208 */ { 04, 01, 26, 0b1011010110100000 }, /* 30 29 30 30 29 30 29 30 30 29 30 29 29 384 -1209 */ { 00, 02, 13, 0b1010101101100000 }, /* 30 29 30 29 30 29 30 30 29 30 30 29 355 -1210 */ { 00, 02, 03, 0b1001010110110000 }, /* 30 29 29 30 29 30 29 30 30 29 30 30 355 -1211 */ { 02, 01, 24, 0b0100100110111000 }, /* 29 30 29 29 30 29 29 30 30 29 30 30 30 384 -1212 */ { 00, 02, 12, 0b0100100101110000 }, /* 29 30 29 29 30 29 29 30 29 30 30 30 354 -1213 */ { 09, 01, 31, 0b0110010010111000 }, /* 29 30 30 29 29 30 29 29 30 29 30 30 30 384 -1214 */ { 00, 02, 19, 0b0101010010110000 }, /* 29 30 29 30 29 30 29 29 30 29 30 30 354 -1215 */ { 00, 02, 08, 0b0110101001010000 }, /* 29 30 30 29 30 29 30 29 29 30 29 30 354 -1216 */ { 07, 01, 28, 0b0110110100101000 }, /* 29 30 30 29 30 30 29 30 29 29 30 29 30 384 -1217 */ { 00, 02, 15, 0b0101101011000000 }, /* 29 30 29 30 30 29 30 29 30 30 29 29 354 -1218 */ { 00, 02, 04, 0b1010101101100000 }, /* 30 29 30 29 30 29 30 30 29 30 30 29 355 -1219 */ { 03, 01, 25, 0b1001001101110000 }, /* 30 29 29 30 29 29 30 30 29 30 30 30 29 384 -1220 */ { 00, 02, 13, 0b1001001011100000 }, /* 30 29 29 30 29 29 30 29 30 30 30 29 354 -1221 */ { 12, 02, 01, 0b1100100101110000 }, /* 30 30 29 29 30 29 29 30 29 30 30 30 29 384 -1222 */ { 00, 02, 20, 0b1100100101100000 }, /* 30 30 29 29 30 29 29 30 29 30 30 29 354 -1223 */ { 00, 02, 09, 0b1101010010100000 }, /* 30 30 29 30 29 30 29 29 30 29 30 29 354 -1224 */ { 08, 01, 29, 0b1101101001010000 }, /* 30 30 29 30 30 29 30 29 29 30 29 30 29 384 -1225 */ { 00, 02, 16, 0b1011010101010000 }, /* 30 29 30 30 29 30 29 30 29 30 29 30 355 -1226 */ { 00, 02, 06, 0b0101011010100000 }, /* 29 30 29 30 29 30 30 29 30 29 30 29 354 -1227 */ { 05, 01, 26, 0b1010101011011000 }, /* 30 29 30 29 30 29 30 29 30 30 29 30 30 385 -1228 */ { 00, 02, 15, 0b0010010111010000 }, /* 29 29 30 29 29 30 29 30 30 30 29 30 354 -1229 */ { 00, 02, 03, 0b1001001011100000 }, /* 30 29 29 30 29 29 30 29 30 30 30 29 354 -1230 */ { 02, 01, 23, 0b1100100101011000 }, /* 30 30 29 29 30 29 29 30 29 30 29 30 30 384 -1231 */ { 00, 02, 11, 0b1010100101010000 }, /* 30 29 30 29 30 29 29 30 29 30 29 30 354 -1232 */ { 09, 01, 31, 0b1101010010101000 }, /* 30 30 29 30 29 30 29 29 30 29 30 29 30 384 -1233 */ { 00, 02, 18, 0b1011001010100000 }, /* 30 29 30 30 29 29 30 29 30 29 30 29 354 -1234 */ { 00, 02, 07, 0b1011010101010000 }, /* 30 29 30 30 29 30 29 30 29 30 29 30 355 -1235 */ { 07, 01, 28, 0b0101011010101000 }, /* 29 30 29 30 29 30 30 29 30 29 30 29 30 384 -1236 */ { 00, 02, 16, 0b0100110110100000 }, /* 29 30 29 29 30 30 29 30 30 29 30 29 354 -1237 */ { 00, 02, 04, 0b1010010110110000 }, /* 30 29 30 29 29 30 29 30 30 29 30 30 355 -1238 */ { 04, 01, 25, 0b0101001010111000 }, /* 29 30 29 30 29 29 30 29 30 29 30 30 30 384 -1239 */ { 00, 02, 13, 0b0101001010110000 }, /* 29 30 29 30 29 29 30 29 30 29 30 30 354 -1240 */ { 12, 02, 02, 0b1010100100111000 }, /* 30 29 30 29 30 29 29 30 29 29 30 30 30 384 -1241 */ { 00, 02, 20, 0b0110100100110000 }, /* 29 30 30 29 30 29 29 30 29 29 30 30 354 -1242 */ { 00, 02, 09, 0b0110101010100000 }, /* 29 30 30 29 30 29 30 29 30 29 30 29 354 -1243 */ { 08, 01, 29, 0b1010110101010000 }, /* 30 29 30 29 30 30 29 30 29 30 29 30 29 384 -1244 */ { 00, 02, 17, 0b1010111001010000 }, /* 30 29 30 29 30 30 30 29 29 30 29 30 355 -1245 */ { 00, 02, 06, 0b0100101101100000 }, /* 29 30 29 29 30 29 30 30 29 30 30 29 354 -1246 */ { 04, 01, 26, 0b1010010101110000 }, /* 30 29 30 29 29 30 29 30 29 30 30 30 29 384 -1247 */ { 00, 02, 14, 0b1010010101110000 }, /* 30 29 30 29 29 30 29 30 29 30 30 30 355 -1248 */ { 00, 02, 04, 0b0101001001110000 }, /* 29 30 29 30 29 29 30 29 29 30 30 30 354 -1249 */ { 02, 01, 23, 0b0110100100110000 }, /* 29 30 30 29 30 29 29 30 29 29 30 30 29 383 -1250 */ { 00, 02, 10, 0b1110010100110000 }, /* 30 30 30 29 29 30 29 30 29 29 30 30 355 -1251 */ { 10, 01, 31, 0b0110110010011000 }, /* 29 30 30 29 30 30 29 29 30 29 29 30 30 384 -1252 */ { 00, 02, 19, 0b0101101010100000 }, /* 29 30 29 30 30 29 30 29 30 29 30 29 354 -1253 */ { 00, 02, 07, 0b0101101011010000 }, /* 29 30 29 30 30 29 30 29 30 30 29 30 355 -1254 */ { 06, 01, 28, 0b0100101101101000 }, /* 29 30 29 29 30 29 30 30 29 30 30 29 30 384 -1255 */ { 00, 02, 16, 0b0100101011100000 }, /* 29 30 29 29 30 29 30 29 30 30 30 29 354 -1256 */ { 00, 02, 05, 0b1010010011100000 }, /* 30 29 30 29 29 30 29 29 30 30 30 29 354 -1257 */ { 04, 01, 24, 0b1101001001101000 }, /* 30 30 29 30 29 29 30 29 29 30 30 29 30 384 -1258 */ { 00, 02, 12, 0b1101001001100000 }, /* 30 30 29 30 29 29 30 29 29 30 30 29 354 -1259 */ { 11, 02, 01, 0b1101010100101000 }, /* 30 30 29 30 29 30 29 30 29 29 30 29 30 384 -1260 */ { 00, 02, 20, 0b1011010100100000 }, /* 30 29 30 30 29 30 29 30 29 29 30 29 354 -1261 */ { 00, 02, 08, 0b1011011010100000 }, /* 30 29 30 30 29 30 30 29 30 29 30 29 355 -1262 */ { 09, 01, 29, 0b0101011011010000 }, /* 29 30 29 30 29 30 30 29 30 30 29 30 29 384 -1263 */ { 00, 02, 17, 0b0101010101110000 }, /* 29 30 29 30 29 30 29 30 29 30 30 30 355 -1264 */ { 00, 02, 07, 0b0100100111010000 }, /* 29 30 29 29 30 29 29 30 30 30 29 30 354 -1265 */ { 05, 01, 26, 0b1010010011011000 }, /* 30 29 30 29 29 30 29 29 30 30 29 30 30 384 -1266 */ { 00, 02, 14, 0b1010010010110000 }, /* 30 29 30 29 29 30 29 29 30 29 30 30 354 -1267 */ { 00, 02, 03, 0b1010101001010000 }, /* 30 29 30 29 30 29 30 29 29 30 29 30 354 -1268 */ { 01, 01, 23, 0b1011010100101000 }, /* 30 29 30 30 29 30 29 30 29 29 30 29 30 384 -1269 */ { 00, 02, 10, 0b1011010100100000 }, /* 30 29 30 30 29 30 29 30 29 29 30 29 354 -1270 */ { 11, 01, 30, 0b1011010111000000 }, /* 30 29 30 30 29 30 29 30 30 30 29 29 29 384 -1271 */ { 00, 02, 18, 0b1010101101100000 }, /* 30 29 30 29 30 29 30 30 29 30 30 29 355 -1272 */ { 00, 02, 08, 0b1001010110110000 }, /* 30 29 29 30 29 30 29 30 30 29 30 30 355 -1273 */ { 06, 01, 28, 0b0100100110111000 }, /* 29 30 29 29 30 29 29 30 30 29 30 30 30 384 -1274 */ { 00, 02, 16, 0b0100100101110000 }, /* 29 30 29 29 30 29 29 30 29 30 30 30 354 -1275 */ { 00, 02, 05, 0b0110010010110000 }, /* 29 30 30 29 29 30 29 29 30 29 30 30 354 -1276 */ { 03, 01, 25, 0b0110101001011000 }, /* 29 30 30 29 30 29 30 29 29 30 29 30 30 384 -1277 */ { 00, 02, 12, 0b0110101001010000 }, /* 29 30 30 29 30 29 30 29 29 30 29 30 354 -1278 */ { 11, 02, 01, 0b0110101100101000 }, /* 29 30 30 29 30 29 30 30 29 29 30 29 30 384 -1279 */ { 00, 02, 20, 0b0101101011000000 }, /* 29 30 29 30 30 29 30 29 30 30 29 29 354 -1280 */ { 00, 02, 09, 0b1010101101100000 }, /* 30 29 30 29 30 29 30 30 29 30 30 29 355 -1281 */ { 08, 01, 29, 0b0010101011101000 }, /* 29 29 30 29 30 29 30 29 30 30 30 29 30 384 -1282 */ { 00, 02, 17, 0b0100100111100000 }, /* 29 30 29 29 30 29 29 30 30 30 30 29 354 -1283 */ { 00, 02, 06, 0b1010010011010000 }, /* 30 29 30 29 29 30 29 29 30 30 29 30 354 -1284 */ { 05, 01, 26, 0b1101001001011000 }, /* 30 30 29 30 29 29 30 29 29 30 29 30 30 384 -1285 */ { 00, 02, 13, 0b1011001001010000 }, /* 30 29 30 30 29 29 30 29 29 30 29 30 354 -1286 */ { 00, 02, 02, 0b1011010100100000 }, /* 30 29 30 30 29 30 29 30 29 29 30 29 354 -1287 */ { 02, 01, 22, 0b1111001010010000 }, /* 30 30 30 30 29 29 30 29 30 29 29 30 29 384 -1288 */ { 00, 02, 10, 0b1011010110100000 }, /* 30 29 30 30 29 30 29 30 30 29 30 29 355 -1289 */ { 10, 01, 30, 0b1001010111010000 }, /* 30 29 29 30 29 30 29 30 30 30 29 30 29 384 -1290 */ { 00, 02, 18, 0b1001010110110000 }, /* 30 29 29 30 29 30 29 30 30 29 30 30 355 -1291 */ { 00, 02, 08, 0b0100100110110000 }, /* 29 30 29 29 30 29 29 30 30 29 30 30 354 -1292 */ { 06, 01, 28, 0b1010010010111000 }, /* 30 29 30 29 29 30 29 29 30 29 30 30 30 384 -1293 */ { 00, 02, 15, 0b1010010010110000 }, /* 30 29 30 29 29 30 29 29 30 29 30 30 354 -1294 */ { 00, 02, 04, 0b1010101001010000 }, /* 30 29 30 29 30 29 30 29 29 30 29 30 354 -1295 */ { 04, 01, 24, 0b1011010100101000 }, /* 30 29 30 30 29 30 29 30 29 29 30 29 30 384 -1296 */ { 00, 02, 12, 0b0110110101000000 }, /* 29 30 30 29 30 30 29 30 29 30 29 29 354 -1297 */ { 12, 01, 31, 0b1010110101100000 }, /* 30 29 30 29 30 30 29 30 29 30 30 29 29 384 -1298 */ { 00, 02, 19, 0b1010101101100000 }, /* 30 29 30 29 30 29 30 30 29 30 30 29 355 -1299 */ { 00, 02, 09, 0b1001001101110000 }, /* 30 29 29 30 29 29 30 30 29 30 30 30 355 -1300 */ { 08, 01, 30, 0b0000100101111000 }, /* 29 29 29 29 30 29 29 30 29 30 30 30 30 383 -1301 */ { 00, 02, 18, 0b0100100101110000 }, /* 29 30 29 29 30 29 29 30 29 30 30 30 354 -1302 */ { 00, 02, 07, 0b0110010010110000 }, /* 29 30 30 29 29 30 29 29 30 29 30 30 354 -1303 */ { 05, 01, 27, 0b0110101001010000 }, /* 29 30 30 29 30 29 30 29 29 30 29 30 29 383 -1304 */ { 00, 02, 14, 0b1101101001010000 }, /* 30 30 29 30 30 29 30 29 29 30 29 30 355 -1305 */ { 00, 02, 03, 0b0101101010100000 }, /* 29 30 29 30 30 29 30 29 30 29 30 29 354 -1306 */ { 01, 01, 23, 0b1010101101100000 }, /* 30 29 30 29 30 29 30 30 29 30 30 29 29 384 -1307 */ { 00, 02, 11, 0b1010011011100000 }, /* 30 29 30 29 29 30 30 29 30 30 30 29 355 -1308 */ { 11, 02, 01, 0b1001001011101000 }, /* 30 29 29 30 29 29 30 29 30 30 30 29 30 384 -1309 */ { 00, 02, 19, 0b1001001011100000 }, /* 30 29 29 30 29 29 30 29 30 30 30 29 354 -1310 */ { 00, 02, 08, 0b1100100101100000 }, /* 30 30 29 29 30 29 29 30 29 30 30 29 354 -1311 */ { 07, 01, 28, 0b1101010010101000 }, /* 30 30 29 30 29 30 29 29 30 29 30 29 30 384 -1312 */ { 00, 02, 16, 0b1101010010100000 }, /* 30 30 29 30 29 30 29 29 30 29 30 29 354 -1313 */ { 00, 02, 04, 0b1101010101010000 }, /* 30 30 29 30 29 30 29 30 29 30 29 30 355 -1314 */ { 03, 01, 25, 0b0101101010101000 }, /* 29 30 29 30 30 29 30 29 30 29 30 29 30 384 -1315 */ { 00, 02, 13, 0b0101011010100000 }, /* 29 30 29 30 29 30 30 29 30 29 30 29 354 -1316 */ { 00, 02, 02, 0b1010011011010000 }, /* 30 29 30 29 29 30 30 29 30 30 29 30 355 -1317 */ { 01, 01, 22, 0b1001001011101000 }, /* 30 29 29 30 29 29 30 29 30 30 30 29 30 384 -1318 */ { 00, 02, 10, 0b1001001010110000 }, /* 30 29 29 30 29 29 30 29 30 29 30 30 354 -1319 */ { 08, 01, 30, 0b1010010101011000 }, /* 30 29 30 29 29 30 29 30 29 30 29 30 30 384 -1320 */ { 00, 02, 18, 0b1010100101010000 }, /* 30 29 30 29 30 29 29 30 29 30 29 30 354 -1321 */ { 00, 02, 06, 0b1011001010100000 }, /* 30 29 30 30 29 29 30 29 30 29 30 29 354 -1322 */ { 05, 01, 26, 0b1011010101010000 }, /* 30 29 30 30 29 30 29 30 29 30 29 30 29 384 -1323 */ { 00, 02, 14, 0b1010110101010000 }, /* 30 29 30 29 30 30 29 30 29 30 29 30 355 -1324 */ { 00, 02, 04, 0b0100110110100000 }, /* 29 30 29 29 30 30 29 30 30 29 30 29 354 -1325 */ { 01, 01, 23, 0b1010010111010000 }, /* 30 29 30 29 29 30 29 30 30 30 29 30 29 384 -1326 */ { 00, 02, 11, 0b1010010101110000 }, /* 30 29 30 29 29 30 29 30 29 30 30 30 355 -1327 */ { 09, 02, 01, 0b0101001010111000 }, /* 29 30 29 30 29 29 30 29 30 29 30 30 30 384 -1328 */ { 00, 02, 20, 0b0101001001110000 }, /* 29 30 29 30 29 29 30 29 29 30 30 30 354 -1329 */ { 00, 02, 08, 0b0110100100110000 }, /* 29 30 30 29 30 29 29 30 29 29 30 30 354 -1330 */ { 07, 01, 28, 0b0110101010011000 }, /* 29 30 30 29 30 29 30 29 30 29 29 30 30 384 -1331 */ { 00, 02, 16, 0b0110101010100000 }, /* 29 30 30 29 30 29 30 29 30 29 30 29 354 -1332 */ { 00, 02, 05, 0b1010101101010000 }, /* 30 29 30 29 30 29 30 30 29 30 29 30 355 -1333 */ { 03, 01, 25, 0b0100101110101000 }, /* 29 30 29 29 30 29 30 30 30 29 30 29 30 384 -1334 */ { 00, 02, 13, 0b0100101101100000 }, /* 29 30 29 29 30 29 30 30 29 30 30 29 354 -1335 */ { 12, 02, 02, 0b1010011001110000 }, /* 30 29 30 29 29 30 30 29 29 30 30 30 29 384 -1336 */ { 00, 02, 21, 0b1010001011100000 }, /* 30 29 30 29 29 29 30 29 30 30 30 29 354 -1337 */ { 00, 02, 09, 0b1101000101100000 }, /* 30 30 29 30 29 29 29 30 29 30 30 29 354 -1338 */ { 08, 01, 29, 0b1110100100110000 }, /* 30 30 30 29 30 29 29 30 29 29 30 30 29 384 -1339 */ { 00, 02, 17, 0b1101010010100000 }, /* 30 30 29 30 29 30 29 29 30 29 30 29 354 -1340 */ { 00, 02, 06, 0b1101101010100000 }, /* 30 30 29 30 30 29 30 29 30 29 30 29 355 -1341 */ { 05, 01, 26, 0b0101101101010000 }, /* 29 30 29 30 30 29 30 30 29 30 29 30 29 384 -1342 */ { 00, 02, 14, 0b0101011011010000 }, /* 29 30 29 30 29 30 30 29 30 30 29 30 355 -1343 */ { 00, 02, 04, 0b0100101011100000 }, /* 29 30 29 29 30 29 30 29 30 30 30 29 354 -1344 */ { 02, 01, 24, 0b1010001011101000 }, /* 30 29 30 29 29 29 30 29 30 30 30 29 30 384 -1345 */ { 00, 02, 11, 0b1010001011010000 }, /* 30 29 30 29 29 29 30 29 30 30 29 30 354 -1346 */ { 10, 01, 31, 0b1101000101011000 }, /* 30 30 29 30 29 29 29 30 29 30 29 30 30 384 -1347 */ { 00, 02, 19, 0b1010101001010000 }, /* 30 29 30 29 30 29 30 29 29 30 29 30 354 -1348 */ { 00, 02, 08, 0b1011010100100000 }, /* 30 29 30 30 29 30 29 30 29 29 30 29 354 -1349 */ { 07, 01, 27, 0b1101011010100000 }, /* 30 30 29 30 29 30 30 29 30 29 30 29 29 384 -1350 */ { 00, 02, 15, 0b1010110110100000 }, /* 30 29 30 29 30 30 29 30 30 29 30 29 355 -1351 */ { 00, 02, 05, 0b0101010111010000 }, /* 29 30 29 30 29 30 29 30 30 30 29 30 355 -1352 */ { 03, 01, 26, 0b0100100111011000 }, /* 29 30 29 29 30 29 29 30 30 30 29 30 30 384 -1353 */ { 00, 02, 13, 0b0100010110110000 }, /* 29 30 29 29 29 30 29 30 30 29 30 30 354 -1354 */ { 00, 02, 02, 0b1010001010110000 }, /* 30 29 30 29 29 29 30 29 30 29 30 30 354 -1355 */ { 01, 01, 22, 0b1101000101011000 }, /* 30 30 29 30 29 29 29 30 29 30 29 30 30 384 -1356 */ { 00, 02, 10, 0b1010101001010000 }, /* 30 29 30 29 30 29 30 29 29 30 29 30 354 -1357 */ { 09, 01, 29, 0b1011010100101000 }, /* 30 29 30 30 29 30 29 30 29 29 30 29 30 384 -1358 */ { 00, 02, 17, 0b0110101100100000 }, /* 29 30 30 29 30 29 30 30 29 29 30 29 354 -1359 */ { 00, 02, 06, 0b1010110101100000 }, /* 30 29 30 29 30 30 29 30 29 30 30 29 355 -1360 */ { 05, 01, 27, 0b0101010110110000 }, /* 29 30 29 30 29 30 29 30 30 29 30 30 29 384 -1361 */ { 00, 02, 14, 0b1001001101110000 }, /* 30 29 29 30 29 29 30 30 29 30 30 30 355 -1362 */ { 00, 02, 04, 0b0100010101110000 }, /* 29 30 29 29 29 30 29 30 29 30 30 30 354 -1363 */ { 03, 01, 24, 0b1010001010111000 }, /* 30 29 30 29 29 29 30 29 30 29 30 30 30 384 -1364 */ { 00, 02, 12, 0b0101001010110000 }, /* 29 30 29 30 29 29 30 29 30 29 30 30 354 -1365 */ { 10, 01, 31, 0b1010101001010000 }, /* 30 29 30 29 30 29 30 29 29 30 29 30 29 383 -1366 */ { 00, 02, 18, 0b1101100101010000 }, /* 30 30 29 30 30 29 29 30 29 30 29 30 355 -1367 */ { 00, 02, 08, 0b0101101010100000 }, /* 29 30 29 30 30 29 30 29 30 29 30 29 354 -1368 */ { 07, 01, 28, 0b1010101101100000 }, /* 30 29 30 29 30 29 30 30 29 30 30 29 29 384 -1369 */ { 00, 02, 15, 0b1010011011100000 }, /* 30 29 30 29 29 30 30 29 30 30 30 29 355 -1370 */ { 00, 02, 05, 0b0101001011100000 }, /* 29 30 29 30 29 29 30 29 30 30 30 29 354 -1371 */ { 03, 01, 25, 0b1100010101110000 }, /* 30 30 29 29 29 30 29 30 29 30 30 30 29 384 -1372 */ { 00, 02, 13, 0b1010010101100000 }, /* 30 29 30 29 29 30 29 30 29 30 30 29 354 -1373 */ { 11, 02, 01, 0b1101001010101000 }, /* 30 30 29 30 29 29 30 29 30 29 30 29 30 384 -1374 */ { 00, 02, 20, 0b1101001010100000 }, /* 30 30 29 30 29 29 30 29 30 29 30 29 354 -1375 */ { 00, 02, 09, 0b1101010101010000 }, /* 30 30 29 30 29 30 29 30 29 30 29 30 355 -1376 */ { 09, 01, 30, 0b0101101010101000 }, /* 29 30 29 30 30 29 30 29 30 29 30 29 30 384 -1377 */ { 00, 02, 17, 0b0101011010100000 }, /* 29 30 29 30 29 30 30 29 30 29 30 29 354 -1378 */ { 00, 02, 06, 0b1010011011010000 }, /* 30 29 30 29 29 30 30 29 30 30 29 30 355 -1379 */ { 05, 01, 27, 0b0101001011101000 }, /* 29 30 29 30 29 29 30 29 30 30 30 29 30 384 -1380 */ { 00, 02, 15, 0b0101001010110000 }, /* 29 30 29 30 29 29 30 29 30 29 30 30 354 -1381 */ { 00, 02, 03, 0b1010100011010000 }, /* 30 29 30 29 30 29 29 29 30 30 29 30 354 -1382 */ { 02, 01, 23, 0b1101001010101000 }, /* 30 30 29 30 29 29 30 29 30 29 30 29 30 384 -1383 */ { 00, 02, 11, 0b1011001010100000 }, /* 30 29 30 30 29 29 30 29 30 29 30 29 354 -1384 */ { 10, 01, 31, 0b1011010101010000 }, /* 30 29 30 30 29 30 29 30 29 30 29 30 29 384 -1385 */ { 00, 02, 18, 0b1010110101010000 }, /* 30 29 30 29 30 30 29 30 29 30 29 30 355 -1386 */ { 00, 02, 08, 0b0100110110100000 }, /* 29 30 29 29 30 30 29 30 30 29 30 29 354 -1387 */ { 06, 01, 28, 0b1010010111010000 }, /* 30 29 30 29 29 30 29 30 30 30 29 30 29 384 -1388 */ { 00, 02, 16, 0b1010010101110000 }, /* 30 29 30 29 29 30 29 30 29 30 30 30 355 -1389 */ { 00, 02, 05, 0b0101000110110000 }, /* 29 30 29 30 29 29 29 30 30 29 30 30 354 -1390 */ { 04, 01, 25, 0b1010100010111000 }, /* 30 29 30 29 30 29 29 29 30 29 30 30 30 384 -1391 */ { 00, 02, 13, 0b0110010100110000 }, /* 29 30 30 29 29 30 29 30 29 29 30 30 354 -1392 */ { 12, 02, 02, 0b0110101010011000 }, /* 29 30 30 29 30 29 30 29 30 29 29 30 30 384 -1393 */ { 00, 02, 20, 0b0101101010100000 }, /* 29 30 29 30 30 29 30 29 30 29 30 29 354 -1394 */ { 00, 02, 09, 0b1010101101010000 }, /* 30 29 30 29 30 29 30 30 29 30 29 30 355 -1395 */ { 09, 01, 30, 0b0010101110101000 }, /* 29 29 30 29 30 29 30 30 30 29 30 29 30 384 -1396 */ { 00, 02, 18, 0b0010101101100000 }, /* 29 29 30 29 30 29 30 30 29 30 30 29 354 -1397 */ { 00, 02, 06, 0b1100001101110000 }, /* 30 30 29 29 29 29 30 30 29 30 30 30 355 -1398 */ { 05, 01, 27, 0b0101000101110000 }, /* 29 30 29 30 29 29 29 30 29 30 30 30 29 383 -1399 */ { 00, 02, 14, 0b1100100101100000 }, /* 30 30 29 29 30 29 29 30 29 30 30 29 354 -1400 */ { 00, 02, 03, 0b1110010010110000 }, /* 30 30 30 29 29 30 29 29 30 29 30 30 355 -1401 */ { 03, 01, 24, 0b0110101010010000 }, /* 29 30 30 29 30 29 30 29 30 29 29 30 29 383 -1402 */ { 00, 02, 11, 0b1101101010100000 }, /* 30 30 29 30 30 29 30 29 30 29 30 29 355 -1403 */ { 11, 02, 01, 0b0101101101010000 }, /* 29 30 29 30 30 29 30 30 29 30 29 30 29 384 -1404 */ { 00, 02, 20, 0b0101011011010000 }, /* 29 30 29 30 29 30 30 29 30 30 29 30 355 -1405 */ { 00, 02, 09, 0b0010101011100000 }, /* 29 29 30 29 30 29 30 29 30 30 30 29 354 -1406 */ { 07, 01, 29, 0b1010001011101000 }, /* 30 29 30 29 29 29 30 29 30 30 30 29 30 384 -1407 */ { 00, 02, 17, 0b1010001011010000 }, /* 30 29 30 29 29 29 30 29 30 30 29 30 354 -1408 */ { 00, 02, 06, 0b1101000101010000 }, /* 30 30 29 30 29 29 29 30 29 30 29 30 354 -1409 */ { 04, 01, 25, 0b1101010010101000 }, /* 30 30 29 30 29 30 29 29 30 29 30 29 30 384 -1410 */ { 00, 02, 13, 0b1011010100100000 }, /* 30 29 30 30 29 30 29 30 29 29 30 29 354 -1411 */ { 12, 02, 02, 0b1011011010010000 }, /* 30 29 30 30 29 30 30 29 30 29 29 30 29 384 -1412 */ { 00, 02, 21, 0b1010110110100000 }, /* 30 29 30 29 30 30 29 30 30 29 30 29 355 -1413 */ { 00, 02, 10, 0b0101010111010000 }, /* 29 30 29 30 29 30 29 30 30 30 29 30 355 -1414 */ { 09, 01, 31, 0b0010010111011000 }, /* 29 29 30 29 29 30 29 30 30 30 29 30 30 384 -1415 */ { 00, 02, 19, 0b0100010110110000 }, /* 29 30 29 29 29 30 29 30 30 29 30 30 354 -1416 */ { 00, 02, 08, 0b1010001010110000 }, /* 30 29 30 29 29 29 30 29 30 29 30 30 354 -1417 */ { 05, 01, 27, 0b1010100101011000 }, /* 30 29 30 29 30 29 29 30 29 30 29 30 30 384 -1418 */ { 00, 02, 15, 0b1010100101010000 }, /* 30 29 30 29 30 29 29 30 29 30 29 30 354 -1419 */ { 00, 02, 04, 0b1011010100100000 }, /* 30 29 30 30 29 30 29 30 29 29 30 29 354 -1420 */ { 01, 01, 24, 0b1011010101010000 }, /* 30 29 30 30 29 30 29 30 29 30 29 30 29 384 -1421 */ { 00, 02, 11, 0b1010101101100000 }, /* 30 29 30 29 30 29 30 30 29 30 30 29 355 -1422 */ { 12, 02, 01, 0b0101010110110000 }, /* 29 30 29 30 29 30 29 30 30 29 30 30 29 384 -1423 */ { 00, 02, 20, 0b0100101101110000 }, /* 29 30 29 29 30 29 30 30 29 30 30 30 355 -1424 */ { 00, 02, 10, 0b0100010101110000 }, /* 29 30 29 29 29 30 29 30 29 30 30 30 354 -1425 */ { 07, 01, 29, 0b0101001010111000 }, /* 29 30 29 30 29 29 30 29 30 29 30 30 30 384 -1426 */ { 00, 02, 17, 0b0101001010110000 }, /* 29 30 29 30 29 29 30 29 30 29 30 30 354 -1427 */ { 00, 02, 06, 0b0110100101010000 }, /* 29 30 30 29 30 29 29 30 29 30 29 30 354 -1428 */ { 04, 01, 26, 0b0110110010101000 }, /* 29 30 30 29 30 30 29 29 30 29 30 29 30 384 -1429 */ { 00, 02, 13, 0b0101101010100000 }, /* 29 30 29 30 30 29 30 29 30 29 30 29 354 -1430 */ { 12, 02, 02, 0b1001101101010000 }, /* 30 29 29 30 30 29 30 30 29 30 29 30 29 384 -1431 */ { 00, 02, 21, 0b1010011011100000 }, /* 30 29 30 29 29 30 30 29 30 30 30 29 355 -1432 */ { 00, 02, 11, 0b0100101011100000 }, /* 29 30 29 29 30 29 30 29 30 30 30 29 354 -1433 */ { 08, 01, 30, 0b1010010101110000 }, /* 30 29 30 29 29 30 29 30 29 30 30 30 29 384 -1434 */ { 00, 02, 18, 0b1010010101100000 }, /* 30 29 30 29 29 30 29 30 29 30 30 29 354 -1435 */ { 00, 02, 07, 0b1101001010100000 }, /* 30 30 29 30 29 29 30 29 30 29 30 29 354 -1436 */ { 06, 01, 27, 0b1110100101010000 }, /* 30 30 30 29 30 29 29 30 29 30 29 30 29 384 -1437 */ { 00, 02, 14, 0b1101010101010000 }, /* 30 30 29 30 29 30 29 30 29 30 29 30 355 -1438 */ { 00, 02, 04, 0b0101011010100000 }, /* 29 30 29 30 29 30 30 29 30 29 30 29 354 -1439 */ { 02, 01, 24, 0b1010101011010000 }, /* 30 29 30 29 30 29 30 29 30 30 29 30 29 384 -1440 */ { 00, 02, 12, 0b1001010111100000 }, /* 30 29 29 30 29 30 29 30 30 30 30 29 355 -1441 */ { 11, 02, 01, 0b0100101011101000 }, /* 29 30 29 29 30 29 30 29 30 30 30 29 30 384 -1442 */ { 00, 02, 20, 0b0100100110110000 }, /* 29 30 29 29 30 29 29 30 30 29 30 30 354 -1443 */ { 00, 02, 09, 0b1010010011010000 }, /* 30 29 30 29 29 30 29 29 30 30 29 30 354 -1444 */ { 07, 01, 29, 0b1101001001110000 }, /* 30 30 29 30 29 29 30 29 29 30 30 30 29 384 -1445 */ { 00, 02, 16, 0b1011001010100000 }, /* 30 29 30 30 29 29 30 29 30 29 30 29 354 -1446 */ { 00, 02, 05, 0b1011010101010000 }, /* 30 29 30 30 29 30 29 30 29 30 29 30 355 -1447 */ { 04, 01, 26, 0b0101011010101000 }, /* 29 30 29 30 29 30 30 29 30 29 30 29 30 384 -1448 */ { 00, 02, 14, 0b0010110110100000 }, /* 29 29 30 29 30 30 29 30 30 29 30 29 354 -1449 */ { 00, 02, 02, 0b1001010110110000 }, /* 30 29 29 30 29 30 29 30 30 29 30 30 355 -1450 */ { 01, 01, 23, 0b0100101010111000 }, /* 29 30 29 29 30 29 30 29 30 29 30 30 30 384 -1451 */ { 00, 02, 11, 0b0100100110110000 }, /* 29 30 29 29 30 29 29 30 30 29 30 30 354 -1452 */ { 09, 01, 31, 0b1010010010111000 }, /* 30 29 30 29 29 30 29 29 30 29 30 30 30 384 -1453 */ { 00, 02, 18, 0b0110010010110000 }, /* 29 30 30 29 29 30 29 29 30 29 30 30 354 -1454 */ { 00, 02, 07, 0b0110101010010000 }, /* 29 30 30 29 30 29 30 29 30 29 29 30 354 -1455 */ { 06, 01, 27, 0b1010110101010000 }, /* 30 29 30 29 30 30 29 30 29 30 29 30 29 384 -1456 */ { 00, 02, 15, 0b0110101101010000 }, /* 29 30 30 29 30 29 30 30 29 30 29 30 355 -1457 */ { 00, 02, 04, 0b0010101101100000 }, /* 29 29 30 29 30 29 30 30 29 30 30 29 354 -1458 */ { 02, 01, 24, 0b1001010101110000 }, /* 30 29 29 30 29 30 29 30 29 30 30 30 29 384 -1459 */ { 00, 02, 12, 0b1001001101110000 }, /* 30 29 29 30 29 29 30 30 29 30 30 30 355 -1460 */ { 11, 02, 02, 0b0100100101110000 }, /* 29 30 29 29 30 29 29 30 29 30 30 30 29 383 -1461 */ { 00, 02, 19, 0b1100100101100000 }, /* 30 30 29 29 30 29 29 30 29 30 30 29 354 -1462 */ { 00, 02, 08, 0b1110010010110000 }, /* 30 30 30 29 29 30 29 29 30 29 30 30 355 -1463 */ { 07, 01, 29, 0b0110101010010000 }, /* 29 30 30 29 30 29 30 29 30 29 29 30 29 383 -1464 */ { 00, 02, 16, 0b1101101010100000 }, /* 30 30 29 30 30 29 30 29 30 29 30 29 355 -1465 */ { 00, 02, 05, 0b0101101011010000 }, /* 29 30 29 30 30 29 30 29 30 30 29 30 355 -1466 */ { 03, 01, 26, 0b0010101101101000 }, /* 29 29 30 29 30 29 30 30 29 30 30 29 30 384 -1467 */ { 00, 02, 14, 0b0010011011100000 }, /* 29 29 30 29 29 30 30 29 30 30 30 29 354 -1468 */ { 00, 02, 03, 0b1001001011100000 }, /* 30 29 29 30 29 29 30 29 30 30 30 29 354 -1469 */ { 02, 01, 22, 0b1100100101101000 }, /* 30 30 29 29 30 29 29 30 29 30 30 29 30 384 -1470 */ { 00, 02, 10, 0b1100100101010000 }, /* 30 30 29 29 30 29 29 30 29 30 29 30 354 -1471 */ { 09, 01, 30, 0b1101010010101000 }, /* 30 30 29 30 29 30 29 29 30 29 30 29 30 384 -1472 */ { 00, 02, 18, 0b1011010010100000 }, /* 30 29 30 30 29 30 29 29 30 29 30 29 354 -1473 */ { 00, 02, 06, 0b1011011010010000 }, /* 30 29 30 30 29 30 30 29 30 29 29 30 355 -1474 */ { 06, 01, 27, 0b0101011011010000 }, /* 29 30 29 30 29 30 30 29 30 30 29 30 29 384 -1475 */ { 00, 02, 15, 0b0101010110110000 }, /* 29 30 29 30 29 30 29 30 30 29 30 30 355 -1476 */ { 00, 02, 05, 0b0010010111010000 }, /* 29 29 30 29 29 30 29 30 30 30 29 30 354 -1477 */ { 02, 01, 24, 0b1001001011011000 }, /* 30 29 29 30 29 29 30 29 30 30 29 30 30 384 -1478 */ { 00, 02, 12, 0b1001001010110000 }, /* 30 29 29 30 29 29 30 29 30 29 30 30 354 -1479 */ { 10, 02, 01, 0b1010100101011000 }, /* 30 29 30 29 30 29 29 30 29 30 29 30 30 384 -1480 */ { 00, 02, 20, 0b0110100101010000 }, /* 29 30 30 29 30 29 29 30 29 30 29 30 354 -1481 */ { 00, 02, 08, 0b0111010010100000 }, /* 29 30 30 30 29 30 29 29 30 29 30 29 354 -1482 */ { 08, 01, 28, 0b1011010101010000 }, /* 30 29 30 30 29 30 29 30 29 30 29 30 29 384 -1483 */ { 00, 02, 16, 0b1010101101100000 }, /* 30 29 30 29 30 29 30 30 29 30 30 29 355 -1484 */ { 00, 02, 06, 0b0101001110110000 }, /* 29 30 29 30 29 29 30 30 30 29 30 30 355 -1485 */ { 04, 01, 26, 0b0010010110111000 }, /* 29 29 30 29 29 30 29 30 30 29 30 30 30 384 -1486 */ { 00, 02, 14, 0b0010010101110000 }, /* 29 29 30 29 29 30 29 30 29 30 30 30 354 -1487 */ { 00, 02, 03, 0b0101001010110000 }, /* 29 30 29 30 29 29 30 29 30 29 30 30 354 -1488 */ { 01, 01, 23, 0b1010100101011000 }, /* 30 29 30 29 30 29 29 30 29 30 29 30 30 384 -1489 */ { 00, 02, 10, 0b0110100101010000 }, /* 29 30 30 29 30 29 29 30 29 30 29 30 354 -1490 */ { 09, 01, 30, 0b0110101010101000 }, /* 29 30 30 29 30 29 30 29 30 29 30 29 30 384 -1491 */ { 00, 02, 18, 0b0101101010100000 }, /* 29 30 29 30 30 29 30 29 30 29 30 29 354 -1492 */ { 00, 02, 07, 0b1010101101010000 }, /* 30 29 30 29 30 29 30 30 29 30 29 30 355 -1493 */ { 05, 01, 27, 0b0100101101101000 }, /* 29 30 29 29 30 29 30 30 29 30 30 29 30 384 -1494 */ { 00, 02, 15, 0b0100101011100000 }, /* 29 30 29 29 30 29 30 29 30 30 30 29 354 -1495 */ { 00, 02, 04, 0b1010010101110000 }, /* 30 29 30 29 29 30 29 30 29 30 30 30 355 -1496 */ { 03, 01, 25, 0b0101001001110000 }, /* 29 30 29 30 29 29 30 29 29 30 30 30 29 383 -1497 */ { 00, 02, 11, 0b1101001010100000 }, /* 30 30 29 30 29 29 30 29 30 29 30 29 354 -1498 */ { 11, 01, 31, 0b1101100101010000 }, /* 30 30 29 30 30 29 29 30 29 30 29 30 29 384 -1499 */ { 00, 02, 19, 0b1011010101010000 }, /* 30 29 30 30 29 30 29 30 29 30 29 30 355 -1500 */ { 00, 02, 09, 0b0101011010100000 }, /* 29 30 29 30 29 30 30 29 30 29 30 29 354 -1501 */ { 07, 01, 29, 0b1001011011010000 }, /* 30 29 29 30 29 30 30 29 30 30 29 30 29 384 -1502 */ { 00, 02, 17, 0b1001010111010000 }, /* 30 29 29 30 29 30 29 30 30 30 29 30 355 -1503 */ { 00, 02, 07, 0b0100101011100000 }, /* 29 30 29 29 30 29 30 29 30 30 30 29 354 -1504 */ { 04, 01, 27, 0b1010010011011000 }, /* 30 29 30 29 29 30 29 29 30 30 29 30 30 384 -1505 */ { 00, 02, 14, 0b1010010011010000 }, /* 30 29 30 29 29 30 29 29 30 30 29 30 354 -1506 */ { 00, 02, 03, 0b1101001001010000 }, /* 30 30 29 30 29 29 30 29 29 30 29 30 354 -1507 */ { 01, 01, 23, 0b1101010101010000 }, /* 30 30 29 30 29 30 29 30 29 30 29 30 29 384 -1508 */ { 00, 02, 11, 0b1011010101010000 }, /* 30 29 30 30 29 30 29 30 29 30 29 30 355 -1509 */ { 09, 01, 31, 0b0101011010101000 }, /* 29 30 29 30 29 30 30 29 30 29 30 29 30 384 -1510 */ { 00, 02, 19, 0b0010110110100000 }, /* 29 29 30 29 30 30 29 30 30 29 30 29 354 -1511 */ { 00, 02, 08, 0b1001010110110000 }, /* 30 29 29 30 29 30 29 30 30 29 30 30 355 -1512 */ { 05, 01, 29, 0b0100100110111000 }, /* 29 30 29 29 30 29 29 30 30 29 30 30 30 384 -1513 */ { 00, 02, 16, 0b0100100101110000 }, /* 29 30 29 29 30 29 29 30 29 30 30 30 354 -1514 */ { 00, 02, 05, 0b1010010010110000 }, /* 30 29 30 29 29 30 29 29 30 29 30 30 354 -1515 */ { 04, 01, 25, 0b1011001001011000 }, /* 30 29 30 30 29 29 30 29 29 30 29 30 30 384 -1516 */ { 00, 02, 13, 0b0110101010010000 }, /* 29 30 30 29 30 29 30 29 30 29 29 30 354 -1517 */ { 12, 02, 01, 0b1010110101010000 }, /* 30 29 30 29 30 30 29 30 29 30 29 30 29 384 -1518 */ { 00, 02, 20, 0b0101101101010000 }, /* 29 30 29 30 30 29 30 30 29 30 29 30 355 -1519 */ { 00, 02, 10, 0b0010101101100000 }, /* 29 29 30 29 30 29 30 30 29 30 30 29 354 -1520 */ { 08, 01, 30, 0b1001010101110000 }, /* 30 29 29 30 29 30 29 30 29 30 30 30 29 384 -1521 */ { 00, 02, 17, 0b1001001011110000 }, /* 30 29 29 30 29 29 30 29 30 30 30 30 355 -1522 */ { 00, 02, 07, 0b0100100101110000 }, /* 29 30 29 29 30 29 29 30 29 30 30 30 354 -1523 */ { 04, 01, 27, 0b0110010010110000 }, /* 29 30 30 29 29 30 29 29 30 29 30 30 29 383 -1524 */ { 00, 02, 14, 0b1101010010100000 }, /* 30 30 29 30 29 30 29 29 30 29 30 29 354 -1525 */ { 12, 02, 02, 0b1110101001010000 }, /* 30 30 30 29 30 29 30 29 29 30 29 30 29 384 -1526 */ { 00, 02, 21, 0b1101011010010000 }, /* 30 30 29 30 29 30 30 29 30 29 29 30 355 -1527 */ { 00, 02, 11, 0b0101011011010000 }, /* 29 30 29 30 29 30 30 29 30 30 29 30 355 -1528 */ { 10, 02, 01, 0b0010101101101000 }, /* 29 29 30 29 30 29 30 30 29 30 30 29 30 384 -1529 */ { 00, 02, 19, 0b0010011011100000 }, /* 29 29 30 29 29 30 30 29 30 30 30 29 354 -1530 */ { 00, 02, 08, 0b0101001011100000 }, /* 29 30 29 30 29 29 30 29 30 30 30 29 354 -1531 */ { 06, 01, 28, 0b1100100101101000 }, /* 30 30 29 29 30 29 29 30 29 30 30 29 30 384 -1532 */ { 00, 02, 16, 0b1100100101010000 }, /* 30 30 29 29 30 29 29 30 29 30 29 30 354 -1533 */ { 00, 02, 04, 0b1101010010100000 }, /* 30 30 29 30 29 30 29 29 30 29 30 29 354 -1534 */ { 02, 01, 24, 0b1101101001010000 }, /* 30 30 29 30 30 29 30 29 29 30 29 30 29 384 -1535 */ { 00, 02, 12, 0b1011010110010000 }, /* 30 29 30 30 29 30 29 30 30 29 29 30 355 -1536 */ { 12, 02, 02, 0b0101011011010000 }, /* 29 30 29 30 29 30 30 29 30 30 29 30 29 384 -1537 */ { 00, 02, 20, 0b0101010110110000 }, /* 29 30 29 30 29 30 29 30 30 29 30 30 355 -1538 */ { 00, 02, 10, 0b0010010111010000 }, /* 29 29 30 29 29 30 29 30 30 30 29 30 354 -1539 */ { 07, 01, 30, 0b1001001011011000 }, /* 30 29 29 30 29 29 30 29 30 30 29 30 30 384 -1540 */ { 00, 02, 18, 0b1001001010110000 }, /* 30 29 29 30 29 29 30 29 30 29 30 30 354 -1541 */ { 00, 02, 06, 0b1010100101010000 }, /* 30 29 30 29 30 29 29 30 29 30 29 30 354 -1542 */ { 05, 01, 26, 0b1011010010101000 }, /* 30 29 30 30 29 30 29 29 30 29 30 29 30 384 -1543 */ { 00, 02, 14, 0b0110110010100000 }, /* 29 30 30 29 30 30 29 29 30 29 30 29 354 -1544 */ { 00, 02, 03, 0b1010110101010000 }, /* 30 29 30 29 30 30 29 30 29 30 29 30 355 -1545 */ { 01, 01, 23, 0b0101010110110000 }, /* 29 30 29 30 29 30 29 30 30 29 30 30 29 384 -1546 */ { 00, 02, 11, 0b0100101110110000 }, /* 29 30 29 29 30 29 30 30 30 29 30 30 355 -1547 */ { 09, 02, 01, 0b0010010110111000 }, /* 29 29 30 29 29 30 29 30 30 29 30 30 30 384 -1548 */ { 00, 02, 20, 0b0010010101110000 }, /* 29 29 30 29 29 30 29 30 29 30 30 30 354 -1549 */ { 00, 02, 08, 0b0101001010110000 }, /* 29 30 29 30 29 29 30 29 30 29 30 30 354 -1550 */ { 06, 01, 28, 0b1010100101010000 }, /* 30 29 30 29 30 29 29 30 29 30 29 30 29 383 -1551 */ { 00, 02, 15, 0b1110100101010000 }, /* 30 30 30 29 30 29 29 30 29 30 29 30 355 -1552 */ { 00, 02, 05, 0b0110101010100000 }, /* 29 30 30 29 30 29 30 29 30 29 30 29 354 -1553 */ { 03, 01, 24, 0b1010110101010000 }, /* 30 29 30 29 30 30 29 30 29 30 29 30 29 384 -1554 */ { 00, 02, 12, 0b1010101101010000 }, /* 30 29 30 29 30 29 30 30 29 30 29 30 355 -1555 */ { 11, 02, 02, 0b0100101101101000 }, /* 29 30 29 29 30 29 30 30 29 30 30 29 30 384 -1556 */ { 00, 02, 21, 0b0100101011100000 }, /* 29 30 29 29 30 29 30 29 30 30 30 29 354 -1557 */ { 00, 02, 09, 0b1010010101110000 }, /* 30 29 30 29 29 30 29 30 29 30 30 30 355 -1558 */ { 07, 01, 30, 0b0101001001101000 }, /* 29 30 29 30 29 29 30 29 29 30 30 29 30 383 -1559 */ { 00, 02, 17, 0b1101001001100000 }, /* 30 30 29 30 29 29 30 29 29 30 30 29 354 -1560 */ { 00, 02, 06, 0b1101100101010000 }, /* 30 30 29 30 30 29 29 30 29 30 29 30 355 -1561 */ { 05, 01, 26, 0b0101101010101000 }, /* 29 30 29 30 30 29 30 29 30 29 30 29 30 384 -1562 */ { 00, 02, 14, 0b0101011010100000 }, /* 29 30 29 30 29 30 30 29 30 29 30 29 354 -1563 */ { 00, 02, 03, 0b1001011011010000 }, /* 30 29 29 30 29 30 30 29 30 30 29 30 355 -1564 */ { 02, 01, 24, 0b0100101011101000 }, /* 29 30 29 29 30 29 30 29 30 30 30 29 30 384 -1565 */ { 00, 02, 11, 0b0100101011100000 }, /* 29 30 29 29 30 29 30 29 30 30 30 29 354 -1566 */ { 10, 01, 31, 0b1010010011011000 }, /* 30 29 30 29 29 30 29 29 30 30 29 30 30 384 -1567 */ { 00, 02, 19, 0b1010010011010000 }, /* 30 29 30 29 29 30 29 29 30 30 29 30 354 -1568 */ { 00, 02, 08, 0b1101001001010000 }, /* 30 30 29 30 29 29 30 29 29 30 29 30 354 -1569 */ { 06, 01, 27, 0b1101010101001000 }, /* 30 30 29 30 29 30 29 30 29 30 29 29 30 384 -1570 */ { 00, 02, 15, 0b1011010101010000 }, /* 30 29 30 30 29 30 29 30 29 30 29 30 355 -1571 */ { 00, 02, 05, 0b0011010110100000 }, /* 29 29 30 30 29 30 29 30 30 29 30 29 354 -1572 */ { 02, 01, 25, 0b1001010111010000 }, /* 30 29 29 30 29 30 29 30 30 30 29 30 29 384 -1573 */ { 00, 02, 12, 0b1001010110110000 }, /* 30 29 29 30 29 30 29 30 30 29 30 30 355 -1574 */ { 12, 02, 02, 0b0100100110111000 }, /* 29 30 29 29 30 29 29 30 30 29 30 30 30 384 -1575 */ { 00, 02, 21, 0b0100100101110000 }, /* 29 30 29 29 30 29 29 30 29 30 30 30 354 -1576 */ { 00, 02, 10, 0b1010010010110000 }, /* 30 29 30 29 29 30 29 29 30 29 30 30 354 -1577 */ { 08, 01, 29, 0b1011001001011000 }, /* 30 29 30 30 29 29 30 29 29 30 29 30 30 384 -1578 */ { 00, 02, 17, 0b0110101001010000 }, /* 29 30 30 29 30 29 30 29 29 30 29 30 354 -1579 */ { 00, 02, 06, 0b0110110101000000 }, /* 29 30 30 29 30 30 29 30 29 30 29 29 354 -1580 */ { 04, 01, 26, 0b1010110110101000 }, /* 30 29 30 29 30 30 29 30 30 29 30 29 30 385 -1581 */ { 00, 02, 14, 0b0010101101100000 }, /* 29 29 30 29 30 29 30 30 29 30 30 29 354 -1582 */ { 00, 02, 03, 0b1001001101110000 }, /* 30 29 29 30 29 29 30 30 29 30 30 30 355 -1583 */ { 02, 01, 24, 0b0100100101111000 }, /* 29 30 29 29 30 29 29 30 29 30 30 30 30 384 -1584 */ { 00, 02, 12, 0b0100100101110000 }, /* 29 30 29 29 30 29 29 30 29 30 30 30 354 -1585 */ { 09, 01, 31, 0b0110010010110000 }, /* 29 30 30 29 29 30 29 29 30 29 30 30 29 383 -1586 */ { 00, 02, 18, 0b1101010010100000 }, /* 30 30 29 30 29 30 29 29 30 29 30 29 354 -1587 */ { 00, 02, 07, 0b1110101001010000 }, /* 30 30 30 29 30 29 30 29 29 30 29 30 355 -1588 */ { 06, 01, 28, 0b0110101101001000 }, /* 29 30 30 29 30 29 30 30 29 30 29 29 30 384 -1589 */ { 00, 02, 15, 0b0101011011010000 }, /* 29 30 29 30 29 30 30 29 30 30 29 30 355 -1590 */ { 00, 02, 05, 0b0010101101100000 }, /* 29 29 30 29 30 29 30 30 29 30 30 29 354 -1591 */ { 03, 01, 25, 0b1001001011110000 }, /* 30 29 29 30 29 29 30 29 30 30 30 30 29 384 -1592 */ { 00, 02, 13, 0b1001001011100000 }, /* 30 29 29 30 29 29 30 29 30 30 30 29 354 -1593 */ { 11, 02, 01, 0b1100100101101000 }, /* 30 30 29 29 30 29 29 30 29 30 30 29 30 384 -1594 */ { 00, 02, 20, 0b1010100101010000 }, /* 30 29 30 29 30 29 29 30 29 30 29 30 354 -1595 */ { 00, 02, 09, 0b1101010010100000 }, /* 30 30 29 30 29 30 29 29 30 29 30 29 354 -1596 */ { 08, 01, 29, 0b1101101001010000 }, /* 30 30 29 30 30 29 30 29 29 30 29 30 29 384 -1597 */ { 00, 02, 16, 0b1011010011010000 }, /* 30 29 30 30 29 30 29 29 30 30 29 30 355 -1598 */ { 00, 02, 06, 0b0101011010110000 }, /* 29 30 29 30 29 30 30 29 30 29 30 30 355 -1599 */ { 04, 01, 27, 0b0010011011011000 }, /* 29 29 30 29 29 30 30 29 30 30 29 30 30 384 -1600 */ { 00, 02, 15, 0b0010010111010000 }, /* 29 29 30 29 29 30 29 30 30 30 29 30 354 -1601 */ { 00, 02, 03, 0b1001001011010000 }, /* 30 29 29 30 29 29 30 29 30 30 29 30 354 -1602 */ { 02, 01, 23, 0b1100100110011000 }, /* 30 30 29 29 30 29 29 30 30 29 29 30 30 384 -1603 */ { 00, 02, 11, 0b1010100101010000 }, /* 30 29 30 29 30 29 29 30 29 30 29 30 354 -1604 */ { 09, 01, 31, 0b1011010010101000 }, /* 30 29 30 30 29 30 29 29 30 29 30 29 30 384 -1605 */ { 00, 02, 18, 0b0110101010100000 }, /* 29 30 30 29 30 29 30 29 30 29 30 29 354 -1606 */ { 00, 02, 07, 0b1010110101010000 }, /* 30 29 30 29 30 30 29 30 29 30 29 30 355 -1607 */ { 06, 01, 28, 0b0101010110101000 }, /* 29 30 29 30 29 30 29 30 30 29 30 29 30 384 -1608 */ { 00, 02, 16, 0b0100101110110000 }, /* 29 30 29 29 30 29 30 30 30 29 30 30 355 -1609 */ { 00, 02, 05, 0b0010010110110000 }, /* 29 29 30 29 29 30 29 30 30 29 30 30 354 -1610 */ { 03, 01, 25, 0b0101001010111000 }, /* 29 30 29 30 29 29 30 29 30 29 30 30 30 384 -1611 */ { 00, 02, 13, 0b0101001010110000 }, /* 29 30 29 30 29 29 30 29 30 29 30 30 354 -1612 */ { 11, 02, 02, 0b1010100101010000 }, /* 30 29 30 29 30 29 29 30 29 30 29 30 29 383 -1613 */ { 00, 02, 19, 0b1110100101010000 }, /* 30 30 30 29 30 29 29 30 29 30 29 30 355 -1614 */ { 00, 02, 09, 0b0110101010100000 }, /* 29 30 30 29 30 29 30 29 30 29 30 29 354 -1615 */ { 08, 01, 29, 0b1010110101010000 }, /* 30 29 30 29 30 30 29 30 29 30 29 30 29 384 -1616 */ { 00, 02, 17, 0b1001101101010000 }, /* 30 29 29 30 30 29 30 30 29 30 29 30 355 -1617 */ { 00, 02, 06, 0b0100101101100000 }, /* 29 30 29 29 30 29 30 30 29 30 30 29 354 -1618 */ { 04, 01, 26, 0b1010010101110000 }, /* 30 29 30 29 29 30 29 30 29 30 30 30 29 384 -1619 */ { 00, 02, 14, 0b1010010011110000 }, /* 30 29 30 29 29 30 29 29 30 30 30 30 355 -1620 */ { 00, 02, 04, 0b0101001001100000 }, /* 29 30 29 30 29 29 30 29 29 30 30 29 353 -1621 */ { 02, 01, 22, 0b1110100100110000 }, /* 30 30 30 29 30 29 29 30 29 29 30 30 29 384 -1622 */ { 00, 02, 10, 0b1101010101010000 }, /* 30 30 29 30 29 30 29 30 29 30 29 30 355 -1623 */ { 10, 01, 31, 0b0101101010101000 }, /* 29 30 29 30 30 29 30 29 30 29 30 29 30 384 -1624 */ { 00, 02, 19, 0b0101011010100000 }, /* 29 30 29 30 29 30 30 29 30 29 30 29 354 -1625 */ { 00, 02, 07, 0b1001011011010000 }, /* 30 29 29 30 29 30 30 29 30 30 29 30 355 -1626 */ { 06, 01, 28, 0b0100101011101000 }, /* 29 30 29 29 30 29 30 29 30 30 30 29 30 384 -1627 */ { 00, 02, 16, 0b0100100111100000 }, /* 29 30 29 29 30 29 29 30 30 30 30 29 354 -1628 */ { 00, 02, 05, 0b1010010011010000 }, /* 30 29 30 29 29 30 29 29 30 30 29 30 354 -1629 */ { 04, 01, 24, 0b1101001001101000 }, /* 30 30 29 30 29 29 30 29 29 30 30 29 30 384 -1630 */ { 00, 02, 12, 0b1101001001010000 }, /* 30 30 29 30 29 29 30 29 29 30 29 30 354 -1631 */ { 11, 02, 01, 0b1101010100101000 }, /* 30 30 29 30 29 30 29 30 29 29 30 29 30 384 -1632 */ { 00, 02, 20, 0b1011010101000000 }, /* 30 29 30 30 29 30 29 30 29 30 29 29 354 -1633 */ { 00, 02, 08, 0b1011010110100000 }, /* 30 29 30 30 29 30 29 30 30 29 30 29 355 -1634 */ { 08, 01, 29, 0b1001010111010000 }, /* 30 29 29 30 29 30 29 30 30 30 29 30 29 384 -1635 */ { 00, 02, 17, 0b1001010110110000 }, /* 30 29 29 30 29 30 29 30 30 29 30 30 355 -1636 */ { 00, 02, 07, 0b0100100110110000 }, /* 29 30 29 29 30 29 29 30 30 29 30 30 354 -1637 */ { 04, 01, 26, 0b1010010010111000 }, /* 30 29 30 29 29 30 29 29 30 29 30 30 30 384 -1638 */ { 00, 02, 14, 0b1010010010110000 }, /* 30 29 30 29 29 30 29 29 30 29 30 30 354 -1639 */ { 00, 02, 03, 0b1010101001010000 }, /* 30 29 30 29 30 29 30 29 29 30 29 30 354 -1640 */ { 01, 01, 23, 0b1011010100101000 }, /* 30 29 30 30 29 30 29 30 29 29 30 29 30 384 -1641 */ { 00, 02, 10, 0b0110110101000000 }, /* 29 30 30 29 30 30 29 30 29 30 29 29 354 -1642 */ { 11, 01, 30, 0b1010110110101000 }, /* 30 29 30 29 30 30 29 30 30 29 30 29 30 385 -1643 */ { 00, 02, 19, 0b0010101101100000 }, /* 29 29 30 29 30 29 30 30 29 30 30 29 354 -1644 */ { 00, 02, 08, 0b1001001101110000 }, /* 30 29 29 30 29 29 30 30 29 30 30 30 355 -1645 */ { 06, 01, 28, 0b0100100101111000 }, /* 29 30 29 29 30 29 29 30 29 30 30 30 30 384 -1646 */ { 00, 02, 16, 0b0100100101110000 }, /* 29 30 29 29 30 29 29 30 29 30 30 30 354 -1647 */ { 00, 02, 05, 0b0110010010110000 }, /* 29 30 30 29 29 30 29 29 30 29 30 30 354 -1648 */ { 03, 01, 25, 0b0110101001010000 }, /* 29 30 30 29 30 29 30 29 29 30 29 30 29 383 -1649 */ { 00, 02, 11, 0b1101101001010000 }, /* 30 30 29 30 30 29 30 29 29 30 29 30 355 -1650 */ { 11, 02, 01, 0b0110101101001000 }, /* 29 30 30 29 30 29 30 30 29 30 29 29 30 384 -1651 */ { 00, 02, 20, 0b0101011011010000 }, /* 29 30 29 30 29 30 30 29 30 30 29 30 355 -1652 */ { 00, 02, 10, 0b0010101110100000 }, /* 29 29 30 29 30 29 30 30 30 29 30 29 354 -1653 */ { 07, 01, 29, 0b1001001011110000 }, /* 30 29 29 30 29 29 30 29 30 30 30 30 29 384 -1654 */ { 00, 02, 17, 0b1001001011100000 }, /* 30 29 29 30 29 29 30 29 30 30 30 29 354 -1655 */ { 00, 02, 06, 0b1100100101100000 }, /* 30 30 29 29 30 29 29 30 29 30 30 29 354 -1656 */ { 05, 01, 26, 0b1101010010101000 }, /* 30 30 29 30 29 30 29 29 30 29 30 29 30 384 -1657 */ { 00, 02, 13, 0b1101010010100000 }, /* 30 30 29 30 29 30 29 29 30 29 30 29 354 -1658 */ { 00, 02, 02, 0b1101101001010000 }, /* 30 30 29 30 30 29 30 29 29 30 29 30 355 -1659 */ { 03, 01, 23, 0b0101101010101000 }, /* 29 30 29 30 30 29 30 29 30 29 30 29 30 384 -1660 */ { 00, 02, 11, 0b0101011010100000 }, /* 29 30 29 30 29 30 30 29 30 29 30 29 354 -1661 */ { 07, 01, 30, 0b1010011011010000 }, /* 30 29 30 29 29 30 30 29 30 30 29 30 29 384 -1662 */ { 00, 02, 18, 0b1010010111010000 }, /* 30 29 30 29 29 30 29 30 30 30 29 30 355 -1663 */ { 00, 02, 08, 0b1001001011010000 }, /* 30 29 29 30 29 29 30 29 30 30 29 30 354 -1664 */ { 06, 01, 28, 0b1010100101011000 }, /* 30 29 30 29 30 29 29 30 29 30 29 30 30 384 -1665 */ { 00, 02, 15, 0b1010100101010000 }, /* 30 29 30 29 30 29 29 30 29 30 29 30 354 -1666 */ { 00, 02, 04, 0b1011010010100000 }, /* 30 29 30 30 29 30 29 29 30 29 30 29 354 -1667 */ { 04, 01, 24, 0b1011010101010000 }, /* 30 29 30 30 29 30 29 30 29 30 29 30 29 384 -1668 */ { 00, 02, 12, 0b1010110101010000 }, /* 30 29 30 29 30 30 29 30 29 30 29 30 355 -1669 */ { 00, 02, 01, 0b0101010110100000 }, /* 29 30 29 30 29 30 29 30 30 29 30 29 354 -1670 */ { 02, 01, 21, 0b1010010111010000 }, /* 30 29 30 29 29 30 29 30 30 30 29 30 29 384 -1671 */ { 00, 02, 09, 0b1010010110110000 }, /* 30 29 30 29 29 30 29 30 30 29 30 30 355 -1672 */ { 07, 01, 30, 0b0101001010111000 }, /* 29 30 29 30 29 29 30 29 30 29 30 30 30 384 -1673 */ { 00, 02, 17, 0b0101001010110000 }, /* 29 30 29 30 29 29 30 29 30 29 30 30 354 -1674 */ { 00, 02, 06, 0b0110100100110000 }, /* 29 30 30 29 30 29 29 30 29 29 30 30 354 -1675 */ { 05, 01, 26, 0b0111010010101000 }, /* 29 30 30 30 29 30 29 29 30 29 30 29 30 384 -1676 */ { 00, 02, 14, 0b0110101010100000 }, /* 29 30 30 29 30 29 30 29 30 29 30 29 354 -1677 */ { 00, 02, 02, 0b1010110110010000 }, /* 30 29 30 29 30 30 29 30 30 29 29 30 355 -1678 */ { 03, 01, 23, 0b0100110110101000 }, /* 29 30 29 29 30 30 29 30 30 29 30 29 30 384 -1679 */ { 00, 02, 11, 0b0100101101100000 }, /* 29 30 29 29 30 29 30 30 29 30 30 29 354 -1680 */ { 08, 01, 31, 0b1010010101110000 }, /* 30 29 30 29 29 30 29 30 29 30 30 30 29 384 -1681 */ { 00, 02, 18, 0b1010010011100000 }, /* 30 29 30 29 29 30 29 29 30 30 30 29 354 -1682 */ { 00, 02, 07, 0b1101001001100000 }, /* 30 30 29 30 29 29 30 29 29 30 30 29 354 -1683 */ { 06, 01, 27, 0b1110100100110000 }, /* 30 30 30 29 30 29 29 30 29 29 30 30 29 384 -1684 */ { 00, 02, 15, 0b1101010100100000 }, /* 30 30 29 30 29 30 29 30 29 29 30 29 354 -1685 */ { 00, 02, 03, 0b1101101010100000 }, /* 30 30 29 30 30 29 30 29 30 29 30 29 355 -1686 */ { 04, 01, 24, 0b0110101101010000 }, /* 29 30 30 29 30 29 30 30 29 30 29 30 29 384 -1687 */ { 00, 02, 12, 0b0101011011010000 }, /* 29 30 29 30 29 30 30 29 30 30 29 30 355 -1688 */ { 00, 02, 02, 0b0100101011100000 }, /* 29 30 29 29 30 29 30 29 30 30 30 29 354 -1689 */ { 03, 01, 21, 0b1010010011101000 }, /* 30 29 30 29 29 30 29 29 30 30 30 29 30 384 -1690 */ { 00, 02, 09, 0b1010010011010000 }, /* 30 29 30 29 29 30 29 29 30 30 29 30 354 -1691 */ { 07, 01, 29, 0b1101001001011000 }, /* 30 30 29 30 29 29 30 29 29 30 29 30 30 384 -1692 */ { 00, 02, 17, 0b1011001001010000 }, /* 30 29 30 30 29 29 30 29 29 30 29 30 354 -1693 */ { 00, 02, 05, 0b1101010100100000 }, /* 30 30 29 30 29 30 29 30 29 29 30 29 354 -1694 */ { 05, 01, 25, 0b1101011010100000 }, /* 30 30 29 30 29 30 30 29 30 29 30 29 29 384 -1695 */ { 00, 02, 13, 0b1011010110100000 }, /* 30 29 30 30 29 30 29 30 30 29 30 29 355 -1696 */ { 00, 02, 03, 0b0101010111010000 }, /* 29 30 29 30 29 30 29 30 30 30 29 30 355 -1697 */ { 03, 01, 23, 0b0100101011011000 }, /* 29 30 29 29 30 29 30 29 30 30 29 30 30 384 -1698 */ { 00, 02, 11, 0b0100100111010000 }, /* 29 30 29 29 30 29 29 30 30 30 29 30 354 -1699 */ { 07, 01, 31, 0b1010010010111000 }, /* 30 29 30 29 29 30 29 29 30 29 30 30 30 384 -1700 */ { 00, 02, 19, 0b1010010010110000 }, /* 30 29 30 29 29 30 29 29 30 29 30 30 354 -1701 */ { 00, 02, 08, 0b1010101001010000 }, /* 30 29 30 29 30 29 30 29 29 30 29 30 354 -1702 */ { 06, 01, 28, 0b1011010100101000 }, /* 30 29 30 30 29 30 29 30 29 29 30 29 30 384 -1703 */ { 00, 02, 16, 0b0110110100100000 }, /* 29 30 30 29 30 30 29 30 29 29 30 29 354 -1704 */ { 00, 02, 05, 0b1010110110100000 }, /* 30 29 30 29 30 30 29 30 30 29 30 29 355 -1705 */ { 04, 01, 25, 0b0101010110110000 }, /* 29 30 29 30 29 30 29 30 30 29 30 30 29 384 -1706 */ { 00, 02, 13, 0b1001001101110000 }, /* 30 29 29 30 29 29 30 30 29 30 30 30 355 -1707 */ { 00, 02, 03, 0b0100100101110000 }, /* 29 30 29 29 30 29 29 30 29 30 30 30 354 -1708 */ { 03, 01, 23, 0b0110010010111000 }, /* 29 30 30 29 29 30 29 29 30 29 30 30 30 384 -1709 */ { 00, 02, 10, 0b1010010011010000 }, /* 30 29 30 29 29 30 29 29 30 30 29 30 354 -1710 */ { 07, 01, 30, 0b0110101001010000 }, /* 29 30 30 29 30 29 30 29 29 30 29 30 29 383 -1711 */ { 00, 02, 17, 0b1101101001010000 }, /* 30 30 29 30 30 29 30 29 29 30 29 30 355 -1712 */ { 00, 02, 07, 0b0101101010100000 }, /* 29 30 29 30 30 29 30 29 30 29 30 29 354 -1713 */ { 05, 01, 26, 0b1010101101100000 }, /* 30 29 30 29 30 29 30 30 29 30 30 29 29 384 -1714 */ { 00, 02, 14, 0b1010101011100000 }, /* 30 29 30 29 30 29 30 29 30 30 30 29 355 -1715 */ { 00, 02, 04, 0b1001001011100000 }, /* 30 29 29 30 29 29 30 29 30 30 30 29 354 -1716 */ { 03, 01, 24, 0b1100100101110000 }, /* 30 30 29 29 30 29 29 30 29 30 30 30 29 384 -1717 */ { 00, 02, 11, 0b1100100101100000 }, /* 30 30 29 29 30 29 29 30 29 30 30 29 354 -1718 */ { 08, 01, 31, 0b1101010010101000 }, /* 30 30 29 30 29 30 29 29 30 29 30 29 30 384 -1719 */ { 00, 02, 19, 0b1101010010100000 }, /* 30 30 29 30 29 30 29 29 30 29 30 29 354 -1720 */ { 00, 02, 08, 0b1101010101010000 }, /* 30 30 29 30 29 30 29 30 29 30 29 30 355 -1721 */ { 06, 01, 28, 0b0101101010101000 }, /* 29 30 29 30 30 29 30 29 30 29 30 29 30 384 -1722 */ { 00, 02, 16, 0b0101011010100000 }, /* 29 30 29 30 29 30 30 29 30 29 30 29 354 -1723 */ { 00, 02, 05, 0b1010011011010000 }, /* 30 29 30 29 29 30 30 29 30 30 29 30 355 -1724 */ { 04, 01, 26, 0b0101001011101000 }, /* 29 30 29 30 29 29 30 29 30 30 30 29 30 384 -1725 */ { 00, 02, 13, 0b0101001011010000 }, /* 29 30 29 30 29 29 30 29 30 30 29 30 354 -1726 */ { 00, 02, 02, 0b1010100101010000 }, /* 30 29 30 29 30 29 29 30 29 30 29 30 354 -1727 */ { 03, 01, 22, 0b1110010010101000 }, /* 30 30 30 29 29 30 29 29 30 29 30 29 30 384 -1728 */ { 00, 02, 10, 0b1011010010100000 }, /* 30 29 30 30 29 30 29 29 30 29 30 29 354 -1729 */ { 07, 01, 29, 0b1011010101010000 }, /* 30 29 30 30 29 30 29 30 29 30 29 30 29 384 -1730 */ { 00, 02, 17, 0b1001110101010000 }, /* 30 29 29 30 30 30 29 30 29 30 29 30 355 -1731 */ { 00, 02, 07, 0b0101010110100000 }, /* 29 30 29 30 29 30 29 30 30 29 30 29 354 -1732 */ { 05, 01, 27, 0b1010010111010000 }, /* 30 29 30 29 29 30 29 30 30 30 29 30 29 384 -1733 */ { 00, 02, 14, 0b1010010110110000 }, /* 30 29 30 29 29 30 29 30 30 29 30 30 355 -1734 */ { 00, 02, 04, 0b0101001010110000 }, /* 29 30 29 30 29 29 30 29 30 29 30 30 354 -1735 */ { 04, 01, 24, 0b1010100010111000 }, /* 30 29 30 29 30 29 29 29 30 29 30 30 30 384 -1736 */ { 00, 02, 12, 0b0110100100110000 }, /* 29 30 30 29 30 29 29 30 29 29 30 30 354 -1737 */ { 09, 01, 31, 0b0110101010011000 }, /* 29 30 30 29 30 29 30 29 30 29 29 30 30 384 -1738 */ { 00, 02, 19, 0b0110101010100000 }, /* 29 30 30 29 30 29 30 29 30 29 30 29 354 -1739 */ { 00, 02, 08, 0b1010101101010000 }, /* 30 29 30 29 30 29 30 30 29 30 29 30 355 -1740 */ { 06, 01, 29, 0b0100110110101000 }, /* 29 30 29 29 30 30 29 30 30 29 30 29 30 384 -1741 */ { 00, 02, 16, 0b0100101101100000 }, /* 29 30 29 29 30 29 30 30 29 30 30 29 354 -1742 */ { 00, 02, 05, 0b1010010101110000 }, /* 30 29 30 29 29 30 29 30 29 30 30 30 355 -1743 */ { 04, 01, 26, 0b0101000101110000 }, /* 29 30 29 30 29 29 29 30 29 30 30 30 29 383 -1744 */ { 00, 02, 13, 0b1101000101100000 }, /* 30 30 29 30 29 29 29 30 29 30 30 29 354 -1745 */ { 00, 02, 01, 0b1110100100110000 }, /* 30 30 30 29 30 29 29 30 29 29 30 30 355 -1746 */ { 03, 01, 22, 0b0110101010010000 }, /* 29 30 30 29 30 29 30 29 30 29 29 30 29 383 -1747 */ { 00, 02, 09, 0b1101101010100000 }, /* 30 30 29 30 30 29 30 29 30 29 30 29 355 -1748 */ { 07, 01, 30, 0b0101101101010000 }, /* 29 30 29 30 30 29 30 30 29 30 29 30 29 384 -1749 */ { 00, 02, 17, 0b0101011011010000 }, /* 29 30 29 30 29 30 30 29 30 30 29 30 355 -1750 */ { 00, 02, 07, 0b0100101011100000 }, /* 29 30 29 29 30 29 30 29 30 30 30 29 354 -1751 */ { 05, 01, 27, 0b1010010011011000 }, /* 30 29 30 29 29 30 29 29 30 30 29 30 30 384 -1752 */ { 00, 02, 15, 0b1010001011010000 }, /* 30 29 30 29 29 29 30 29 30 30 29 30 354 -1753 */ { 00, 02, 03, 0b1101000101010000 }, /* 30 30 29 30 29 29 29 30 29 30 29 30 354 -1754 */ { 04, 01, 23, 0b1101010100101000 }, /* 30 30 29 30 29 30 29 30 29 29 30 29 30 384 -1755 */ { 00, 02, 11, 0b1011010100100000 }, /* 30 29 30 30 29 30 29 30 29 29 30 29 354 -1756 */ { 09, 01, 31, 0b1101011010010000 }, /* 30 30 29 30 29 30 30 29 30 29 29 30 29 384 -1757 */ { 00, 02, 18, 0b1010110110100000 }, /* 30 29 30 29 30 30 29 30 30 29 30 29 355 -1758 */ { 00, 02, 08, 0b0101010111010000 }, /* 29 30 29 30 29 30 29 30 30 30 29 30 355 -1759 */ { 06, 01, 29, 0b0010101011011000 }, /* 29 29 30 29 30 29 30 29 30 30 29 30 30 384 -1760 */ { 00, 02, 17, 0b0100010110110000 }, /* 29 30 29 29 29 30 29 30 30 29 30 30 354 -1761 */ { 00, 02, 05, 0b1010001010110000 }, /* 30 29 30 29 29 29 30 29 30 29 30 30 354 -1762 */ { 05, 01, 25, 0b1011000101011000 }, /* 30 29 30 30 29 29 29 30 29 30 29 30 30 384 -1763 */ { 00, 02, 13, 0b1010100101010000 }, /* 30 29 30 29 30 29 29 30 29 30 29 30 354 -1764 */ { 00, 02, 02, 0b1011010100100000 }, /* 30 29 30 30 29 30 29 30 29 29 30 29 354 -1765 */ { 02, 01, 21, 0b1011010110010000 }, /* 30 29 30 30 29 30 29 30 30 29 29 30 29 384 -1766 */ { 00, 02, 09, 0b1010110101100000 }, /* 30 29 30 29 30 30 29 30 29 30 30 29 355 -1767 */ { 07, 01, 30, 0b0101010110110000 }, /* 29 30 29 30 29 30 29 30 30 29 30 30 29 384 -1768 */ { 00, 02, 18, 0b0101001101110000 }, /* 29 30 29 30 29 29 30 30 29 30 30 30 355 -1769 */ { 00, 02, 07, 0b0100010101110000 }, /* 29 30 29 29 29 30 29 30 29 30 30 30 354 -1770 */ { 05, 01, 27, 0b0110001010111000 }, /* 29 30 30 29 29 29 30 29 30 29 30 30 30 384 -1771 */ { 00, 02, 15, 0b0101001010110000 }, /* 29 30 29 30 29 29 30 29 30 29 30 30 354 -1772 */ { 00, 02, 04, 0b0110100101010000 }, /* 29 30 30 29 30 29 29 30 29 30 29 30 354 -1773 */ { 03, 01, 23, 0b0110110010101000 }, /* 29 30 30 29 30 30 29 29 30 29 30 29 30 384 -1774 */ { 00, 02, 11, 0b0101101010100000 }, /* 29 30 29 30 30 29 30 29 30 29 30 29 354 -1775 */ { 10, 01, 31, 0b1010101101010000 }, /* 30 29 30 29 30 29 30 30 29 30 29 30 29 384 -1776 */ { 00, 02, 19, 0b1010011011010000 }, /* 30 29 30 29 29 30 30 29 30 30 29 30 355 -1777 */ { 00, 02, 08, 0b0100101011100000 }, /* 29 30 29 29 30 29 30 29 30 30 30 29 354 -1778 */ { 06, 01, 28, 0b1001010101110000 }, /* 30 29 29 30 29 30 29 30 29 30 30 30 29 384 -1779 */ { 00, 02, 16, 0b1010010101100000 }, /* 30 29 30 29 29 30 29 30 29 30 30 29 354 -1780 */ { 00, 02, 05, 0b1101001010100000 }, /* 30 30 29 30 29 29 30 29 30 29 30 29 354 -1781 */ { 05, 01, 24, 0b1110100101010000 }, /* 30 30 30 29 30 29 29 30 29 30 29 30 29 384 -1782 */ { 00, 02, 12, 0b1101010101010000 }, /* 30 30 29 30 29 30 29 30 29 30 29 30 355 -1783 */ { 00, 02, 02, 0b0101101010100000 }, /* 29 30 29 30 30 29 30 29 30 29 30 29 354 -1784 */ { 03, 01, 22, 0b1010101101010000 }, /* 30 29 30 29 30 29 30 30 29 30 29 30 29 384 -1785 */ { 00, 02, 09, 0b1010011011010000 }, /* 30 29 30 29 29 30 30 29 30 30 29 30 355 -1786 */ { 07, 01, 30, 0b0100101011101000 }, /* 29 30 29 29 30 29 30 29 30 30 30 29 30 384 -1787 */ { 00, 02, 18, 0b0100101010110000 }, /* 29 30 29 29 30 29 30 29 30 29 30 30 354 -1788 */ { 00, 02, 07, 0b1010100011010000 }, /* 30 29 30 29 30 29 29 29 30 30 29 30 354 -1789 */ { 05, 01, 26, 0b1101001010101000 }, /* 30 30 29 30 29 29 30 29 30 29 30 29 30 384 -1790 */ { 00, 02, 14, 0b1011001010100000 }, /* 30 29 30 30 29 29 30 29 30 29 30 29 354 -1791 */ { 00, 02, 03, 0b1011010101010000 }, /* 30 29 30 30 29 30 29 30 29 30 29 30 355 -1792 */ { 04, 01, 24, 0b0101011010101000 }, /* 29 30 29 30 29 30 30 29 30 29 30 29 30 384 -1793 */ { 00, 02, 11, 0b0100110110100000 }, /* 29 30 29 29 30 30 29 30 30 29 30 29 354 -1794 */ { 00, 01, 31, 0b1001010111010000 }, /* 30 29 29 30 29 30 29 30 30 30 29 30 355 -1795 */ { 02, 01, 21, 0b0100101010111000 }, /* 29 30 29 29 30 29 30 29 30 29 30 30 30 384 -1796 */ { 00, 02, 09, 0b0100100110110000 }, /* 29 30 29 29 30 29 29 30 30 29 30 30 354 -1797 */ { 06, 01, 28, 0b1010100010111000 }, /* 30 29 30 29 30 29 29 29 30 29 30 30 30 384 -1798 */ { 00, 02, 16, 0b0110010010110000 }, /* 29 30 30 29 29 30 29 29 30 29 30 30 354 -1799 */ { 00, 02, 05, 0b0110101010010000 }, /* 29 30 30 29 30 29 30 29 30 29 29 30 354 -1800 */ { 04, 01, 25, 0b1011010101010000 }, /* 30 29 30 30 29 30 29 30 29 30 29 30 29 384 -1801 */ { 00, 02, 13, 0b0110101101010000 }, /* 29 30 30 29 30 29 30 30 29 30 29 30 355 -1802 */ { 00, 02, 03, 0b0010101110100000 }, /* 29 29 30 29 30 29 30 30 30 29 30 29 354 -1803 */ { 02, 01, 23, 0b1001010110110000 }, /* 30 29 29 30 29 30 29 30 30 29 30 30 29 384 -1804 */ { 00, 02, 11, 0b1001001101110000 }, /* 30 29 29 30 29 29 30 30 29 30 30 30 355 -1805 */ { 06, 01, 31, 0b0101000101110000 }, /* 29 30 29 30 29 29 29 30 29 30 30 30 29 383 -1806 */ { 00, 02, 18, 0b1101000101100000 }, /* 30 30 29 30 29 29 29 30 29 30 30 29 354 -1807 */ { 00, 02, 07, 0b1110010010110000 }, /* 30 30 30 29 29 30 29 29 30 29 30 30 355 -1808 */ { 05, 01, 28, 0b0110101010010000 }, /* 29 30 30 29 30 29 30 29 30 29 29 30 29 383 -1809 */ { 00, 02, 14, 0b1101101010010000 }, /* 30 30 29 30 30 29 30 29 30 29 29 30 355 -1810 */ { 00, 02, 04, 0b0101101101010000 }, /* 29 30 29 30 30 29 30 30 29 30 29 30 355 -1811 */ { 03, 01, 25, 0b0010101101101000 }, /* 29 29 30 29 30 29 30 30 29 30 30 29 30 384 -1812 */ { 00, 02, 13, 0b0010101011100000 }, /* 29 29 30 29 30 29 30 29 30 30 30 29 354 -1813 */ { 00, 02, 01, 0b1010001011100000 }, /* 30 29 30 29 29 29 30 29 30 30 30 29 354 -1814 */ { 02, 01, 21, 0b1101000101101000 }, /* 30 30 29 30 29 29 29 30 29 30 30 29 30 384 -1815 */ { 00, 02, 09, 0b1100100101010000 }, /* 30 30 29 29 30 29 29 30 29 30 29 30 354 -1816 */ { 06, 01, 29, 0b1101010010101000 }, /* 30 30 29 30 29 30 29 29 30 29 30 29 30 384 -1817 */ { 00, 02, 16, 0b1011010100100000 }, /* 30 29 30 30 29 30 29 30 29 29 30 29 354 -1818 */ { 00, 02, 05, 0b1011011010010000 }, /* 30 29 30 30 29 30 30 29 30 29 29 30 355 -1819 */ { 04, 01, 26, 0b0101011011010000 }, /* 29 30 29 30 29 30 30 29 30 30 29 30 29 384 -1820 */ { 00, 02, 14, 0b0101010111010000 }, /* 29 30 29 30 29 30 29 30 30 30 29 30 355 -1821 */ { 00, 02, 03, 0b0010010111010000 }, /* 29 29 30 29 29 30 29 30 30 30 29 30 354 -1822 */ { 03, 01, 23, 0b1010001011011000 }, /* 30 29 30 29 29 29 30 29 30 30 29 30 30 384 -1823 */ { 00, 02, 11, 0b1010001010110000 }, /* 30 29 30 29 29 29 30 29 30 29 30 30 354 -1824 */ { 07, 01, 31, 0b1010100101011000 }, /* 30 29 30 29 30 29 29 30 29 30 29 30 30 384 -1825 */ { 00, 02, 18, 0b1010100101010000 }, /* 30 29 30 29 30 29 29 30 29 30 29 30 354 -1826 */ { 00, 02, 07, 0b1011010010100000 }, /* 30 29 30 30 29 30 29 29 30 29 30 29 354 -1827 */ { 05, 01, 27, 0b1011010101010000 }, /* 30 29 30 30 29 30 29 30 29 30 29 30 29 384 -1828 */ { 00, 02, 15, 0b1010110101010000 }, /* 30 29 30 29 30 30 29 30 29 30 29 30 355 -1829 */ { 00, 02, 04, 0b0101010110110000 }, /* 29 30 29 30 29 30 29 30 30 29 30 30 355 -1830 */ { 04, 01, 25, 0b0010010110111000 }, /* 29 29 30 29 29 30 29 30 30 29 30 30 30 384 -1831 */ { 00, 02, 13, 0b0010010101110000 }, /* 29 29 30 29 29 30 29 30 29 30 30 30 354 -1832 */ { 09, 02, 02, 0b0101001010111000 }, /* 29 30 29 30 29 29 30 29 30 29 30 30 30 384 -1833 */ { 00, 02, 20, 0b0101001010110000 }, /* 29 30 29 30 29 29 30 29 30 29 30 30 354 -1834 */ { 00, 02, 09, 0b0110100101010000 }, /* 29 30 30 29 30 29 29 30 29 30 29 30 354 -1835 */ { 06, 01, 29, 0b0110110010101000 }, /* 29 30 30 29 30 30 29 29 30 29 30 29 30 384 -1836 */ { 00, 02, 17, 0b0101101010100000 }, /* 29 30 29 30 30 29 30 29 30 29 30 29 354 -1837 */ { 00, 02, 05, 0b1010101101010000 }, /* 30 29 30 29 30 29 30 30 29 30 29 30 355 -1838 */ { 04, 01, 26, 0b0101001101101000 }, /* 29 30 29 30 29 29 30 30 29 30 30 29 30 384 -1839 */ { 00, 02, 14, 0b0100101011100000 }, /* 29 30 29 29 30 29 30 29 30 30 30 29 354 -1840 */ { 00, 02, 03, 0b1010010101110000 }, /* 30 29 30 29 29 30 29 30 29 30 30 30 355 -1841 */ { 03, 01, 23, 0b0101001010110000 }, /* 29 30 29 30 29 29 30 29 30 29 30 30 29 383 -1842 */ { 00, 02, 10, 0b1101001010100000 }, /* 30 30 29 30 29 29 30 29 30 29 30 29 354 -1843 */ { 07, 01, 30, 0b1110100101010000 }, /* 30 30 30 29 30 29 29 30 29 30 29 30 29 384 -1844 */ { 00, 02, 18, 0b1101010101010000 }, /* 30 30 29 30 29 30 29 30 29 30 29 30 355 -1845 */ { 00, 02, 07, 0b0101101010100000 }, /* 29 30 29 30 30 29 30 29 30 29 30 29 354 -1846 */ { 05, 01, 27, 0b1010101011010000 }, /* 30 29 30 29 30 29 30 29 30 30 29 30 29 384 -1847 */ { 00, 02, 15, 0b1001010111010000 }, /* 30 29 29 30 29 30 29 30 30 30 29 30 355 -1848 */ { 00, 02, 05, 0b0100101011100000 }, /* 29 30 29 29 30 29 30 29 30 30 30 29 354 -1849 */ { 04, 01, 24, 0b1010010101011000 }, /* 30 29 30 29 29 30 29 30 29 30 29 30 30 384 -1850 */ { 00, 02, 12, 0b1010010011010000 }, /* 30 29 30 29 29 30 29 29 30 30 29 30 354 -1851 */ { 08, 02, 01, 0b1101001001011000 }, /* 30 30 29 30 29 29 30 29 29 30 29 30 30 384 -1852 */ { 00, 02, 20, 0b1011001010010000 }, /* 30 29 30 30 29 29 30 29 30 29 29 30 354 -1853 */ { 00, 02, 08, 0b1011010101010000 }, /* 30 29 30 30 29 30 29 30 29 30 29 30 355 -1854 */ { 07, 01, 29, 0b0101011010101000 }, /* 29 30 29 30 29 30 30 29 30 29 30 29 30 384 -1855 */ { 00, 02, 17, 0b0010110110100000 }, /* 29 29 30 29 30 30 29 30 30 29 30 29 354 -1856 */ { 00, 02, 06, 0b1001010111010000 }, /* 30 29 29 30 29 30 29 30 30 30 29 30 355 -1857 */ { 05, 01, 26, 0b0100101010111000 }, /* 29 30 29 29 30 29 30 29 30 29 30 30 30 384 -1858 */ { 00, 02, 14, 0b0100100110110000 }, /* 29 30 29 29 30 29 29 30 30 29 30 30 354 -1859 */ { 00, 02, 03, 0b1010010010110000 }, /* 30 29 30 29 29 30 29 29 30 29 30 30 354 -1860 */ { 03, 01, 23, 0b1011001001011000 }, /* 30 29 30 30 29 29 30 29 29 30 29 30 30 384 -1861 */ { 00, 02, 10, 0b0110101010010000 }, /* 29 30 30 29 30 29 30 29 30 29 29 30 354 -1862 */ { 08, 01, 30, 0b1010110101001000 }, /* 30 29 30 29 30 30 29 30 29 30 29 29 30 384 -1863 */ { 00, 02, 18, 0b0110101101010000 }, /* 29 30 30 29 30 29 30 30 29 30 29 30 355 -1864 */ { 00, 02, 08, 0b0010101101100000 }, /* 29 29 30 29 30 29 30 30 29 30 30 29 354 -1865 */ { 05, 01, 27, 0b1001010110110000 }, /* 30 29 29 30 29 30 29 30 30 29 30 30 29 384 -1866 */ { 00, 02, 15, 0b1001001101110000 }, /* 30 29 29 30 29 29 30 30 29 30 30 30 355 -1867 */ { 00, 02, 05, 0b0100100101110000 }, /* 29 30 29 29 30 29 29 30 29 30 30 30 354 -1868 */ { 04, 01, 25, 0b0110010010110000 }, /* 29 30 30 29 29 30 29 29 30 29 30 30 29 383 -1869 */ { 00, 02, 11, 0b1110010010100000 }, /* 30 30 30 29 29 30 29 29 30 29 30 29 354 -1870 */ { 10, 01, 31, 0b1110101001010000 }, /* 30 30 30 29 30 29 30 29 29 30 29 30 29 384 -1871 */ { 00, 02, 19, 0b1101101010010000 }, /* 30 30 29 30 30 29 30 29 30 29 29 30 355 -1872 */ { 00, 02, 09, 0b0101101011010000 }, /* 29 30 29 30 30 29 30 29 30 30 29 30 355 -1873 */ { 06, 01, 29, 0b0010101101101000 }, /* 29 29 30 29 30 29 30 30 29 30 30 29 30 384 -1874 */ { 00, 02, 17, 0b0010101011100000 }, /* 29 29 30 29 30 29 30 29 30 30 30 29 354 -1875 */ { 00, 02, 06, 0b1001001011100000 }, /* 30 29 29 30 29 29 30 29 30 30 30 29 354 -1876 */ { 05, 01, 26, 0b1100100101101000 }, /* 30 30 29 29 30 29 29 30 29 30 30 29 30 384 -1877 */ { 00, 02, 13, 0b1100100101010000 }, /* 30 30 29 29 30 29 29 30 29 30 29 30 354 -1878 */ { 00, 02, 02, 0b1101010010100000 }, /* 30 30 29 30 29 30 29 29 30 29 30 29 354 -1879 */ { 03, 01, 22, 0b1101101001010000 }, /* 30 30 29 30 30 29 30 29 29 30 29 30 29 384 -1880 */ { 00, 02, 10, 0b1011011010010000 }, /* 30 29 30 30 29 30 30 29 30 29 29 30 355 -1881 */ { 07, 01, 30, 0b0101011011010000 }, /* 29 30 29 30 29 30 30 29 30 30 29 30 29 384 -1882 */ { 00, 02, 18, 0b0101010110110000 }, /* 29 30 29 30 29 30 29 30 30 29 30 30 355 -1883 */ { 00, 02, 08, 0b0010010111010000 }, /* 29 29 30 29 29 30 29 30 30 30 29 30 354 -1884 */ { 05, 01, 28, 0b1001001011011000 }, /* 30 29 29 30 29 29 30 29 30 30 29 30 30 384 -1885 */ { 00, 02, 15, 0b1001001010110000 }, /* 30 29 29 30 29 29 30 29 30 29 30 30 354 -1886 */ { 00, 02, 04, 0b1010100101010000 }, /* 30 29 30 29 30 29 29 30 29 30 29 30 354 -1887 */ { 04, 01, 24, 0b1101010010101000 }, /* 30 30 29 30 29 30 29 29 30 29 30 29 30 384 -1888 */ { 00, 02, 12, 0b1011010010100000 }, /* 30 29 30 30 29 30 29 29 30 29 30 29 354 -1889 */ { 00, 01, 31, 0b1011010101010000 }, /* 30 29 30 30 29 30 29 30 29 30 29 30 355 -1890 */ { 02, 01, 21, 0b0101011010101000 }, /* 29 30 29 30 29 30 30 29 30 29 30 29 30 384 -1891 */ { 00, 02, 09, 0b0101010110110000 }, /* 29 30 29 30 29 30 29 30 30 29 30 30 355 -1892 */ { 06, 01, 30, 0b0010010110111000 }, /* 29 29 30 29 29 30 29 30 30 29 30 30 30 384 -1893 */ { 00, 02, 17, 0b0010010101110000 }, /* 29 29 30 29 29 30 29 30 29 30 30 30 354 -1894 */ { 00, 02, 06, 0b0101001010110000 }, /* 29 30 29 30 29 29 30 29 30 29 30 30 354 -1895 */ { 05, 01, 26, 0b1010100101010000 }, /* 30 29 30 29 30 29 29 30 29 30 29 30 29 383 -1896 */ { 00, 02, 13, 0b1110100101010000 }, /* 30 30 30 29 30 29 29 30 29 30 29 30 355 -1897 */ { 00, 02, 02, 0b0110101010100000 }, /* 29 30 30 29 30 29 30 29 30 29 30 29 354 -1898 */ { 03, 01, 22, 0b1010110101010000 }, /* 30 29 30 29 30 30 29 30 29 30 29 30 29 384 -1899 */ { 00, 02, 10, 0b1010101101010000 }, /* 30 29 30 29 30 29 30 30 29 30 29 30 355 -1900 */ { 08, 01, 31, 0b0100101101101000 }, /* 29 30 29 29 30 29 30 30 29 30 30 29 30 384 -1901 */ { 00, 02, 19, 0b0100101011100000 }, /* 29 30 29 29 30 29 30 29 30 30 30 29 354 -1902 */ { 00, 02, 08, 0b1010010101110000 }, /* 30 29 30 29 29 30 29 30 29 30 30 30 355 -1903 */ { 05, 01, 29, 0b0101001001101000 }, /* 29 30 29 30 29 29 30 29 29 30 30 29 30 383 -1904 */ { 00, 02, 16, 0b1101001001100000 }, /* 30 30 29 30 29 29 30 29 29 30 30 29 354 -1905 */ { 00, 02, 04, 0b1101100101010000 }, /* 30 30 29 30 30 29 29 30 29 30 29 30 355 -1906 */ { 04, 01, 25, 0b0110101010101000 }, /* 29 30 30 29 30 29 30 29 30 29 30 29 30 384 -1907 */ { 00, 02, 13, 0b0101011010100000 }, /* 29 30 29 30 29 30 30 29 30 29 30 29 354 -1908 */ { 00, 02, 02, 0b1001101011010000 }, /* 30 29 29 30 30 29 30 29 30 30 29 30 355 -1909 */ { 02, 01, 22, 0b0100101011101000 }, /* 29 30 29 29 30 29 30 29 30 30 30 29 30 384 -1910 */ { 00, 02, 10, 0b0100101011100000 }, /* 29 30 29 29 30 29 30 29 30 30 30 29 354 -1911 */ { 06, 01, 30, 0b1010010011011000 }, /* 30 29 30 29 29 30 29 29 30 30 29 30 30 384 -1912 */ { 00, 02, 18, 0b1010010011010000 }, /* 30 29 30 29 29 30 29 29 30 30 29 30 354 -1913 */ { 00, 02, 06, 0b1101001001010000 }, /* 30 30 29 30 29 29 30 29 29 30 29 30 354 -1914 */ { 05, 01, 26, 0b1101100101001000 }, /* 30 30 29 30 30 29 29 30 29 30 29 29 30 384 -1915 */ { 00, 02, 14, 0b1011010101010000 }, /* 30 29 30 30 29 30 29 30 29 30 29 30 355 -1916 */ { 00, 02, 04, 0b0101011010100000 }, /* 29 30 29 30 29 30 30 29 30 29 30 29 354 -1917 */ { 02, 01, 23, 0b1001011011010000 }, /* 30 29 29 30 29 30 30 29 30 30 29 30 29 384 -1918 */ { 00, 02, 11, 0b1001010111010000 }, /* 30 29 29 30 29 30 29 30 30 30 29 30 355 -1919 */ { 07, 02, 01, 0b0100101011011000 }, /* 29 30 29 29 30 29 30 29 30 30 29 30 30 384 -1920 */ { 00, 02, 20, 0b0100100110110000 }, /* 29 30 29 29 30 29 29 30 30 29 30 30 354 -1921 */ { 00, 02, 08, 0b1010010010110000 }, /* 30 29 30 29 29 30 29 29 30 29 30 30 354 -1922 */ { 05, 01, 28, 0b1011001001011000 }, /* 30 29 30 30 29 29 30 29 29 30 29 30 30 384 -1923 */ { 00, 02, 16, 0b0110101010010000 }, /* 29 30 30 29 30 29 30 29 30 29 29 30 354 -1924 */ { 00, 02, 05, 0b1010110101000000 }, /* 30 29 30 29 30 30 29 30 29 30 29 29 354 -1925 */ { 04, 01, 24, 0b1011010110101000 }, /* 30 29 30 30 29 30 29 30 30 29 30 29 30 385 -1926 */ { 00, 02, 13, 0b0010101101100000 }, /* 29 29 30 29 30 29 30 30 29 30 30 29 354 -1927 */ { 00, 02, 02, 0b1001010110110000 }, /* 30 29 29 30 29 30 29 30 30 29 30 30 355 -1928 */ { 02, 01, 23, 0b0100100110111000 }, /* 29 30 29 29 30 29 29 30 30 29 30 30 30 384 -1929 */ { 00, 02, 10, 0b0100100101110000 }, /* 29 30 29 29 30 29 29 30 29 30 30 30 354 -1930 */ { 06, 01, 30, 0b0110010010110000 }, /* 29 30 30 29 29 30 29 29 30 29 30 30 29 383 -1931 */ { 00, 02, 17, 0b1110010010100000 }, /* 30 30 30 29 29 30 29 29 30 29 30 29 354 -1932 */ { 00, 02, 06, 0b1110101001010000 }, /* 30 30 30 29 30 29 30 29 29 30 29 30 355 -1933 */ { 05, 01, 26, 0b0110110101001000 }, /* 29 30 30 29 30 30 29 30 29 30 29 29 30 384 -1934 */ { 00, 02, 14, 0b0101101101010000 }, /* 29 30 29 30 30 29 30 30 29 30 29 30 355 -1935 */ { 00, 02, 04, 0b0010101101100000 }, /* 29 29 30 29 30 29 30 30 29 30 30 29 354 -1936 */ { 03, 01, 24, 0b1001010101110000 }, /* 30 29 29 30 29 30 29 30 29 30 30 30 29 384 -1937 */ { 00, 02, 11, 0b1001001011100000 }, /* 30 29 29 30 29 29 30 29 30 30 30 29 354 -1938 */ { 07, 01, 31, 0b1100100101101000 }, /* 30 30 29 29 30 29 29 30 29 30 30 29 30 384 -1939 */ { 00, 02, 19, 0b1100100101010000 }, /* 30 30 29 29 30 29 29 30 29 30 29 30 354 -1940 */ { 00, 02, 08, 0b1101010010100000 }, /* 30 30 29 30 29 30 29 29 30 29 30 29 354 -1941 */ { 06, 01, 27, 0b1101101001010000 }, /* 30 30 29 30 30 29 30 29 29 30 29 30 29 384 -1942 */ { 00, 02, 15, 0b1011011010010000 }, /* 30 29 30 30 29 30 30 29 30 29 29 30 355 -1943 */ { 00, 02, 05, 0b0101011011010000 }, /* 29 30 29 30 29 30 30 29 30 30 29 30 355 -1944 */ { 04, 01, 26, 0b0010101011011000 }, /* 29 29 30 29 30 29 30 29 30 30 29 30 30 384 -1945 */ { 00, 02, 13, 0b0010010111010000 }, /* 29 29 30 29 29 30 29 30 30 30 29 30 354 -1946 */ { 00, 02, 02, 0b1001001011010000 }, /* 30 29 29 30 29 29 30 29 30 30 29 30 354 -1947 */ { 02, 01, 22, 0b1100100101011000 }, /* 30 30 29 29 30 29 29 30 29 30 29 30 30 384 -1948 */ { 00, 02, 10, 0b1010100101010000 }, /* 30 29 30 29 30 29 29 30 29 30 29 30 354 -1949 */ { 07, 01, 29, 0b1101010010101000 }, /* 30 30 29 30 29 30 29 29 30 29 30 29 30 384 -1950 */ { 00, 02, 17, 0b1011010010100000 }, /* 30 29 30 30 29 30 29 29 30 29 30 29 354 -1951 */ { 00, 02, 06, 0b1011010101010000 }, /* 30 29 30 30 29 30 29 30 29 30 29 30 355 -1952 */ { 05, 01, 27, 0b0101011010101000 }, /* 29 30 29 30 29 30 30 29 30 29 30 29 30 384 -1953 */ { 00, 02, 14, 0b0100110110110000 }, /* 29 30 29 29 30 30 29 30 30 29 30 30 355 -1954 */ { 00, 02, 04, 0b0010010110110000 }, /* 29 29 30 29 29 30 29 30 30 29 30 30 354 -1955 */ { 03, 01, 24, 0b1001001010111000 }, /* 30 29 29 30 29 29 30 29 30 29 30 30 30 384 -1956 */ { 00, 02, 12, 0b0101001010110000 }, /* 29 30 29 30 29 29 30 29 30 29 30 30 354 -1957 */ { 08, 01, 31, 0b1010100101011000 }, /* 30 29 30 29 30 29 29 30 29 30 29 30 30 384 -1958 */ { 00, 02, 19, 0b0110100101010000 }, /* 29 30 30 29 30 29 29 30 29 30 29 30 354 -1959 */ { 00, 02, 08, 0b0110101010100000 }, /* 29 30 30 29 30 29 30 29 30 29 30 29 354 -1960 */ { 06, 01, 28, 0b1010110101010000 }, /* 30 29 30 29 30 30 29 30 29 30 29 30 29 384 -1961 */ { 00, 02, 15, 0b1010101101010000 }, /* 30 29 30 29 30 29 30 30 29 30 29 30 355 -1962 */ { 00, 02, 05, 0b0100101101100000 }, /* 29 30 29 29 30 29 30 30 29 30 30 29 354 -1963 */ { 04, 01, 25, 0b1010010101110000 }, /* 30 29 30 29 29 30 29 30 29 30 30 30 29 384 -1964 */ { 00, 02, 13, 0b1010010101110000 }, /* 30 29 30 29 29 30 29 30 29 30 30 30 355 -1965 */ { 00, 02, 02, 0b0101001001110000 }, /* 29 30 29 30 29 29 30 29 29 30 30 30 354 -1966 */ { 03, 01, 22, 0b0110100100110000 }, /* 29 30 30 29 30 29 29 30 29 29 30 30 29 383 -1967 */ { 00, 02, 09, 0b1101100101010000 }, /* 30 30 29 30 30 29 29 30 29 30 29 30 355 -1968 */ { 07, 01, 30, 0b0110101010101000 }, /* 29 30 30 29 30 29 30 29 30 29 30 29 30 384 -1969 */ { 00, 02, 17, 0b0101011010100000 }, /* 29 30 29 30 29 30 30 29 30 29 30 29 354 -1970 */ { 00, 02, 06, 0b1001101011010000 }, /* 30 29 29 30 30 29 30 29 30 30 29 30 355 -1971 */ { 05, 01, 27, 0b0100101011101000 }, /* 29 30 29 29 30 29 30 29 30 30 30 29 30 384 -1972 */ { 00, 02, 15, 0b0100101011100000 }, /* 29 30 29 29 30 29 30 29 30 30 30 29 354 -1973 */ { 00, 02, 03, 0b1010010011100000 }, /* 30 29 30 29 29 30 29 29 30 30 30 29 354 -1974 */ { 04, 01, 23, 0b1101001001101000 }, /* 30 30 29 30 29 29 30 29 29 30 30 29 30 384 -1975 */ { 00, 02, 11, 0b1101001001010000 }, /* 30 30 29 30 29 29 30 29 29 30 29 30 354 -1976 */ { 08, 01, 31, 0b1101010101001000 }, /* 30 30 29 30 29 30 29 30 29 30 29 29 30 384 -1977 */ { 00, 02, 18, 0b1011010101000000 }, /* 30 29 30 30 29 30 29 30 29 30 29 29 354 -1978 */ { 00, 02, 07, 0b1101011010100000 }, /* 30 30 29 30 29 30 30 29 30 29 30 29 355 -1979 */ { 06, 01, 28, 0b1001011011010000 }, /* 30 29 29 30 29 30 30 29 30 30 29 30 29 384 -1980 */ { 00, 02, 16, 0b1001010110110000 }, /* 30 29 29 30 29 30 29 30 30 29 30 30 355 -1981 */ { 00, 02, 05, 0b0100100110110000 }, /* 29 30 29 29 30 29 29 30 30 29 30 30 354 -1982 */ { 04, 01, 25, 0b1010010011011000 }, /* 30 29 30 29 29 30 29 29 30 30 29 30 30 384 -1983 */ { 00, 02, 13, 0b1010010010110000 }, /* 30 29 30 29 29 30 29 29 30 29 30 30 354 -1984 */ { 10, 02, 02, 0b1011001001011000 }, /* 30 29 30 30 29 29 30 29 29 30 29 30 30 384 -1985 */ { 00, 02, 20, 0b0110101001010000 }, /* 29 30 30 29 30 29 30 29 29 30 29 30 354 -1986 */ { 00, 02, 09, 0b0110110101000000 }, /* 29 30 30 29 30 30 29 30 29 30 29 29 354 -1987 */ { 06, 01, 29, 0b1011010110101000 }, /* 30 29 30 30 29 30 29 30 30 29 30 29 30 385 -1988 */ { 00, 02, 18, 0b0010101101100000 }, /* 29 29 30 29 30 29 30 30 29 30 30 29 354 -1989 */ { 00, 02, 06, 0b1001010110110000 }, /* 30 29 29 30 29 30 29 30 30 29 30 30 355 -1990 */ { 05, 01, 27, 0b0100100110111000 }, /* 29 30 29 29 30 29 29 30 30 29 30 30 30 384 -1991 */ { 00, 02, 15, 0b0100100101110000 }, /* 29 30 29 29 30 29 29 30 29 30 30 30 354 -1992 */ { 00, 02, 04, 0b0110010010110000 }, /* 29 30 30 29 29 30 29 29 30 29 30 30 354 -1993 */ { 03, 01, 23, 0b0110101001010000 }, /* 29 30 30 29 30 29 30 29 29 30 29 30 29 383 -1994 */ { 00, 02, 10, 0b1110101001010000 }, /* 30 30 30 29 30 29 30 29 29 30 29 30 355 -1995 */ { 08, 01, 31, 0b0110110101001000 }, /* 29 30 30 29 30 30 29 30 29 30 29 29 30 384 -1996 */ { 00, 02, 19, 0b0101101011010000 }, /* 29 30 29 30 30 29 30 29 30 30 29 30 355 -1997 */ { 00, 02, 08, 0b0010101101100000 }, /* 29 29 30 29 30 29 30 30 29 30 30 29 354 -1998 */ { 05, 01, 28, 0b1001001101110000 }, /* 30 29 29 30 29 29 30 30 29 30 30 30 29 384 -1999 */ { 00, 02, 16, 0b1001001011100000 }, /* 30 29 29 30 29 29 30 29 30 30 30 29 354 -2000 */ { 00, 02, 05, 0b1100100101100000 }, /* 30 30 29 29 30 29 29 30 29 30 30 29 354 -2001 */ { 04, 01, 24, 0b1110010010101000 }, /* 30 30 30 29 29 30 29 29 30 29 30 29 30 384 -2002 */ { 00, 02, 12, 0b1101010010100000 }, /* 30 30 29 30 29 30 29 29 30 29 30 29 354 -2003 */ { 00, 02, 01, 0b1101101001010000 }, /* 30 30 29 30 30 29 30 29 29 30 29 30 355 -2004 */ { 02, 01, 22, 0b0101101010101000 }, /* 29 30 29 30 30 29 30 29 30 29 30 29 30 384 -2005 */ { 00, 02, 09, 0b0101011011000000 }, /* 29 30 29 30 29 30 30 29 30 30 29 29 354 -2006 */ { 07, 01, 29, 0b1010101011011000 }, /* 30 29 30 29 30 29 30 29 30 30 29 30 30 385 -2007 */ { 00, 02, 18, 0b0010010111010000 }, /* 29 29 30 29 29 30 29 30 30 30 29 30 354 -2008 */ { 00, 02, 07, 0b1001001011010000 }, /* 30 29 29 30 29 29 30 29 30 30 29 30 354 -2009 */ { 05, 01, 26, 0b1100100101011000 }, /* 30 30 29 29 30 29 29 30 29 30 29 30 30 384 -2010 */ { 00, 02, 14, 0b1010100101010000 }, /* 30 29 30 29 30 29 29 30 29 30 29 30 354 -2011 */ { 00, 02, 03, 0b1011010010100000 }, /* 30 29 30 30 29 30 29 29 30 29 30 29 354 -2012 */ { 03, 01, 23, 0b1011101001010000 }, /* 30 29 30 30 30 29 30 29 29 30 29 30 29 384 -2013 */ { 00, 02, 10, 0b1011010101010000 }, /* 30 29 30 30 29 30 29 30 29 30 29 30 355 -2014 */ { 09, 01, 31, 0b0101010110101000 }, /* 29 30 29 30 29 30 29 30 30 29 30 29 30 384 -2015 */ { 00, 02, 19, 0b0100101110100000 }, /* 29 30 29 29 30 29 30 30 30 29 30 29 354 -2016 */ { 00, 02, 08, 0b1010010110110000 }, /* 30 29 30 29 29 30 29 30 30 29 30 30 355 -2017 */ { 05, 01, 28, 0b0101001010111000 }, /* 29 30 29 30 29 29 30 29 30 29 30 30 30 384 -2018 */ { 00, 02, 16, 0b0101001010110000 }, /* 29 30 29 30 29 29 30 29 30 29 30 30 354 -2019 */ { 00, 02, 05, 0b1010100101010000 }, /* 30 29 30 29 30 29 29 30 29 30 29 30 354 -2020 */ { 04, 01, 25, 0b1011010010101000 }, /* 30 29 30 30 29 30 29 29 30 29 30 29 30 384 -2021 */ { 00, 02, 12, 0b0110101010100000 }, /* 29 30 30 29 30 29 30 29 30 29 30 29 354 -2022 */ { 00, 02, 01, 0b1010110101010000 }, /* 30 29 30 29 30 30 29 30 29 30 29 30 355 -2023 */ { 02, 01, 22, 0b0101010110101000 }, /* 29 30 29 30 29 30 29 30 30 29 30 29 30 384 -2024 */ { 00, 02, 10, 0b0100101101100000 }, /* 29 30 29 29 30 29 30 30 29 30 30 29 354 -2025 */ { 06, 01, 29, 0b1010010101110000 }, /* 30 29 30 29 29 30 29 30 29 30 30 30 29 384 -2026 */ { 00, 02, 17, 0b1010010101110000 }, /* 30 29 30 29 29 30 29 30 29 30 30 30 355 -2027 */ { 00, 02, 07, 0b0101001001110000 }, /* 29 30 29 30 29 29 30 29 29 30 30 30 354 -2028 */ { 05, 01, 27, 0b0110100100110000 }, /* 29 30 30 29 30 29 29 30 29 29 30 30 29 383 -2029 */ { 00, 02, 13, 0b1101100100110000 }, /* 30 30 29 30 30 29 29 30 29 29 30 30 355 -2030 */ { 00, 02, 03, 0b0101101010100000 }, /* 29 30 29 30 30 29 30 29 30 29 30 29 354 -2031 */ { 03, 01, 23, 0b1010101101010000 }, /* 30 29 30 29 30 29 30 30 29 30 29 30 29 384 -2032 */ { 00, 02, 11, 0b1001011011010000 }, /* 30 29 29 30 29 30 30 29 30 30 29 30 355 -2033 */ { 11, 01, 31, 0b0100101011101000 }, /* 29 30 29 29 30 29 30 29 30 30 30 29 30 384 -2034 */ { 00, 02, 19, 0b0100101011100000 }, /* 29 30 29 29 30 29 30 29 30 30 30 29 354 -2035 */ { 00, 02, 08, 0b1010010011010000 }, /* 30 29 30 29 29 30 29 29 30 30 29 30 354 -2036 */ { 06, 01, 28, 0b1101001001101000 }, /* 30 30 29 30 29 29 30 29 29 30 30 29 30 384 -2037 */ { 00, 02, 15, 0b1101001001010000 }, /* 30 30 29 30 29 29 30 29 29 30 29 30 354 -2038 */ { 00, 02, 04, 0b1101010100100000 }, /* 30 30 29 30 29 30 29 30 29 29 30 29 354 -2039 */ { 05, 01, 24, 0b1101101010100000 }, /* 30 30 29 30 30 29 30 29 30 29 30 29 29 384 -2040 */ { 00, 02, 12, 0b1011011010100000 }, /* 30 29 30 30 29 30 30 29 30 29 30 29 355 -2041 */ { 00, 02, 01, 0b1001011011010000 }, /* 30 29 29 30 29 30 30 29 30 30 29 30 355 -2042 */ { 02, 01, 22, 0b0100101011011000 }, /* 29 30 29 29 30 29 30 29 30 30 29 30 30 384 -2043 */ { 00, 02, 10, 0b0100100110110000 }, /* 29 30 29 29 30 29 29 30 30 29 30 30 354 -2044 */ { 07, 01, 30, 0b1010010010111000 }, /* 30 29 30 29 29 30 29 29 30 29 30 30 30 384 -2045 */ { 00, 02, 17, 0b1010010010110000 }, /* 30 29 30 29 29 30 29 29 30 29 30 30 354 -2046 */ { 00, 02, 06, 0b1011001001010000 }, /* 30 29 30 30 29 29 30 29 29 30 29 30 354 -2047 */ { 05, 01, 26, 0b1011010100101000 }, /* 30 29 30 30 29 30 29 30 29 29 30 29 30 384 -2048 */ { 00, 02, 14, 0b0110110101000000 }, /* 29 30 30 29 30 30 29 30 29 30 29 29 354 -2049 */ { 00, 02, 02, 0b1010110110100000 }, /* 30 29 30 29 30 30 29 30 30 29 30 29 355 -2050 */ { 03, 01, 23, 0b1001010110110000 }, /* 30 29 29 30 29 30 29 30 30 29 30 30 29 384 - */ }; - - internal override int MinCalendarYear => MinLunisolarYear; - - internal override int MaxCalendarYear => MaxLunisolarYear; - - internal override DateTime MinDate => s_minDate; - - internal override DateTime MaxDate => s_maxDate; - - internal override EraInfo[]? CalEraInfo => null; - - internal override int GetYearInfo(int lunarYear, int index) - { - if (lunarYear < MinLunisolarYear || lunarYear > MaxLunisolarYear) - { - throw new ArgumentOutOfRangeException( - "year", - lunarYear, - SR.Format(SR.ArgumentOutOfRange_Range, MinLunisolarYear, MaxLunisolarYear)); - } - - return s_yinfo[lunarYear - MinLunisolarYear, index]; - } - - internal override int GetYear(int year, DateTime time) - { - return year; - } - - internal override int GetGregorianYear(int year, int era) - { - if (era != CurrentEra && era != GregorianEra) - { - throw new ArgumentOutOfRangeException(nameof(era), era, SR.ArgumentOutOfRange_InvalidEraValue); - } - if (year < MinLunisolarYear || year > MaxLunisolarYear) - { - throw new ArgumentOutOfRangeException( - nameof(year), - year, - SR.Format(SR.ArgumentOutOfRange_Range, MinLunisolarYear, MaxLunisolarYear)); - } - - return year; - } - - public KoreanLunisolarCalendar() - { - } - - public override int GetEra(DateTime time) - { - CheckTicksRange(time.Ticks); - return GregorianEra; - } - - internal override CalendarId BaseCalendarID => CalendarId.KOREA; - - internal override CalendarId ID => CalendarId.KOREANLUNISOLAR; - - public override int[] Eras => new int[] { GregorianEra }; - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/LocaleData.Unix.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/LocaleData.Unix.cs deleted file mode 100644 index 2af5eb9c250..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/LocaleData.Unix.cs +++ /dev/null @@ -1,4573 +0,0 @@ -// 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; - -#pragma warning disable SA1001 - -// This file contains the handling of Windows OS specific culture features. - -namespace System.Globalization -{ - internal enum LocaleDataParts - { - Lcid = 0, - AnsiCodePage = 1, - OemCodePage = 2, - MacCodePage = 3, - EbcdicCodePage = 4, - GeoId = 5, - DigitSubstitution = 6, - SpecificLocaleIndex = 7, - ConsoleLocaleIndex = 8 - } - - internal static class LocaleData - { - // this is done rather than using a large readonly array of strings to avoid - // generating a large amount of code in the static constructor. - // Using indices from s_localeNamesIndices, we binary search this string when mapping - // an culture name to Lcid. Note that these names are all lowercase and are - // sorted alphabetically (ordinal). - private const string c_localeNames = - // culture name Lcid - "aa" + // 01000 - 0 - "aa-dj" + // 01000 - 2 - "aa-er" + // 01000 - 7 - "aa-et" + // 01000 - 12 - "af" + // 00036 - 17 - "af-na" + // 01000 - 19 - "af-za" + // 00436 - 24 - "agq" + // 01000 - 29 - "agq-cm" + // 01000 - 32 - "ak" + // 01000 - 38 - "ak-gh" + // 01000 - 40 - "am" + // 0005e - 45 - "am-et" + // 0045e - 47 - "ar" + // 00001 - 52 - "ar-001" + // 01000 - 54 - "ar-ae" + // 03801 - 60 - "ar-bh" + // 03c01 - 65 - "ar-dj" + // 01000 - 70 - "ar-dz" + // 01401 - 75 - "ar-eg" + // 00c01 - 80 - "ar-er" + // 01000 - 85 - "ar-il" + // 01000 - 90 - "ar-iq" + // 00801 - 95 - "ar-jo" + // 02c01 - 100 - "ar-km" + // 01000 - 105 - "ar-kw" + // 03401 - 110 - "ar-lb" + // 03001 - 115 - "ar-ly" + // 01001 - 120 - "ar-ma" + // 01801 - 125 - "ar-mr" + // 01000 - 130 - "ar-om" + // 02001 - 135 - "ar-ps" + // 01000 - 140 - "ar-qa" + // 04001 - 145 - "ar-sa" + // 00401 - 150 - "ar-sd" + // 01000 - 155 - "ar-so" + // 01000 - 160 - "ar-ss" + // 01000 - 165 - "ar-sy" + // 02801 - 170 - "ar-td" + // 01000 - 175 - "ar-tn" + // 01c01 - 180 - "ar-ye" + // 02401 - 185 - "arn" + // 0007a - 190 - "arn-cl" + // 0047a - 193 - "as" + // 0004d - 199 - "as-in" + // 0044d - 201 - "asa" + // 01000 - 206 - "asa-tz" + // 01000 - 209 - "ast" + // 01000 - 215 - "ast-es" + // 01000 - 218 - "az" + // 0002c - 224 - "az-cyrl" + // 0742c - 226 - "az-cyrl-az" + // 0082c - 233 - "az-latn" + // 0782c - 243 - "az-latn-az" + // 0042c - 250 - "ba" + // 0006d - 260 - "ba-ru" + // 0046d - 262 - "bas" + // 01000 - 267 - "bas-cm" + // 01000 - 270 - "be" + // 00023 - 276 - "be-by" + // 00423 - 278 - "bem" + // 01000 - 283 - "bem-zm" + // 01000 - 286 - "bez" + // 01000 - 292 - "bez-tz" + // 01000 - 295 - "bg" + // 00002 - 301 - "bg-bg" + // 00402 - 303 - "bin" + // 00066 - 308 - "bin-ng" + // 00466 - 311 - "bm" + // 01000 - 317 - "bm-latn" + // 01000 - 319 - "bm-latn-ml" + // 01000 - 326 - "bn" + // 00045 - 336 - "bn-bd" + // 00845 - 338 - "bn-in" + // 00445 - 343 - "bo" + // 00051 - 348 - "bo-cn" + // 00451 - 350 - "bo-in" + // 01000 - 355 - "br" + // 0007e - 360 - "br-fr" + // 0047e - 362 - "brx" + // 01000 - 367 - "brx-in" + // 01000 - 370 - "bs" + // 0781a - 376 - "bs-cyrl" + // 0641a - 378 - "bs-cyrl-ba" + // 0201a - 385 - "bs-latn" + // 0681a - 395 - "bs-latn-ba" + // 0141a - 402 - "byn" + // 01000 - 412 - "byn-er" + // 01000 - 415 - "ca" + // 00003 - 421 - "ca-ad" + // 01000 - 423 - "ca-es" + // 00403 - 428 - "ca-es-valencia" + // 00803 - 433 - "ca-fr" + // 01000 - 447 - "ca-it" + // 01000 - 452 - "ce" + // 01000 - 457 - "ce-ru" + // 01000 - 459 - "cgg" + // 01000 - 464 - "cgg-ug" + // 01000 - 467 - "chr" + // 0005c - 473 - "chr-cher" + // 07c5c - 476 - "chr-cher-us" + // 0045c - 484 - "co" + // 00083 - 495 - "co-fr" + // 00483 - 497 - "cs" + // 00005 - 502 - "cs-cz" + // 00405 - 504 - "cu" + // 01000 - 509 - "cu-ru" + // 01000 - 511 - "cy" + // 00052 - 516 - "cy-gb" + // 00452 - 518 - "da" + // 00006 - 523 - "da-dk" + // 00406 - 525 - "da-gl" + // 01000 - 530 - "dav" + // 01000 - 535 - "dav-ke" + // 01000 - 538 - "de" + // 00007 - 544 - "de-at" + // 00c07 - 546 - "de-be" + // 01000 - 551 - "de-ch" + // 00807 - 556 - "de-de" + // 00407 - 561 - "de-de_phoneb" + // 10407 - 566 - "de-it" + // 01000 - 578 - "de-li" + // 01407 - 583 - "de-lu" + // 01007 - 588 - "dje" + // 01000 - 593 - "dje-ne" + // 01000 - 596 - "dsb" + // 07c2e - 602 - "dsb-de" + // 0082e - 605 - "dua" + // 01000 - 611 - "dua-cm" + // 01000 - 614 - "dv" + // 00065 - 620 - "dv-mv" + // 00465 - 622 - "dyo" + // 01000 - 627 - "dyo-sn" + // 01000 - 630 - "dz" + // 01000 - 636 - "dz-bt" + // 00c51 - 638 - "ebu" + // 01000 - 643 - "ebu-ke" + // 01000 - 646 - "ee" + // 01000 - 652 - "ee-gh" + // 01000 - 654 - "ee-tg" + // 01000 - 659 - "el" + // 00008 - 664 - "el-cy" + // 01000 - 666 - "el-gr" + // 00408 - 671 - "en" + // 00009 - 676 - "en-001" + // 01000 - 678 - "en-029" + // 02409 - 684 - "en-150" + // 01000 - 690 - "en-ag" + // 01000 - 696 - "en-ai" + // 01000 - 701 - "en-as" + // 01000 - 706 - "en-at" + // 01000 - 711 - "en-au" + // 00c09 - 716 - "en-bb" + // 01000 - 721 - "en-be" + // 01000 - 726 - "en-bi" + // 01000 - 731 - "en-bm" + // 01000 - 736 - "en-bs" + // 01000 - 741 - "en-bw" + // 01000 - 746 - "en-bz" + // 02809 - 751 - "en-ca" + // 01009 - 756 - "en-cc" + // 01000 - 761 - "en-ch" + // 01000 - 766 - "en-ck" + // 01000 - 771 - "en-cm" + // 01000 - 776 - "en-cx" + // 01000 - 781 - "en-cy" + // 01000 - 786 - "en-de" + // 01000 - 791 - "en-dk" + // 01000 - 796 - "en-dm" + // 01000 - 801 - "en-er" + // 01000 - 806 - "en-fi" + // 01000 - 811 - "en-fj" + // 01000 - 816 - "en-fk" + // 01000 - 821 - "en-fm" + // 01000 - 826 - "en-gb" + // 00809 - 831 - "en-gd" + // 01000 - 836 - "en-gg" + // 01000 - 841 - "en-gh" + // 01000 - 846 - "en-gi" + // 01000 - 851 - "en-gm" + // 01000 - 856 - "en-gu" + // 01000 - 861 - "en-gy" + // 01000 - 866 - "en-hk" + // 03c09 - 871 - "en-id" + // 03809 - 876 - "en-ie" + // 01809 - 881 - "en-il" + // 01000 - 886 - "en-im" + // 01000 - 891 - "en-in" + // 04009 - 896 - "en-io" + // 01000 - 901 - "en-je" + // 01000 - 906 - "en-jm" + // 02009 - 911 - "en-ke" + // 01000 - 916 - "en-ki" + // 01000 - 921 - "en-kn" + // 01000 - 926 - "en-ky" + // 01000 - 931 - "en-lc" + // 01000 - 936 - "en-lr" + // 01000 - 941 - "en-ls" + // 01000 - 946 - "en-mg" + // 01000 - 951 - "en-mh" + // 01000 - 956 - "en-mo" + // 01000 - 961 - "en-mp" + // 01000 - 966 - "en-ms" + // 01000 - 971 - "en-mt" + // 01000 - 976 - "en-mu" + // 01000 - 981 - "en-mw" + // 01000 - 986 - "en-my" + // 04409 - 991 - "en-na" + // 01000 - 996 - "en-nf" + // 01000 - 1001 - "en-ng" + // 01000 - 1006 - "en-nl" + // 01000 - 1011 - "en-nr" + // 01000 - 1016 - "en-nu" + // 01000 - 1021 - "en-nz" + // 01409 - 1026 - "en-pg" + // 01000 - 1031 - "en-ph" + // 03409 - 1036 - "en-pk" + // 01000 - 1041 - "en-pn" + // 01000 - 1046 - "en-pr" + // 01000 - 1051 - "en-pw" + // 01000 - 1056 - "en-rw" + // 01000 - 1061 - "en-sb" + // 01000 - 1066 - "en-sc" + // 01000 - 1071 - "en-sd" + // 01000 - 1076 - "en-se" + // 01000 - 1081 - "en-sg" + // 04809 - 1086 - "en-sh" + // 01000 - 1091 - "en-si" + // 01000 - 1096 - "en-sl" + // 01000 - 1101 - "en-ss" + // 01000 - 1106 - "en-sx" + // 01000 - 1111 - "en-sz" + // 01000 - 1116 - "en-tc" + // 01000 - 1121 - "en-tk" + // 01000 - 1126 - "en-to" + // 01000 - 1131 - "en-tt" + // 02c09 - 1136 - "en-tv" + // 01000 - 1141 - "en-tz" + // 01000 - 1146 - "en-ug" + // 01000 - 1151 - "en-um" + // 01000 - 1156 - "en-us" + // 00409 - 1161 - "en-vc" + // 01000 - 1166 - "en-vg" + // 01000 - 1171 - "en-vi" + // 01000 - 1176 - "en-vu" + // 01000 - 1181 - "en-ws" + // 01000 - 1186 - "en-za" + // 01c09 - 1191 - "en-zm" + // 01000 - 1196 - "en-zw" + // 03009 - 1201 - "eo" + // 01000 - 1206 - "eo-001" + // 01000 - 1208 - "es" + // 0000a - 1214 - "es-419" + // 0580a - 1216 - "es-ar" + // 02c0a - 1222 - "es-bo" + // 0400a - 1227 - "es-br" + // 01000 - 1232 - "es-cl" + // 0340a - 1237 - "es-co" + // 0240a - 1242 - "es-cr" + // 0140a - 1247 - "es-cu" + // 05c0a - 1252 - "es-do" + // 01c0a - 1257 - "es-ec" + // 0300a - 1262 - "es-es" + // 00c0a - 1267 - "es-es_tradnl" + // 0040a - 1272 - "es-gq" + // 01000 - 1284 - "es-gt" + // 0100a - 1289 - "es-hn" + // 0480a - 1294 - "es-mx" + // 0080a - 1299 - "es-ni" + // 04c0a - 1304 - "es-pa" + // 0180a - 1309 - "es-pe" + // 0280a - 1314 - "es-ph" + // 01000 - 1319 - "es-pr" + // 0500a - 1324 - "es-py" + // 03c0a - 1329 - "es-sv" + // 0440a - 1334 - "es-us" + // 0540a - 1339 - "es-uy" + // 0380a - 1344 - "es-ve" + // 0200a - 1349 - "et" + // 00025 - 1354 - "et-ee" + // 00425 - 1356 - "eu" + // 0002d - 1361 - "eu-es" + // 0042d - 1363 - "ewo" + // 01000 - 1368 - "ewo-cm" + // 01000 - 1371 - "fa" + // 00029 - 1377 - "fa-ir" + // 00429 - 1379 - "ff" + // 00067 - 1384 - "ff-cm" + // 01000 - 1386 - "ff-gn" + // 01000 - 1391 - "ff-latn" + // 07c67 - 1396 - "ff-latn-sn" + // 00867 - 1403 - "ff-mr" + // 01000 - 1413 - "ff-ng" + // 00467 - 1418 - "fi" + // 0000b - 1423 - "fi-fi" + // 0040b - 1425 - "fil" + // 00064 - 1430 - "fil-ph" + // 00464 - 1433 - "fo" + // 00038 - 1439 - "fo-dk" + // 01000 - 1441 - "fo-fo" + // 00438 - 1446 - "fr" + // 0000c - 1451 - "fr-029" + // 01c0c - 1453 - "fr-be" + // 0080c - 1459 - "fr-bf" + // 01000 - 1464 - "fr-bi" + // 01000 - 1469 - "fr-bj" + // 01000 - 1474 - "fr-bl" + // 01000 - 1479 - "fr-ca" + // 00c0c - 1484 - "fr-cd" + // 0240c - 1489 - "fr-cf" + // 01000 - 1494 - "fr-cg" + // 01000 - 1499 - "fr-ch" + // 0100c - 1504 - "fr-ci" + // 0300c - 1509 - "fr-cm" + // 02c0c - 1514 - "fr-dj" + // 01000 - 1519 - "fr-dz" + // 01000 - 1524 - "fr-fr" + // 0040c - 1529 - "fr-ga" + // 01000 - 1534 - "fr-gf" + // 01000 - 1539 - "fr-gn" + // 01000 - 1544 - "fr-gp" + // 01000 - 1549 - "fr-gq" + // 01000 - 1554 - "fr-ht" + // 03c0c - 1559 - "fr-km" + // 01000 - 1564 - "fr-lu" + // 0140c - 1569 - "fr-ma" + // 0380c - 1574 - "fr-mc" + // 0180c - 1579 - "fr-mf" + // 01000 - 1584 - "fr-mg" + // 01000 - 1589 - "fr-ml" + // 0340c - 1594 - "fr-mq" + // 01000 - 1599 - "fr-mr" + // 01000 - 1604 - "fr-mu" + // 01000 - 1609 - "fr-nc" + // 01000 - 1614 - "fr-ne" + // 01000 - 1619 - "fr-pf" + // 01000 - 1624 - "fr-pm" + // 01000 - 1629 - "fr-re" + // 0200c - 1634 - "fr-rw" + // 01000 - 1639 - "fr-sc" + // 01000 - 1644 - "fr-sn" + // 0280c - 1649 - "fr-sy" + // 01000 - 1654 - "fr-td" + // 01000 - 1659 - "fr-tg" + // 01000 - 1664 - "fr-tn" + // 01000 - 1669 - "fr-vu" + // 01000 - 1674 - "fr-wf" + // 01000 - 1679 - "fr-yt" + // 01000 - 1684 - "fur" + // 01000 - 1689 - "fur-it" + // 01000 - 1692 - "fy" + // 00062 - 1698 - "fy-nl" + // 00462 - 1700 - "ga" + // 0003c - 1705 - "ga-ie" + // 0083c - 1707 - "gd" + // 00091 - 1712 - "gd-gb" + // 00491 - 1714 - "gl" + // 00056 - 1719 - "gl-es" + // 00456 - 1721 - "gn" + // 00074 - 1726 - "gn-py" + // 00474 - 1728 - "gsw" + // 00084 - 1733 - "gsw-ch" + // 01000 - 1736 - "gsw-fr" + // 00484 - 1742 - "gsw-li" + // 01000 - 1748 - "gu" + // 00047 - 1754 - "gu-in" + // 00447 - 1756 - "guz" + // 01000 - 1761 - "guz-ke" + // 01000 - 1764 - "gv" + // 01000 - 1770 - "gv-im" + // 01000 - 1772 - "ha" + // 00068 - 1777 - "ha-latn" + // 07c68 - 1779 - "ha-latn-gh" + // 01000 - 1786 - "ha-latn-ne" + // 01000 - 1796 - "ha-latn-ng" + // 00468 - 1806 - "haw" + // 00075 - 1816 - "haw-us" + // 00475 - 1819 - "he" + // 0000d - 1825 - "he-il" + // 0040d - 1827 - "hi" + // 00039 - 1832 - "hi-in" + // 00439 - 1834 - "hr" + // 0001a - 1839 - "hr-ba" + // 0101a - 1841 - "hr-hr" + // 0041a - 1846 - "hsb" + // 0002e - 1851 - "hsb-de" + // 0042e - 1854 - "hu" + // 0000e - 1860 - "hu-hu" + // 0040e - 1862 - "hu-hu_technl" + // 1040e - 1867 - "hy" + // 0002b - 1879 - "hy-am" + // 0042b - 1881 - "ia" + // 01000 - 1886 - "ia-001" + // 01000 - 1888 - "ia-fr" + // 01000 - 1894 - "ibb" + // 00069 - 1899 - "ibb-ng" + // 00469 - 1902 - "id" + // 00021 - 1908 - "id-id" + // 00421 - 1910 - "ig" + // 00070 - 1915 - "ig-ng" + // 00470 - 1917 - "ii" + // 00078 - 1922 - "ii-cn" + // 00478 - 1924 - "is" + // 0000f - 1929 - "is-is" + // 0040f - 1931 - "it" + // 00010 - 1936 - "it-ch" + // 00810 - 1938 - "it-it" + // 00410 - 1943 - "it-sm" + // 01000 - 1948 - "iu" + // 0005d - 1953 - "iu-cans" + // 0785d - 1955 - "iu-cans-ca" + // 0045d - 1962 - "iu-latn" + // 07c5d - 1972 - "iu-latn-ca" + // 0085d - 1979 - "ja" + // 00011 - 1989 - "ja-jp" + // 00411 - 1991 - "ja-jp_radstr" + // 40411 - 1996 - "jgo" + // 01000 - 2008 - "jgo-cm" + // 01000 - 2011 - "jmc" + // 01000 - 2017 - "jmc-tz" + // 01000 - 2020 - "jv" + // 01000 - 2026 - "jv-java" + // 01000 - 2028 - "jv-java-id" + // 01000 - 2035 - "jv-latn" + // 01000 - 2045 - "jv-latn-id" + // 01000 - 2052 - "ka" + // 00037 - 2062 - "ka-ge" + // 00437 - 2064 - "ka-ge_modern" + // 10437 - 2069 - "kab" + // 01000 - 2081 - "kab-dz" + // 01000 - 2084 - "kam" + // 01000 - 2090 - "kam-ke" + // 01000 - 2093 - "kde" + // 01000 - 2099 - "kde-tz" + // 01000 - 2102 - "kea" + // 01000 - 2108 - "kea-cv" + // 01000 - 2111 - "khq" + // 01000 - 2117 - "khq-ml" + // 01000 - 2120 - "ki" + // 01000 - 2126 - "ki-ke" + // 01000 - 2128 - "kk" + // 0003f - 2133 - "kk-kz" + // 0043f - 2135 - "kkj" + // 01000 - 2140 - "kkj-cm" + // 01000 - 2143 - "kl" + // 0006f - 2149 - "kl-gl" + // 0046f - 2151 - "kln" + // 01000 - 2156 - "kln-ke" + // 01000 - 2159 - "km" + // 00053 - 2165 - "km-kh" + // 00453 - 2167 - "kn" + // 0004b - 2172 - "kn-in" + // 0044b - 2174 - "ko" + // 00012 - 2179 - "ko-kp" + // 01000 - 2181 - "ko-kr" + // 00412 - 2186 - "kok" + // 00057 - 2191 - "kok-in" + // 00457 - 2194 - "kr" + // 00071 - 2200 - "kr-ng" + // 00471 - 2202 - "ks" + // 00060 - 2207 - "ks-arab" + // 00460 - 2209 - "ks-arab-in" + // 01000 - 2216 - "ks-deva" + // 01000 - 2226 - "ks-deva-in" + // 00860 - 2233 - "ksb" + // 01000 - 2243 - "ksb-tz" + // 01000 - 2246 - "ksf" + // 01000 - 2252 - "ksf-cm" + // 01000 - 2255 - "ksh" + // 01000 - 2261 - "ksh-de" + // 01000 - 2264 - "ku" + // 00092 - 2270 - "ku-arab" + // 07c92 - 2272 - "ku-arab-iq" + // 00492 - 2279 - "ku-arab-ir" + // 01000 - 2289 - "kw" + // 01000 - 2299 - "kw-gb" + // 01000 - 2301 - "ky" + // 00040 - 2306 - "ky-kg" + // 00440 - 2308 - "la" + // 00076 - 2313 - "la-001" + // 00476 - 2315 - "lag" + // 01000 - 2321 - "lag-tz" + // 01000 - 2324 - "lb" + // 0006e - 2330 - "lb-lu" + // 0046e - 2332 - "lg" + // 01000 - 2337 - "lg-ug" + // 01000 - 2339 - "lkt" + // 01000 - 2344 - "lkt-us" + // 01000 - 2347 - "ln" + // 01000 - 2353 - "ln-ao" + // 01000 - 2355 - "ln-cd" + // 01000 - 2360 - "ln-cf" + // 01000 - 2365 - "ln-cg" + // 01000 - 2370 - "lo" + // 00054 - 2375 - "lo-la" + // 00454 - 2377 - "lrc" + // 01000 - 2382 - "lrc-iq" + // 01000 - 2385 - "lrc-ir" + // 01000 - 2391 - "lt" + // 00027 - 2397 - "lt-lt" + // 00427 - 2399 - "lu" + // 01000 - 2404 - "lu-cd" + // 01000 - 2406 - "luo" + // 01000 - 2411 - "luo-ke" + // 01000 - 2414 - "luy" + // 01000 - 2420 - "luy-ke" + // 01000 - 2423 - "lv" + // 00026 - 2429 - "lv-lv" + // 00426 - 2431 - "mas" + // 01000 - 2436 - "mas-ke" + // 01000 - 2439 - "mas-tz" + // 01000 - 2445 - "mer" + // 01000 - 2451 - "mer-ke" + // 01000 - 2454 - "mfe" + // 01000 - 2460 - "mfe-mu" + // 01000 - 2463 - "mg" + // 01000 - 2469 - "mg-mg" + // 01000 - 2471 - "mgh" + // 01000 - 2476 - "mgh-mz" + // 01000 - 2479 - "mgo" + // 01000 - 2485 - "mgo-cm" + // 01000 - 2488 - "mi" + // 00081 - 2494 - "mi-nz" + // 00481 - 2496 - "mk" + // 0002f - 2501 - "mk-mk" + // 0042f - 2503 - "ml" + // 0004c - 2508 - "ml-in" + // 0044c - 2510 - "mn" + // 00050 - 2515 - "mn-cyrl" + // 07850 - 2517 - "mn-mn" + // 00450 - 2524 - "mn-mong" + // 07c50 - 2529 - "mn-mong-cn" + // 00850 - 2536 - "mn-mong-mn" + // 00c50 - 2546 - "mni" + // 00058 - 2556 - "mni-in" + // 00458 - 2559 - "moh" + // 0007c - 2565 - "moh-ca" + // 0047c - 2568 - "mr" + // 0004e - 2574 - "mr-in" + // 0044e - 2576 - "ms" + // 0003e - 2581 - "ms-bn" + // 0083e - 2583 - "ms-my" + // 0043e - 2588 - "ms-sg" + // 01000 - 2593 - "mt" + // 0003a - 2598 - "mt-mt" + // 0043a - 2600 - "mua" + // 01000 - 2605 - "mua-cm" + // 01000 - 2608 - "my" + // 00055 - 2614 - "my-mm" + // 00455 - 2616 - "mzn" + // 01000 - 2621 - "mzn-ir" + // 01000 - 2624 - "naq" + // 01000 - 2630 - "naq-na" + // 01000 - 2633 - "nb" + // 07c14 - 2639 - "nb-no" + // 00414 - 2641 - "nb-sj" + // 01000 - 2646 - "nd" + // 01000 - 2651 - "nd-zw" + // 01000 - 2653 - "nds" + // 01000 - 2658 - "nds-de" + // 01000 - 2661 - "nds-nl" + // 01000 - 2667 - "ne" + // 00061 - 2673 - "ne-in" + // 00861 - 2675 - "ne-np" + // 00461 - 2680 - "nl" + // 00013 - 2685 - "nl-aw" + // 01000 - 2687 - "nl-be" + // 00813 - 2692 - "nl-bq" + // 01000 - 2697 - "nl-cw" + // 01000 - 2702 - "nl-nl" + // 00413 - 2707 - "nl-sr" + // 01000 - 2712 - "nl-sx" + // 01000 - 2717 - "nmg" + // 01000 - 2722 - "nmg-cm" + // 01000 - 2725 - "nn" + // 07814 - 2731 - "nn-no" + // 00814 - 2733 - "nnh" + // 01000 - 2738 - "nnh-cm" + // 01000 - 2741 - "no" + // 00014 - 2747 - "nqo" + // 01000 - 2749 - "nqo-gn" + // 01000 - 2752 - "nr" + // 01000 - 2758 - "nr-za" + // 01000 - 2760 - "nso" + // 0006c - 2765 - "nso-za" + // 0046c - 2768 - "nus" + // 01000 - 2774 - "nus-ss" + // 01000 - 2777 - "nyn" + // 01000 - 2783 - "nyn-ug" + // 01000 - 2786 - "oc" + // 00082 - 2792 - "oc-fr" + // 00482 - 2794 - "om" + // 00072 - 2799 - "om-et" + // 00472 - 2801 - "om-ke" + // 01000 - 2806 - "or" + // 00048 - 2811 - "or-in" + // 00448 - 2813 - "os" + // 01000 - 2818 - "os-ge" + // 01000 - 2820 - "os-ru" + // 01000 - 2825 - "pa" + // 00046 - 2830 - "pa-arab" + // 07c46 - 2832 - "pa-arab-pk" + // 00846 - 2839 - "pa-in" + // 00446 - 2849 - "pap" + // 00079 - 2854 - "pap-029" + // 00479 - 2857 - "pl" + // 00015 - 2864 - "pl-pl" + // 00415 - 2866 - "prg" + // 01000 - 2871 - "prg-001" + // 01000 - 2874 - "prs" + // 0008c - 2881 - "prs-af" + // 0048c - 2884 - "ps" + // 00063 - 2890 - "ps-af" + // 00463 - 2892 - "pt" + // 00016 - 2897 - "pt-ao" + // 01000 - 2899 - "pt-br" + // 00416 - 2904 - "pt-ch" + // 01000 - 2909 - "pt-cv" + // 01000 - 2914 - "pt-gq" + // 01000 - 2919 - "pt-gw" + // 01000 - 2924 - "pt-lu" + // 01000 - 2929 - "pt-mo" + // 01000 - 2934 - "pt-mz" + // 01000 - 2939 - "pt-pt" + // 00816 - 2944 - "pt-st" + // 01000 - 2949 - "pt-tl" + // 01000 - 2954 - "qps-latn-x-sh" + // 00901 - 2959 - "qps-ploc" + // 00501 - 2972 - "qps-ploca" + // 005fe - 2980 - "qps-plocm" + // 009ff - 2989 - "quc" + // 00086 - 2998 - "quc-latn" + // 07c86 - 3001 - "quc-latn-gt" + // 00486 - 3009 - "quz" + // 0006b - 3020 - "quz-bo" + // 0046b - 3023 - "quz-ec" + // 0086b - 3029 - "quz-pe" + // 00c6b - 3035 - "rm" + // 00017 - 3041 - "rm-ch" + // 00417 - 3043 - "rn" + // 01000 - 3048 - "rn-bi" + // 01000 - 3050 - "ro" + // 00018 - 3055 - "ro-md" + // 00818 - 3057 - "ro-ro" + // 00418 - 3062 - "rof" + // 01000 - 3067 - "rof-tz" + // 01000 - 3070 - "ru" + // 00019 - 3076 - "ru-by" + // 01000 - 3078 - "ru-kg" + // 01000 - 3083 - "ru-kz" + // 01000 - 3088 - "ru-md" + // 00819 - 3093 - "ru-ru" + // 00419 - 3098 - "ru-ua" + // 01000 - 3103 - "rw" + // 00087 - 3108 - "rw-rw" + // 00487 - 3110 - "rwk" + // 01000 - 3115 - "rwk-tz" + // 01000 - 3118 - "sa" + // 0004f - 3124 - "sa-in" + // 0044f - 3126 - "sah" + // 00085 - 3131 - "sah-ru" + // 00485 - 3134 - "saq" + // 01000 - 3140 - "saq-ke" + // 01000 - 3143 - "sbp" + // 01000 - 3149 - "sbp-tz" + // 01000 - 3152 - "sd" + // 00059 - 3158 - "sd-arab" + // 07c59 - 3160 - "sd-arab-pk" + // 00859 - 3167 - "sd-deva" + // 01000 - 3177 - "sd-deva-in" + // 00459 - 3184 - "se" + // 0003b - 3194 - "se-fi" + // 00c3b - 3196 - "se-no" + // 0043b - 3201 - "se-se" + // 0083b - 3206 - "seh" + // 01000 - 3211 - "seh-mz" + // 01000 - 3214 - "ses" + // 01000 - 3220 - "ses-ml" + // 01000 - 3223 - "sg" + // 01000 - 3229 - "sg-cf" + // 01000 - 3231 - "shi" + // 01000 - 3236 - "shi-latn" + // 01000 - 3239 - "shi-latn-ma" + // 01000 - 3247 - "shi-tfng" + // 01000 - 3258 - "shi-tfng-ma" + // 01000 - 3266 - "si" + // 0005b - 3277 - "si-lk" + // 0045b - 3279 - "sk" + // 0001b - 3284 - "sk-sk" + // 0041b - 3286 - "sl" + // 00024 - 3291 - "sl-si" + // 00424 - 3293 - "sma" + // 0783b - 3298 - "sma-no" + // 0183b - 3301 - "sma-se" + // 01c3b - 3307 - "smj" + // 07c3b - 3313 - "smj-no" + // 0103b - 3316 - "smj-se" + // 0143b - 3322 - "smn" + // 0703b - 3328 - "smn-fi" + // 0243b - 3331 - "sms" + // 0743b - 3337 - "sms-fi" + // 0203b - 3340 - "sn" + // 01000 - 3346 - "sn-latn" + // 01000 - 3348 - "sn-latn-zw" + // 01000 - 3355 - "so" + // 00077 - 3365 - "so-dj" + // 01000 - 3367 - "so-et" + // 01000 - 3372 - "so-ke" + // 01000 - 3377 - "so-so" + // 00477 - 3382 - "sq" + // 0001c - 3387 - "sq-al" + // 0041c - 3389 - "sq-mk" + // 01000 - 3394 - "sq-xk" + // 01000 - 3399 - "sr" + // 07c1a - 3404 - "sr-cyrl" + // 06c1a - 3406 - "sr-cyrl-ba" + // 01c1a - 3413 - "sr-cyrl-cs" + // 00c1a - 3423 - "sr-cyrl-me" + // 0301a - 3433 - "sr-cyrl-rs" + // 0281a - 3443 - "sr-cyrl-xk" + // 01000 - 3453 - "sr-latn" + // 0701a - 3463 - "sr-latn-ba" + // 0181a - 3470 - "sr-latn-cs" + // 0081a - 3480 - "sr-latn-me" + // 02c1a - 3490 - "sr-latn-rs" + // 0241a - 3500 - "sr-latn-xk" + // 01000 - 3510 - "ss" + // 01000 - 3520 - "ss-sz" + // 01000 - 3522 - "ss-za" + // 01000 - 3527 - "ssy" + // 01000 - 3532 - "ssy-er" + // 01000 - 3535 - "st" + // 00030 - 3541 - "st-ls" + // 01000 - 3543 - "st-za" + // 00430 - 3548 - "sv" + // 0001d - 3553 - "sv-ax" + // 01000 - 3555 - "sv-fi" + // 0081d - 3560 - "sv-se" + // 0041d - 3565 - "sw" + // 00041 - 3570 - "sw-cd" + // 01000 - 3572 - "sw-ke" + // 00441 - 3577 - "sw-tz" + // 01000 - 3582 - "sw-ug" + // 01000 - 3587 - "swc" + // 01000 - 3592 - "swc-cd" + // 01000 - 3595 - "syr" + // 0005a - 3601 - "syr-sy" + // 0045a - 3604 - "ta" + // 00049 - 3610 - "ta-in" + // 00449 - 3612 - "ta-lk" + // 00849 - 3617 - "ta-my" + // 01000 - 3622 - "ta-sg" + // 01000 - 3627 - "te" + // 0004a - 3632 - "te-in" + // 0044a - 3634 - "teo" + // 01000 - 3639 - "teo-ke" + // 01000 - 3642 - "teo-ug" + // 01000 - 3648 - "tg" + // 00028 - 3654 - "tg-cyrl" + // 07c28 - 3656 - "tg-cyrl-tj" + // 00428 - 3663 - "th" + // 0001e - 3673 - "th-th" + // 0041e - 3675 - "ti" + // 00073 - 3680 - "ti-er" + // 00873 - 3682 - "ti-et" + // 00473 - 3687 - "tig" + // 01000 - 3692 - "tig-er" + // 01000 - 3695 - "tk" + // 00042 - 3701 - "tk-tm" + // 00442 - 3703 - "tn" + // 00032 - 3708 - "tn-bw" + // 00832 - 3710 - "tn-za" + // 00432 - 3715 - "to" + // 01000 - 3720 - "to-to" + // 01000 - 3722 - "tr" + // 0001f - 3727 - "tr-cy" + // 01000 - 3729 - "tr-tr" + // 0041f - 3734 - "ts" + // 00031 - 3739 - "ts-za" + // 00431 - 3741 - "tt" + // 00044 - 3746 - "tt-ru" + // 00444 - 3748 - "twq" + // 01000 - 3753 - "twq-ne" + // 01000 - 3756 - "tzm" + // 0005f - 3762 - "tzm-arab" + // 01000 - 3765 - "tzm-arab-ma" + // 0045f - 3773 - "tzm-latn" + // 07c5f - 3784 - "tzm-latn-dz" + // 0085f - 3792 - "tzm-latn-ma" + // 01000 - 3803 - "tzm-tfng" + // 0785f - 3814 - "tzm-tfng-ma" + // 0105f - 3822 - "ug" + // 00080 - 3833 - "ug-cn" + // 00480 - 3835 - "uk" + // 00022 - 3840 - "uk-ua" + // 00422 - 3842 - "ur" + // 00020 - 3847 - "ur-in" + // 00820 - 3849 - "ur-pk" + // 00420 - 3854 - "uz" + // 00043 - 3859 - "uz-arab" + // 01000 - 3861 - "uz-arab-af" + // 01000 - 3868 - "uz-cyrl" + // 07843 - 3878 - "uz-cyrl-uz" + // 00843 - 3885 - "uz-latn" + // 07c43 - 3895 - "uz-latn-uz" + // 00443 - 3902 - "vai" + // 01000 - 3912 - "vai-latn" + // 01000 - 3915 - "vai-latn-lr" + // 01000 - 3923 - "vai-vaii" + // 01000 - 3934 - "vai-vaii-lr" + // 01000 - 3942 - "ve" + // 00033 - 3953 - "ve-za" + // 00433 - 3955 - "vi" + // 0002a - 3960 - "vi-vn" + // 0042a - 3962 - "vo" + // 01000 - 3967 - "vo-001" + // 01000 - 3969 - "vun" + // 01000 - 3975 - "vun-tz" + // 01000 - 3978 - "wae" + // 01000 - 3984 - "wae-ch" + // 01000 - 3987 - "wal" + // 01000 - 3993 - "wal-et" + // 01000 - 3996 - "wo" + // 00088 - 4002 - "wo-sn" + // 00488 - 4004 - "x-iv_mathan" + // 1007f - 4009 - "xh" + // 00034 - 4020 - "xh-za" + // 00434 - 4022 - "xog" + // 01000 - 4027 - "xog-ug" + // 01000 - 4030 - "yav" + // 01000 - 4036 - "yav-cm" + // 01000 - 4039 - "yi" + // 0003d - 4045 - "yi-001" + // 0043d - 4047 - "yo" + // 0006a - 4053 - "yo-bj" + // 01000 - 4055 - "yo-ng" + // 0046a - 4060 - "yue" + // 01000 - 4065 - "yue-hk" + // 01000 - 4068 - "zgh" + // 01000 - 4074 - "zgh-tfng" + // 01000 - 4077 - "zgh-tfng-ma" + // 01000 - 4085 - "zh" + // 07804 - 4096 - "zh-chs" + // 00004 - 4098 - "zh-cht" + // 07c04 - 4104 - "zh-cn" + // 00804 - 4110 - "zh-cn_phoneb" + // 50804 - 4115 - "zh-cn_stroke" + // 20804 - 4127 - "zh-hans" + // 00004 - 4139 - "zh-hans-hk" + // 01000 - 4146 - "zh-hans-mo" + // 01000 - 4156 - "zh-hant" + // 07c04 - 4166 - "zh-hk" + // 00c04 - 4173 - "zh-hk_radstr" + // 40c04 - 4178 - "zh-mo" + // 01404 - 4190 - "zh-mo_radstr" + // 41404 - 4195 - "zh-mo_stroke" + // 21404 - 4207 - "zh-sg" + // 01004 - 4219 - "zh-sg_phoneb" + // 51004 - 4224 - "zh-sg_stroke" + // 21004 - 4236 - "zh-tw" + // 00404 - 4248 - "zh-tw_pronun" + // 30404 - 4253 - "zh-tw_radstr" + // 40404 - 4265 - "zu" + // 00035 - 4277 - "zu-za"; // 00435 - 4279 - - // c_threeLetterWindowsLanguageName is string containing 3-letter Windows language names - // every 3-characters entry is matching locale name entry in c_localeNames - - private const string c_threeLetterWindowsLanguageName = - "ZZZ" + // aa - "ZZZ" + // aa-dj - "ZZZ" + // aa-er - "ZZZ" + // aa-et - "AFK" + // af - "ZZZ" + // af-na - "AFK" + // af-za - "ZZZ" + // agq - "ZZZ" + // agq-cm - "ZZZ" + // ak - "ZZZ" + // ak-gh - "AMH" + // am - "AMH" + // am-et - "ARA" + // ar - "ZZZ" + // ar-001 - "ARU" + // ar-ae - "ARH" + // ar-bh - "ZZZ" + // ar-dj - "ARG" + // ar-dz - "ARE" + // ar-eg - "ZZZ" + // ar-er - "ZZZ" + // ar-il - "ARI" + // ar-iq - "ARJ" + // ar-jo - "ZZZ" + // ar-km - "ARK" + // ar-kw - "ARB" + // ar-lb - "ARL" + // ar-ly - "ARM" + // ar-ma - "ZZZ" + // ar-mr - "ARO" + // ar-om - "ZZZ" + // ar-ps - "ARQ" + // ar-qa - "ARA" + // ar-sa - "ZZZ" + // ar-sd - "ZZZ" + // ar-so - "ZZZ" + // ar-ss - "ARS" + // ar-sy - "ZZZ" + // ar-td - "ART" + // ar-tn - "ARY" + // ar-ye - "MPD" + // arn - "MPD" + // arn-cl - "ASM" + // as - "ASM" + // as-in - "ZZZ" + // asa - "ZZZ" + // asa-tz - "ZZZ" + // ast - "ZZZ" + // ast-es - "AZE" + // az - "AZC" + // az-cyrl - "AZC" + // az-cyrl-az - "AZE" + // az-latn - "AZE" + // az-latn-az - "BAS" + // ba - "BAS" + // ba-ru - "ZZZ" + // bas - "ZZZ" + // bas-cm - "BEL" + // be - "BEL" + // be-by - "ZZZ" + // bem - "ZZZ" + // bem-zm - "ZZZ" + // bez - "ZZZ" + // bez-tz - "BGR" + // bg - "BGR" + // bg-bg - "ZZZ" + // bin - "ZZZ" + // bin-ng - "ZZZ" + // bm - "ZZZ" + // bm-latn - "ZZZ" + // bm-latn-ml - "BNB" + // bn - "BNB" + // bn-bd - "BNG" + // bn-in - "BOB" + // bo - "BOB" + // bo-cn - "ZZZ" + // bo-in - "BRE" + // br - "BRE" + // br-fr - "ZZZ" + // brx - "ZZZ" + // brx-in - "BSB" + // bs - "BSC" + // bs-cyrl - "BSC" + // bs-cyrl-ba - "BSB" + // bs-latn - "BSB" + // bs-latn-ba - "ZZZ" + // byn - "ZZZ" + // byn-er - "CAT" + // ca - "ZZZ" + // ca-ad - "CAT" + // ca-es - "VAL" + // ca-es-valencia - "ZZZ" + // ca-fr - "ZZZ" + // ca-it - "ZZZ" + // ce - "ZZZ" + // ce-ru - "ZZZ" + // cgg - "ZZZ" + // cgg-ug - "CRE" + // chr - "CRE" + // chr-cher - "CRE" + // chr-cher-us - "COS" + // co - "COS" + // co-fr - "CSY" + // cs - "CSY" + // cs-cz - "ZZZ" + // cu - "ZZZ" + // cu-ru - "CYM" + // cy - "CYM" + // cy-gb - "DAN" + // da - "DAN" + // da-dk - "ZZZ" + // da-gl - "ZZZ" + // dav - "ZZZ" + // dav-ke - "DEU" + // de - "DEA" + // de-at - "ZZZ" + // de-be - "DES" + // de-ch - "DEU" + // de-de - "DEU" + // de-de_phoneb - "ZZZ" + // de-it - "DEC" + // de-li - "DEL" + // de-lu - "ZZZ" + // dje - "ZZZ" + // dje-ne - "DSB" + // dsb - "DSB" + // dsb-de - "ZZZ" + // dua - "ZZZ" + // dua-cm - "DIV" + // dv - "DIV" + // dv-mv - "ZZZ" + // dyo - "ZZZ" + // dyo-sn - "ZZZ" + // dz - "ZZZ" + // dz-bt - "ZZZ" + // ebu - "ZZZ" + // ebu-ke - "ZZZ" + // ee - "ZZZ" + // ee-gh - "ZZZ" + // ee-tg - "ELL" + // el - "ZZZ" + // el-cy - "ELL" + // el-gr - "ENU" + // en - "ZZZ" + // en-001 - "ENB" + // en-029 - "ZZZ" + // en-150 - "ZZZ" + // en-ag - "ZZZ" + // en-ai - "ZZZ" + // en-as - "ZZZ" + // en-at - "ENA" + // en-au - "ZZZ" + // en-bb - "ZZZ" + // en-be - "ZZZ" + // en-bi - "ZZZ" + // en-bm - "ZZZ" + // en-bs - "ZZZ" + // en-bw - "ENL" + // en-bz - "ENC" + // en-ca - "ZZZ" + // en-cc - "ZZZ" + // en-ch - "ZZZ" + // en-ck - "ZZZ" + // en-cm - "ZZZ" + // en-cx - "ZZZ" + // en-cy - "ZZZ" + // en-de - "ZZZ" + // en-dk - "ZZZ" + // en-dm - "ZZZ" + // en-er - "ZZZ" + // en-fi - "ZZZ" + // en-fj - "ZZZ" + // en-fk - "ZZZ" + // en-fm - "ENG" + // en-gb - "ZZZ" + // en-gd - "ZZZ" + // en-gg - "ZZZ" + // en-gh - "ZZZ" + // en-gi - "ZZZ" + // en-gm - "ZZZ" + // en-gu - "ZZZ" + // en-gy - "ENH" + // en-hk - "ZZZ" + // en-id - "ENI" + // en-ie - "ZZZ" + // en-il - "ZZZ" + // en-im - "ENN" + // en-in - "ZZZ" + // en-io - "ZZZ" + // en-je - "ENJ" + // en-jm - "ZZZ" + // en-ke - "ZZZ" + // en-ki - "ZZZ" + // en-kn - "ZZZ" + // en-ky - "ZZZ" + // en-lc - "ZZZ" + // en-lr - "ZZZ" + // en-ls - "ZZZ" + // en-mg - "ZZZ" + // en-mh - "ZZZ" + // en-mo - "ZZZ" + // en-mp - "ZZZ" + // en-ms - "ZZZ" + // en-mt - "ZZZ" + // en-mu - "ZZZ" + // en-mw - "ENM" + // en-my - "ZZZ" + // en-na - "ZZZ" + // en-nf - "ZZZ" + // en-ng - "ZZZ" + // en-nl - "ZZZ" + // en-nr - "ZZZ" + // en-nu - "ENZ" + // en-nz - "ZZZ" + // en-pg - "ENP" + // en-ph - "ZZZ" + // en-pk - "ZZZ" + // en-pn - "ZZZ" + // en-pr - "ZZZ" + // en-pw - "ZZZ" + // en-rw - "ZZZ" + // en-sb - "ZZZ" + // en-sc - "ZZZ" + // en-sd - "ZZZ" + // en-se - "ENE" + // en-sg - "ZZZ" + // en-sh - "ZZZ" + // en-si - "ZZZ" + // en-sl - "ZZZ" + // en-ss - "ZZZ" + // en-sx - "ZZZ" + // en-sz - "ZZZ" + // en-tc - "ZZZ" + // en-tk - "ZZZ" + // en-to - "ENT" + // en-tt - "ZZZ" + // en-tv - "ZZZ" + // en-tz - "ZZZ" + // en-ug - "ZZZ" + // en-um - "ENU" + // en-us - "ZZZ" + // en-vc - "ZZZ" + // en-vg - "ZZZ" + // en-vi - "ZZZ" + // en-vu - "ZZZ" + // en-ws - "ENS" + // en-za - "ZZZ" + // en-zm - "ENW" + // en-zw - "ZZZ" + // eo - "ZZZ" + // eo-001 - "ESN" + // es - "ESJ" + // es-419 - "ESS" + // es-ar - "ESB" + // es-bo - "ZZZ" + // es-br - "ESL" + // es-cl - "ESO" + // es-co - "ESC" + // es-cr - "ESK" + // es-cu - "ESD" + // es-do - "ESF" + // es-ec - "ESN" + // es-es - "ESP" + // es-es_tradnl - "ZZZ" + // es-gq - "ESG" + // es-gt - "ESH" + // es-hn - "ESM" + // es-mx - "ESI" + // es-ni - "ESA" + // es-pa - "ESR" + // es-pe - "ZZZ" + // es-ph - "ESU" + // es-pr - "ESZ" + // es-py - "ESE" + // es-sv - "EST" + // es-us - "ESY" + // es-uy - "ESV" + // es-ve - "ETI" + // et - "ETI" + // et-ee - "EUQ" + // eu - "EUQ" + // eu-es - "ZZZ" + // ewo - "ZZZ" + // ewo-cm - "FAR" + // fa - "FAR" + // fa-ir - "FUL" + // ff - "ZZZ" + // ff-cm - "ZZZ" + // ff-gn - "FUL" + // ff-latn - "FUL" + // ff-latn-sn - "ZZZ" + // ff-mr - "ZZZ" + // ff-ng - "FIN" + // fi - "FIN" + // fi-fi - "FPO" + // fil - "FPO" + // fil-ph - "FOS" + // fo - "ZZZ" + // fo-dk - "FOS" + // fo-fo - "FRA" + // fr - "ZZZ" + // fr-029 - "FRB" + // fr-be - "ZZZ" + // fr-bf - "ZZZ" + // fr-bi - "ZZZ" + // fr-bj - "ZZZ" + // fr-bl - "FRC" + // fr-ca - "FRD" + // fr-cd - "ZZZ" + // fr-cf - "ZZZ" + // fr-cg - "FRS" + // fr-ch - "FRI" + // fr-ci - "FRE" + // fr-cm - "ZZZ" + // fr-dj - "ZZZ" + // fr-dz - "FRA" + // fr-fr - "ZZZ" + // fr-ga - "ZZZ" + // fr-gf - "ZZZ" + // fr-gn - "ZZZ" + // fr-gp - "ZZZ" + // fr-gq - "FRH" + // fr-ht - "ZZZ" + // fr-km - "FRL" + // fr-lu - "FRO" + // fr-ma - "FRM" + // fr-mc - "ZZZ" + // fr-mf - "ZZZ" + // fr-mg - "FRF" + // fr-ml - "ZZZ" + // fr-mq - "ZZZ" + // fr-mr - "ZZZ" + // fr-mu - "ZZZ" + // fr-nc - "ZZZ" + // fr-ne - "ZZZ" + // fr-pf - "ZZZ" + // fr-pm - "FRR" + // fr-re - "ZZZ" + // fr-rw - "ZZZ" + // fr-sc - "FRN" + // fr-sn - "ZZZ" + // fr-sy - "ZZZ" + // fr-td - "ZZZ" + // fr-tg - "ZZZ" + // fr-tn - "ZZZ" + // fr-vu - "ZZZ" + // fr-wf - "ZZZ" + // fr-yt - "ZZZ" + // fur - "ZZZ" + // fur-it - "FYN" + // fy - "FYN" + // fy-nl - "IRE" + // ga - "IRE" + // ga-ie - "GLA" + // gd - "GLA" + // gd-gb - "GLC" + // gl - "GLC" + // gl-es - "GRN" + // gn - "GRN" + // gn-py - "ZZZ" + // gsw - "ZZZ" + // gsw-ch - "GSW" + // gsw-fr - "ZZZ" + // gsw-li - "GUJ" + // gu - "GUJ" + // gu-in - "ZZZ" + // guz - "ZZZ" + // guz-ke - "ZZZ" + // gv - "ZZZ" + // gv-im - "HAU" + // ha - "HAU" + // ha-latn - "ZZZ" + // ha-latn-gh - "ZZZ" + // ha-latn-ne - "HAU" + // ha-latn-ng - "HAW" + // haw - "HAW" + // haw-us - "HEB" + // he - "HEB" + // he-il - "HIN" + // hi - "HIN" + // hi-in - "HRV" + // hr - "HRB" + // hr-ba - "HRV" + // hr-hr - "HSB" + // hsb - "HSB" + // hsb-de - "HUN" + // hu - "HUN" + // hu-hu - "HUN" + // hu-hu_technl - "HYE" + // hy - "HYE" + // hy-am - "ZZZ" + // ia - "ZZZ" + // ia-001 - "ZZZ" + // ia-fr - "ZZZ" + // ibb - "ZZZ" + // ibb-ng - "IND" + // id - "IND" + // id-id - "IBO" + // ig - "IBO" + // ig-ng - "III" + // ii - "III" + // ii-cn - "ISL" + // is - "ISL" + // is-is - "ITA" + // it - "ITS" + // it-ch - "ITA" + // it-it - "ZZZ" + // it-sm - "IUK" + // iu - "IUS" + // iu-cans - "IUS" + // iu-cans-ca - "IUK" + // iu-latn - "IUK" + // iu-latn-ca - "JPN" + // ja - "JPN" + // ja-jp - "JPN" + // ja-jp_radstr - "ZZZ" + // jgo - "ZZZ" + // jgo-cm - "ZZZ" + // jmc - "ZZZ" + // jmc-tz - "JAV" + // jv - "ZZZ" + // jv-java - "ZZZ" + // jv-java-id - "JAV" + // jv-latn - "JAV" + // jv-latn-id - "KAT" + // ka - "KAT" + // ka-ge - "KAT" + // ka-ge_modern - "ZZZ" + // kab - "ZZZ" + // kab-dz - "ZZZ" + // kam - "ZZZ" + // kam-ke - "ZZZ" + // kde - "ZZZ" + // kde-tz - "ZZZ" + // kea - "ZZZ" + // kea-cv - "ZZZ" + // khq - "ZZZ" + // khq-ml - "ZZZ" + // ki - "ZZZ" + // ki-ke - "KKZ" + // kk - "KKZ" + // kk-kz - "ZZZ" + // kkj - "ZZZ" + // kkj-cm - "KAL" + // kl - "KAL" + // kl-gl - "ZZZ" + // kln - "ZZZ" + // kln-ke - "KHM" + // km - "KHM" + // km-kh - "KDI" + // kn - "KDI" + // kn-in - "KOR" + // ko - "ZZZ" + // ko-kp - "KOR" + // ko-kr - "KNK" + // kok - "KNK" + // kok-in - "ZZZ" + // kr - "ZZZ" + // kr-ng - "ZZZ" + // ks - "ZZZ" + // ks-arab - "ZZZ" + // ks-arab-in - "ZZZ" + // ks-deva - "ZZZ" + // ks-deva-in - "ZZZ" + // ksb - "ZZZ" + // ksb-tz - "ZZZ" + // ksf - "ZZZ" + // ksf-cm - "ZZZ" + // ksh - "ZZZ" + // ksh-de - "KUR" + // ku - "KUR" + // ku-arab - "KUR" + // ku-arab-iq - "ZZZ" + // ku-arab-ir - "ZZZ" + // kw - "ZZZ" + // kw-gb - "KYR" + // ky - "KYR" + // ky-kg - "ZZZ" + // la - "ZZZ" + // la-001 - "ZZZ" + // lag - "ZZZ" + // lag-tz - "LBX" + // lb - "LBX" + // lb-lu - "ZZZ" + // lg - "ZZZ" + // lg-ug - "ZZZ" + // lkt - "ZZZ" + // lkt-us - "ZZZ" + // ln - "ZZZ" + // ln-ao - "ZZZ" + // ln-cd - "ZZZ" + // ln-cf - "ZZZ" + // ln-cg - "LAO" + // lo - "LAO" + // lo-la - "ZZZ" + // lrc - "ZZZ" + // lrc-iq - "ZZZ" + // lrc-ir - "LTH" + // lt - "LTH" + // lt-lt - "ZZZ" + // lu - "ZZZ" + // lu-cd - "ZZZ" + // luo - "ZZZ" + // luo-ke - "ZZZ" + // luy - "ZZZ" + // luy-ke - "LVI" + // lv - "LVI" + // lv-lv - "ZZZ" + // mas - "ZZZ" + // mas-ke - "ZZZ" + // mas-tz - "ZZZ" + // mer - "ZZZ" + // mer-ke - "ZZZ" + // mfe - "ZZZ" + // mfe-mu - "MLG" + // mg - "MLG" + // mg-mg - "ZZZ" + // mgh - "ZZZ" + // mgh-mz - "ZZZ" + // mgo - "ZZZ" + // mgo-cm - "MRI" + // mi - "MRI" + // mi-nz - "MKI" + // mk - "MKI" + // mk-mk - "MYM" + // ml - "MYM" + // ml-in - "MNN" + // mn - "MNN" + // mn-cyrl - "MNN" + // mn-mn - "MNG" + // mn-mong - "MNG" + // mn-mong-cn - "MNM" + // mn-mong-mn - "ZZZ" + // mni - "ZZZ" + // mni-in - "MWK" + // moh - "MWK" + // moh-ca - "MAR" + // mr - "MAR" + // mr-in - "MSL" + // ms - "MSB" + // ms-bn - "MSL" + // ms-my - "ZZZ" + // ms-sg - "MLT" + // mt - "MLT" + // mt-mt - "ZZZ" + // mua - "ZZZ" + // mua-cm - "MYA" + // my - "MYA" + // my-mm - "ZZZ" + // mzn - "ZZZ" + // mzn-ir - "ZZZ" + // naq - "ZZZ" + // naq-na - "NOR" + // nb - "NOR" + // nb-no - "ZZZ" + // nb-sj - "ZZZ" + // nd - "ZZZ" + // nd-zw - "ZZZ" + // nds - "ZZZ" + // nds-de - "ZZZ" + // nds-nl - "NEP" + // ne - "NEI" + // ne-in - "NEP" + // ne-np - "NLD" + // nl - "ZZZ" + // nl-aw - "NLB" + // nl-be - "ZZZ" + // nl-bq - "ZZZ" + // nl-cw - "NLD" + // nl-nl - "ZZZ" + // nl-sr - "ZZZ" + // nl-sx - "ZZZ" + // nmg - "ZZZ" + // nmg-cm - "NON" + // nn - "NON" + // nn-no - "ZZZ" + // nnh - "ZZZ" + // nnh-cm - "NOR" + // no - "NQO" + // nqo - "NQO" + // nqo-gn - "ZZZ" + // nr - "ZZZ" + // nr-za - "NSO" + // nso - "NSO" + // nso-za - "ZZZ" + // nus - "ZZZ" + // nus-ss - "ZZZ" + // nyn - "ZZZ" + // nyn-ug - "OCI" + // oc - "OCI" + // oc-fr - "ORM" + // om - "ORM" + // om-et - "ZZZ" + // om-ke - "ORI" + // or - "ORI" + // or-in - "ZZZ" + // os - "ZZZ" + // os-ge - "ZZZ" + // os-ru - "PAN" + // pa - "PAP" + // pa-arab - "PAP" + // pa-arab-pk - "PAN" + // pa-in - "ZZZ" + // pap - "ZZZ" + // pap-029 - "PLK" + // pl - "PLK" + // pl-pl - "ZZZ" + // prg - "ZZZ" + // prg-001 - "PRS" + // prs - "PRS" + // prs-af - "PAS" + // ps - "PAS" + // ps-af - "PTB" + // pt - "PTA" + // pt-ao - "PTB" + // pt-br - "ZZZ" + // pt-ch - "ZZZ" + // pt-cv - "ZZZ" + // pt-gq - "ZZZ" + // pt-gw - "ZZZ" + // pt-lu - "ZZZ" + // pt-mo - "ZZZ" + // pt-mz - "PTG" + // pt-pt - "ZZZ" + // pt-st - "ZZZ" + // pt-tl - "ENJ" + // qps-latn-x-sh - "ENU" + // qps-ploc - "JPN" + // qps-ploca - "ARA" + // qps-plocm - "QUT" + // quc - "QUT" + // quc-latn - "QUT" + // quc-latn-gt - "QUB" + // quz - "QUB" + // quz-bo - "QUE" + // quz-ec - "QUP" + // quz-pe - "RMC" + // rm - "RMC" + // rm-ch - "ZZZ" + // rn - "ZZZ" + // rn-bi - "ROM" + // ro - "ROD" + // ro-md - "ROM" + // ro-ro - "ZZZ" + // rof - "ZZZ" + // rof-tz - "RUS" + // ru - "ZZZ" + // ru-by - "ZZZ" + // ru-kg - "ZZZ" + // ru-kz - "RUM" + // ru-md - "RUS" + // ru-ru - "ZZZ" + // ru-ua - "KIN" + // rw - "KIN" + // rw-rw - "ZZZ" + // rwk - "ZZZ" + // rwk-tz - "SAN" + // sa - "SAN" + // sa-in - "SAH" + // sah - "SAH" + // sah-ru - "ZZZ" + // saq - "ZZZ" + // saq-ke - "ZZZ" + // sbp - "ZZZ" + // sbp-tz - "SIP" + // sd - "SIP" + // sd-arab - "SIP" + // sd-arab-pk - "ZZZ" + // sd-deva - "ZZZ" + // sd-deva-in - "SME" + // se - "SMG" + // se-fi - "SME" + // se-no - "SMF" + // se-se - "ZZZ" + // seh - "ZZZ" + // seh-mz - "ZZZ" + // ses - "ZZZ" + // ses-ml - "ZZZ" + // sg - "ZZZ" + // sg-cf - "ZZZ" + // shi - "ZZZ" + // shi-latn - "ZZZ" + // shi-latn-ma - "ZZZ" + // shi-tfng - "ZZZ" + // shi-tfng-ma - "SIN" + // si - "SIN" + // si-lk - "SKY" + // sk - "SKY" + // sk-sk - "SLV" + // sl - "SLV" + // sl-si - "SMB" + // sma - "SMA" + // sma-no - "SMB" + // sma-se - "SMK" + // smj - "SMJ" + // smj-no - "SMK" + // smj-se - "SMN" + // smn - "SMN" + // smn-fi - "SMS" + // sms - "SMS" + // sms-fi - "SNA" + // sn - "SNA" + // sn-latn - "SNA" + // sn-latn-zw - "SOM" + // so - "ZZZ" + // so-dj - "ZZZ" + // so-et - "ZZZ" + // so-ke - "SOM" + // so-so - "SQI" + // sq - "SQI" + // sq-al - "ZZZ" + // sq-mk - "ZZZ" + // sq-xk - "SRM" + // sr - "SRO" + // sr-cyrl - "SRN" + // sr-cyrl-ba - "SRB" + // sr-cyrl-cs - "SRQ" + // sr-cyrl-me - "SRO" + // sr-cyrl-rs - "ZZZ" + // sr-cyrl-xk - "SRM" + // sr-latn - "SRS" + // sr-latn-ba - "SRL" + // sr-latn-cs - "SRP" + // sr-latn-me - "SRM" + // sr-latn-rs - "ZZZ" + // sr-latn-xk - "ZZZ" + // ss - "ZZZ" + // ss-sz - "ZZZ" + // ss-za - "ZZZ" + // ssy - "ZZZ" + // ssy-er - "SOT" + // st - "ZZZ" + // st-ls - "SOT" + // st-za - "SVE" + // sv - "ZZZ" + // sv-ax - "SVF" + // sv-fi - "SVE" + // sv-se - "SWK" + // sw - "ZZZ" + // sw-cd - "SWK" + // sw-ke - "ZZZ" + // sw-tz - "ZZZ" + // sw-ug - "ZZZ" + // swc - "ZZZ" + // swc-cd - "SYR" + // syr - "SYR" + // syr-sy - "TAI" + // ta - "TAI" + // ta-in - "TAM" + // ta-lk - "ZZZ" + // ta-my - "ZZZ" + // ta-sg - "TEL" + // te - "TEL" + // te-in - "ZZZ" + // teo - "ZZZ" + // teo-ke - "ZZZ" + // teo-ug - "TAJ" + // tg - "TAJ" + // tg-cyrl - "TAJ" + // tg-cyrl-tj - "THA" + // th - "THA" + // th-th - "TIR" + // ti - "TIR" + // ti-er - "TIE" + // ti-et - "ZZZ" + // tig - "ZZZ" + // tig-er - "TUK" + // tk - "TUK" + // tk-tm - "TSN" + // tn - "TSB" + // tn-bw - "TSN" + // tn-za - "ZZZ" + // to - "ZZZ" + // to-to - "TRK" + // tr - "ZZZ" + // tr-cy - "TRK" + // tr-tr - "TSO" + // ts - "TSO" + // ts-za - "TTT" + // tt - "TTT" + // tt-ru - "ZZZ" + // twq - "ZZZ" + // twq-ne - "TZA" + // tzm - "ZZZ" + // tzm-arab - "ZZZ" + // tzm-arab-ma - "TZA" + // tzm-latn - "TZA" + // tzm-latn-dz - "ZZZ" + // tzm-latn-ma - "TZM" + // tzm-tfng - "TZM" + // tzm-tfng-ma - "UIG" + // ug - "UIG" + // ug-cn - "UKR" + // uk - "UKR" + // uk-ua - "URD" + // ur - "URI" + // ur-in - "URD" + // ur-pk - "UZB" + // uz - "ZZZ" + // uz-arab - "ZZZ" + // uz-arab-af - "UZC" + // uz-cyrl - "UZC" + // uz-cyrl-uz - "UZB" + // uz-latn - "UZB" + // uz-latn-uz - "ZZZ" + // vai - "ZZZ" + // vai-latn - "ZZZ" + // vai-latn-lr - "ZZZ" + // vai-vaii - "ZZZ" + // vai-vaii-lr - "ZZZ" + // ve - "ZZZ" + // ve-za - "VIT" + // vi - "VIT" + // vi-vn - "ZZZ" + // vo - "ZZZ" + // vo-001 - "ZZZ" + // vun - "ZZZ" + // vun-tz - "ZZZ" + // wae - "ZZZ" + // wae-ch - "ZZZ" + // wal - "ZZZ" + // wal-et - "WOL" + // wo - "WOL" + // wo-sn - "IVL" + // x-iv_mathan - "XHO" + // xh - "XHO" + // xh-za - "ZZZ" + // xog - "ZZZ" + // xog-ug - "ZZZ" + // yav - "ZZZ" + // yav-cm - "ZZZ" + // yi - "ZZZ" + // yi-001 - "YOR" + // yo - "ZZZ" + // yo-bj - "YOR" + // yo-ng - "ZZZ" + // yue - "ZZZ" + // yue-hk - "ZHG" + // zgh - "ZHG" + // zgh-tfng - "ZHG" + // zgh-tfng-ma - "CHS" + // zh - "CHS" + // zh-chs - "CHT" + // zh-cht - "CHS" + // zh-cn - "CHS" + // zh-cn_phoneb - "CHS" + // zh-cn_stroke - "CHS" + // zh-hans - "ZZZ" + // zh-hans-hk - "ZZZ" + // zh-hans-mo - "ZHH" + // zh-hant - "ZHH" + // zh-hk - "ZHH" + // zh-hk_radstr - "ZHM" + // zh-mo - "ZHM" + // zh-mo_radstr - "ZHM" + // zh-mo_stroke - "ZHI" + // zh-sg - "ZHI" + // zh-sg_phoneb - "ZHI" + // zh-sg_stroke - "CHT" + // zh-tw - "CHT" + // zh-tw_pronun - "CHT" + // zh-tw_radstr - "ZUL" + // zu - "ZUL"; // zu-za - - // s_localeNamesIndices contains the start index of every culture name in the string - // s_localeNames. We infer the length of each string by looking at the start index - // of the next string. - private static readonly int[] s_localeNamesIndices = new int[] - { - // c_localeNames index, // index to this array - culture name - 0 , // 0 - aa - 2 , // 1 - aa-dj - 7 , // 2 - aa-er - 12 , // 3 - aa-et - 17 , // 4 - af - 19 , // 5 - af-na - 24 , // 6 - af-za - 29 , // 7 - agq - 32 , // 8 - agq-cm - 38 , // 9 - ak - 40 , // 10 - ak-gh - 45 , // 11 - am - 47 , // 12 - am-et - 52 , // 13 - ar - 54 , // 14 - ar-001 - 60 , // 15 - ar-ae - 65 , // 16 - ar-bh - 70 , // 17 - ar-dj - 75 , // 18 - ar-dz - 80 , // 19 - ar-eg - 85 , // 20 - ar-er - 90 , // 21 - ar-il - 95 , // 22 - ar-iq - 100 , // 23 - ar-jo - 105 , // 24 - ar-km - 110 , // 25 - ar-kw - 115 , // 26 - ar-lb - 120 , // 27 - ar-ly - 125 , // 28 - ar-ma - 130 , // 29 - ar-mr - 135 , // 30 - ar-om - 140 , // 31 - ar-ps - 145 , // 32 - ar-qa - 150 , // 33 - ar-sa - 155 , // 34 - ar-sd - 160 , // 35 - ar-so - 165 , // 36 - ar-ss - 170 , // 37 - ar-sy - 175 , // 38 - ar-td - 180 , // 39 - ar-tn - 185 , // 40 - ar-ye - 190 , // 41 - arn - 193 , // 42 - arn-cl - 199 , // 43 - as - 201 , // 44 - as-in - 206 , // 45 - asa - 209 , // 46 - asa-tz - 215 , // 47 - ast - 218 , // 48 - ast-es - 224 , // 49 - az - 226 , // 50 - az-cyrl - 233 , // 51 - az-cyrl-az - 243 , // 52 - az-latn - 250 , // 53 - az-latn-az - 260 , // 54 - ba - 262 , // 55 - ba-ru - 267 , // 56 - bas - 270 , // 57 - bas-cm - 276 , // 58 - be - 278 , // 59 - be-by - 283 , // 60 - bem - 286 , // 61 - bem-zm - 292 , // 62 - bez - 295 , // 63 - bez-tz - 301 , // 64 - bg - 303 , // 65 - bg-bg - 308 , // 66 - bin - 311 , // 67 - bin-ng - 317 , // 68 - bm - 319 , // 69 - bm-latn - 326 , // 70 - bm-latn-ml - 336 , // 71 - bn - 338 , // 72 - bn-bd - 343 , // 73 - bn-in - 348 , // 74 - bo - 350 , // 75 - bo-cn - 355 , // 76 - bo-in - 360 , // 77 - br - 362 , // 78 - br-fr - 367 , // 79 - brx - 370 , // 80 - brx-in - 376 , // 81 - bs - 378 , // 82 - bs-cyrl - 385 , // 83 - bs-cyrl-ba - 395 , // 84 - bs-latn - 402 , // 85 - bs-latn-ba - 412 , // 86 - byn - 415 , // 87 - byn-er - 421 , // 88 - ca - 423 , // 89 - ca-ad - 428 , // 90 - ca-es - 433 , // 91 - ca-es-valencia - 447 , // 92 - ca-fr - 452 , // 93 - ca-it - 457 , // 94 - ce - 459 , // 95 - ce-ru - 464 , // 96 - cgg - 467 , // 97 - cgg-ug - 473 , // 98 - chr - 476 , // 99 - chr-cher - 484 , // 100 - chr-cher-us - 495 , // 101 - co - 497 , // 102 - co-fr - 502 , // 103 - cs - 504 , // 104 - cs-cz - 509 , // 105 - cu - 511 , // 106 - cu-ru - 516 , // 107 - cy - 518 , // 108 - cy-gb - 523 , // 109 - da - 525 , // 110 - da-dk - 530 , // 111 - da-gl - 535 , // 112 - dav - 538 , // 113 - dav-ke - 544 , // 114 - de - 546 , // 115 - de-at - 551 , // 116 - de-be - 556 , // 117 - de-ch - 561 , // 118 - de-de - 566 , // 119 - de-de_phoneb - 578 , // 120 - de-it - 583 , // 121 - de-li - 588 , // 122 - de-lu - 593 , // 123 - dje - 596 , // 124 - dje-ne - 602 , // 125 - dsb - 605 , // 126 - dsb-de - 611 , // 127 - dua - 614 , // 128 - dua-cm - 620 , // 129 - dv - 622 , // 130 - dv-mv - 627 , // 131 - dyo - 630 , // 132 - dyo-sn - 636 , // 133 - dz - 638 , // 134 - dz-bt - 643 , // 135 - ebu - 646 , // 136 - ebu-ke - 652 , // 137 - ee - 654 , // 138 - ee-gh - 659 , // 139 - ee-tg - 664 , // 140 - el - 666 , // 141 - el-cy - 671 , // 142 - el-gr - 676 , // 143 - en - 678 , // 144 - en-001 - 684 , // 145 - en-029 - 690 , // 146 - en-150 - 696 , // 147 - en-ag - 701 , // 148 - en-ai - 706 , // 149 - en-as - 711 , // 150 - en-at - 716 , // 151 - en-au - 721 , // 152 - en-bb - 726 , // 153 - en-be - 731 , // 154 - en-bi - 736 , // 155 - en-bm - 741 , // 156 - en-bs - 746 , // 157 - en-bw - 751 , // 158 - en-bz - 756 , // 159 - en-ca - 761 , // 160 - en-cc - 766 , // 161 - en-ch - 771 , // 162 - en-ck - 776 , // 163 - en-cm - 781 , // 164 - en-cx - 786 , // 165 - en-cy - 791 , // 166 - en-de - 796 , // 167 - en-dk - 801 , // 168 - en-dm - 806 , // 169 - en-er - 811 , // 170 - en-fi - 816 , // 171 - en-fj - 821 , // 172 - en-fk - 826 , // 173 - en-fm - 831 , // 174 - en-gb - 836 , // 175 - en-gd - 841 , // 176 - en-gg - 846 , // 177 - en-gh - 851 , // 178 - en-gi - 856 , // 179 - en-gm - 861 , // 180 - en-gu - 866 , // 181 - en-gy - 871 , // 182 - en-hk - 876 , // 183 - en-id - 881 , // 184 - en-ie - 886 , // 185 - en-il - 891 , // 186 - en-im - 896 , // 187 - en-in - 901 , // 188 - en-io - 906 , // 189 - en-je - 911 , // 190 - en-jm - 916 , // 191 - en-ke - 921 , // 192 - en-ki - 926 , // 193 - en-kn - 931 , // 194 - en-ky - 936 , // 195 - en-lc - 941 , // 196 - en-lr - 946 , // 197 - en-ls - 951 , // 198 - en-mg - 956 , // 199 - en-mh - 961 , // 200 - en-mo - 966 , // 201 - en-mp - 971 , // 202 - en-ms - 976 , // 203 - en-mt - 981 , // 204 - en-mu - 986 , // 205 - en-mw - 991 , // 206 - en-my - 996 , // 207 - en-na - 1001, // 208 - en-nf - 1006, // 209 - en-ng - 1011, // 210 - en-nl - 1016, // 211 - en-nr - 1021, // 212 - en-nu - 1026, // 213 - en-nz - 1031, // 214 - en-pg - 1036, // 215 - en-ph - 1041, // 216 - en-pk - 1046, // 217 - en-pn - 1051, // 218 - en-pr - 1056, // 219 - en-pw - 1061, // 220 - en-rw - 1066, // 221 - en-sb - 1071, // 222 - en-sc - 1076, // 223 - en-sd - 1081, // 224 - en-se - 1086, // 225 - en-sg - 1091, // 226 - en-sh - 1096, // 227 - en-si - 1101, // 228 - en-sl - 1106, // 229 - en-ss - 1111, // 230 - en-sx - 1116, // 231 - en-sz - 1121, // 232 - en-tc - 1126, // 233 - en-tk - 1131, // 234 - en-to - 1136, // 235 - en-tt - 1141, // 236 - en-tv - 1146, // 237 - en-tz - 1151, // 238 - en-ug - 1156, // 239 - en-um - 1161, // 240 - en-us - 1166, // 241 - en-vc - 1171, // 242 - en-vg - 1176, // 243 - en-vi - 1181, // 244 - en-vu - 1186, // 245 - en-ws - 1191, // 246 - en-za - 1196, // 247 - en-zm - 1201, // 248 - en-zw - 1206, // 249 - eo - 1208, // 250 - eo-001 - 1214, // 251 - es - 1216, // 252 - es-419 - 1222, // 253 - es-ar - 1227, // 254 - es-bo - 1232, // 255 - es-br - 1237, // 256 - es-cl - 1242, // 257 - es-co - 1247, // 258 - es-cr - 1252, // 259 - es-cu - 1257, // 260 - es-do - 1262, // 261 - es-ec - 1267, // 262 - es-es - 1272, // 263 - es-es_tradnl - 1284, // 264 - es-gq - 1289, // 265 - es-gt - 1294, // 266 - es-hn - 1299, // 267 - es-mx - 1304, // 268 - es-ni - 1309, // 269 - es-pa - 1314, // 270 - es-pe - 1319, // 271 - es-ph - 1324, // 272 - es-pr - 1329, // 273 - es-py - 1334, // 274 - es-sv - 1339, // 275 - es-us - 1344, // 276 - es-uy - 1349, // 277 - es-ve - 1354, // 278 - et - 1356, // 279 - et-ee - 1361, // 280 - eu - 1363, // 281 - eu-es - 1368, // 282 - ewo - 1371, // 283 - ewo-cm - 1377, // 284 - fa - 1379, // 285 - fa-ir - 1384, // 286 - ff - 1386, // 287 - ff-cm - 1391, // 288 - ff-gn - 1396, // 289 - ff-latn - 1403, // 290 - ff-latn-sn - 1413, // 291 - ff-mr - 1418, // 292 - ff-ng - 1423, // 293 - fi - 1425, // 294 - fi-fi - 1430, // 295 - fil - 1433, // 296 - fil-ph - 1439, // 297 - fo - 1441, // 298 - fo-dk - 1446, // 299 - fo-fo - 1451, // 300 - fr - 1453, // 301 - fr-029 - 1459, // 302 - fr-be - 1464, // 303 - fr-bf - 1469, // 304 - fr-bi - 1474, // 305 - fr-bj - 1479, // 306 - fr-bl - 1484, // 307 - fr-ca - 1489, // 308 - fr-cd - 1494, // 309 - fr-cf - 1499, // 310 - fr-cg - 1504, // 311 - fr-ch - 1509, // 312 - fr-ci - 1514, // 313 - fr-cm - 1519, // 314 - fr-dj - 1524, // 315 - fr-dz - 1529, // 316 - fr-fr - 1534, // 317 - fr-ga - 1539, // 318 - fr-gf - 1544, // 319 - fr-gn - 1549, // 320 - fr-gp - 1554, // 321 - fr-gq - 1559, // 322 - fr-ht - 1564, // 323 - fr-km - 1569, // 324 - fr-lu - 1574, // 325 - fr-ma - 1579, // 326 - fr-mc - 1584, // 327 - fr-mf - 1589, // 328 - fr-mg - 1594, // 329 - fr-ml - 1599, // 330 - fr-mq - 1604, // 331 - fr-mr - 1609, // 332 - fr-mu - 1614, // 333 - fr-nc - 1619, // 334 - fr-ne - 1624, // 335 - fr-pf - 1629, // 336 - fr-pm - 1634, // 337 - fr-re - 1639, // 338 - fr-rw - 1644, // 339 - fr-sc - 1649, // 340 - fr-sn - 1654, // 341 - fr-sy - 1659, // 342 - fr-td - 1664, // 343 - fr-tg - 1669, // 344 - fr-tn - 1674, // 345 - fr-vu - 1679, // 346 - fr-wf - 1684, // 347 - fr-yt - 1689, // 348 - fur - 1692, // 349 - fur-it - 1698, // 350 - fy - 1700, // 351 - fy-nl - 1705, // 352 - ga - 1707, // 353 - ga-ie - 1712, // 354 - gd - 1714, // 355 - gd-gb - 1719, // 356 - gl - 1721, // 357 - gl-es - 1726, // 358 - gn - 1728, // 359 - gn-py - 1733, // 360 - gsw - 1736, // 361 - gsw-ch - 1742, // 362 - gsw-fr - 1748, // 363 - gsw-li - 1754, // 364 - gu - 1756, // 365 - gu-in - 1761, // 366 - guz - 1764, // 367 - guz-ke - 1770, // 368 - gv - 1772, // 369 - gv-im - 1777, // 370 - ha - 1779, // 371 - ha-latn - 1786, // 372 - ha-latn-gh - 1796, // 373 - ha-latn-ne - 1806, // 374 - ha-latn-ng - 1816, // 375 - haw - 1819, // 376 - haw-us - 1825, // 377 - he - 1827, // 378 - he-il - 1832, // 379 - hi - 1834, // 380 - hi-in - 1839, // 381 - hr - 1841, // 382 - hr-ba - 1846, // 383 - hr-hr - 1851, // 384 - hsb - 1854, // 385 - hsb-de - 1860, // 386 - hu - 1862, // 387 - hu-hu - 1867, // 388 - hu-hu_technl - 1879, // 389 - hy - 1881, // 390 - hy-am - 1886, // 391 - ia - 1888, // 392 - ia-001 - 1894, // 393 - ia-fr - 1899, // 394 - ibb - 1902, // 395 - ibb-ng - 1908, // 396 - id - 1910, // 397 - id-id - 1915, // 398 - ig - 1917, // 399 - ig-ng - 1922, // 400 - ii - 1924, // 401 - ii-cn - 1929, // 402 - is - 1931, // 403 - is-is - 1936, // 404 - it - 1938, // 405 - it-ch - 1943, // 406 - it-it - 1948, // 407 - it-sm - 1953, // 408 - iu - 1955, // 409 - iu-cans - 1962, // 410 - iu-cans-ca - 1972, // 411 - iu-latn - 1979, // 412 - iu-latn-ca - 1989, // 413 - ja - 1991, // 414 - ja-jp - 1996, // 415 - ja-jp_radstr - 2008, // 416 - jgo - 2011, // 417 - jgo-cm - 2017, // 418 - jmc - 2020, // 419 - jmc-tz - 2026, // 420 - jv - 2028, // 421 - jv-java - 2035, // 422 - jv-java-id - 2045, // 423 - jv-latn - 2052, // 424 - jv-latn-id - 2062, // 425 - ka - 2064, // 426 - ka-ge - 2069, // 427 - ka-ge_modern - 2081, // 428 - kab - 2084, // 429 - kab-dz - 2090, // 430 - kam - 2093, // 431 - kam-ke - 2099, // 432 - kde - 2102, // 433 - kde-tz - 2108, // 434 - kea - 2111, // 435 - kea-cv - 2117, // 436 - khq - 2120, // 437 - khq-ml - 2126, // 438 - ki - 2128, // 439 - ki-ke - 2133, // 440 - kk - 2135, // 441 - kk-kz - 2140, // 442 - kkj - 2143, // 443 - kkj-cm - 2149, // 444 - kl - 2151, // 445 - kl-gl - 2156, // 446 - kln - 2159, // 447 - kln-ke - 2165, // 448 - km - 2167, // 449 - km-kh - 2172, // 450 - kn - 2174, // 451 - kn-in - 2179, // 452 - ko - 2181, // 453 - ko-kp - 2186, // 454 - ko-kr - 2191, // 455 - kok - 2194, // 456 - kok-in - 2200, // 457 - kr - 2202, // 458 - kr-ng - 2207, // 459 - ks - 2209, // 460 - ks-arab - 2216, // 461 - ks-arab-in - 2226, // 462 - ks-deva - 2233, // 463 - ks-deva-in - 2243, // 464 - ksb - 2246, // 465 - ksb-tz - 2252, // 466 - ksf - 2255, // 467 - ksf-cm - 2261, // 468 - ksh - 2264, // 469 - ksh-de - 2270, // 470 - ku - 2272, // 471 - ku-arab - 2279, // 472 - ku-arab-iq - 2289, // 473 - ku-arab-ir - 2299, // 474 - kw - 2301, // 475 - kw-gb - 2306, // 476 - ky - 2308, // 477 - ky-kg - 2313, // 478 - la - 2315, // 479 - la-001 - 2321, // 480 - lag - 2324, // 481 - lag-tz - 2330, // 482 - lb - 2332, // 483 - lb-lu - 2337, // 484 - lg - 2339, // 485 - lg-ug - 2344, // 486 - lkt - 2347, // 487 - lkt-us - 2353, // 488 - ln - 2355, // 489 - ln-ao - 2360, // 490 - ln-cd - 2365, // 491 - ln-cf - 2370, // 492 - ln-cg - 2375, // 493 - lo - 2377, // 494 - lo-la - 2382, // 495 - lrc - 2385, // 496 - lrc-iq - 2391, // 497 - lrc-ir - 2397, // 498 - lt - 2399, // 499 - lt-lt - 2404, // 500 - lu - 2406, // 501 - lu-cd - 2411, // 502 - luo - 2414, // 503 - luo-ke - 2420, // 504 - luy - 2423, // 505 - luy-ke - 2429, // 506 - lv - 2431, // 507 - lv-lv - 2436, // 508 - mas - 2439, // 509 - mas-ke - 2445, // 510 - mas-tz - 2451, // 511 - mer - 2454, // 512 - mer-ke - 2460, // 513 - mfe - 2463, // 514 - mfe-mu - 2469, // 515 - mg - 2471, // 516 - mg-mg - 2476, // 517 - mgh - 2479, // 518 - mgh-mz - 2485, // 519 - mgo - 2488, // 520 - mgo-cm - 2494, // 521 - mi - 2496, // 522 - mi-nz - 2501, // 523 - mk - 2503, // 524 - mk-mk - 2508, // 525 - ml - 2510, // 526 - ml-in - 2515, // 527 - mn - 2517, // 528 - mn-cyrl - 2524, // 529 - mn-mn - 2529, // 530 - mn-mong - 2536, // 531 - mn-mong-cn - 2546, // 532 - mn-mong-mn - 2556, // 533 - mni - 2559, // 534 - mni-in - 2565, // 535 - moh - 2568, // 536 - moh-ca - 2574, // 537 - mr - 2576, // 538 - mr-in - 2581, // 539 - ms - 2583, // 540 - ms-bn - 2588, // 541 - ms-my - 2593, // 542 - ms-sg - 2598, // 543 - mt - 2600, // 544 - mt-mt - 2605, // 545 - mua - 2608, // 546 - mua-cm - 2614, // 547 - my - 2616, // 548 - my-mm - 2621, // 549 - mzn - 2624, // 550 - mzn-ir - 2630, // 551 - naq - 2633, // 552 - naq-na - 2639, // 553 - nb - 2641, // 554 - nb-no - 2646, // 555 - nb-sj - 2651, // 556 - nd - 2653, // 557 - nd-zw - 2658, // 558 - nds - 2661, // 559 - nds-de - 2667, // 560 - nds-nl - 2673, // 561 - ne - 2675, // 562 - ne-in - 2680, // 563 - ne-np - 2685, // 564 - nl - 2687, // 565 - nl-aw - 2692, // 566 - nl-be - 2697, // 567 - nl-bq - 2702, // 568 - nl-cw - 2707, // 569 - nl-nl - 2712, // 570 - nl-sr - 2717, // 571 - nl-sx - 2722, // 572 - nmg - 2725, // 573 - nmg-cm - 2731, // 574 - nn - 2733, // 575 - nn-no - 2738, // 576 - nnh - 2741, // 577 - nnh-cm - 2747, // 578 - no - 2749, // 579 - nqo - 2752, // 580 - nqo-gn - 2758, // 581 - nr - 2760, // 582 - nr-za - 2765, // 583 - nso - 2768, // 584 - nso-za - 2774, // 585 - nus - 2777, // 586 - nus-ss - 2783, // 587 - nyn - 2786, // 588 - nyn-ug - 2792, // 589 - oc - 2794, // 590 - oc-fr - 2799, // 591 - om - 2801, // 592 - om-et - 2806, // 593 - om-ke - 2811, // 594 - or - 2813, // 595 - or-in - 2818, // 596 - os - 2820, // 597 - os-ge - 2825, // 598 - os-ru - 2830, // 599 - pa - 2832, // 600 - pa-arab - 2839, // 601 - pa-arab-pk - 2849, // 602 - pa-in - 2854, // 603 - pap - 2857, // 604 - pap-029 - 2864, // 605 - pl - 2866, // 606 - pl-pl - 2871, // 607 - prg - 2874, // 608 - prg-001 - 2881, // 609 - prs - 2884, // 610 - prs-af - 2890, // 611 - ps - 2892, // 612 - ps-af - 2897, // 613 - pt - 2899, // 614 - pt-ao - 2904, // 615 - pt-br - 2909, // 616 - pt-ch - 2914, // 617 - pt-cv - 2919, // 618 - pt-gq - 2924, // 619 - pt-gw - 2929, // 620 - pt-lu - 2934, // 621 - pt-mo - 2939, // 622 - pt-mz - 2944, // 623 - pt-pt - 2949, // 624 - pt-st - 2954, // 625 - pt-tl - 2959, // 626 - qps-latn-x-sh - 2972, // 627 - qps-ploc - 2980, // 628 - qps-ploca - 2989, // 629 - qps-plocm - 2998, // 630 - quc - 3001, // 631 - quc-latn - 3009, // 632 - quc-latn-gt - 3020, // 633 - quz - 3023, // 634 - quz-bo - 3029, // 635 - quz-ec - 3035, // 636 - quz-pe - 3041, // 637 - rm - 3043, // 638 - rm-ch - 3048, // 639 - rn - 3050, // 640 - rn-bi - 3055, // 641 - ro - 3057, // 642 - ro-md - 3062, // 643 - ro-ro - 3067, // 644 - rof - 3070, // 645 - rof-tz - 3076, // 646 - ru - 3078, // 647 - ru-by - 3083, // 648 - ru-kg - 3088, // 649 - ru-kz - 3093, // 650 - ru-md - 3098, // 651 - ru-ru - 3103, // 652 - ru-ua - 3108, // 653 - rw - 3110, // 654 - rw-rw - 3115, // 655 - rwk - 3118, // 656 - rwk-tz - 3124, // 657 - sa - 3126, // 658 - sa-in - 3131, // 659 - sah - 3134, // 660 - sah-ru - 3140, // 661 - saq - 3143, // 662 - saq-ke - 3149, // 663 - sbp - 3152, // 664 - sbp-tz - 3158, // 665 - sd - 3160, // 666 - sd-arab - 3167, // 667 - sd-arab-pk - 3177, // 668 - sd-deva - 3184, // 669 - sd-deva-in - 3194, // 670 - se - 3196, // 671 - se-fi - 3201, // 672 - se-no - 3206, // 673 - se-se - 3211, // 674 - seh - 3214, // 675 - seh-mz - 3220, // 676 - ses - 3223, // 677 - ses-ml - 3229, // 678 - sg - 3231, // 679 - sg-cf - 3236, // 680 - shi - 3239, // 681 - shi-latn - 3247, // 682 - shi-latn-ma - 3258, // 683 - shi-tfng - 3266, // 684 - shi-tfng-ma - 3277, // 685 - si - 3279, // 686 - si-lk - 3284, // 687 - sk - 3286, // 688 - sk-sk - 3291, // 689 - sl - 3293, // 690 - sl-si - 3298, // 691 - sma - 3301, // 692 - sma-no - 3307, // 693 - sma-se - 3313, // 694 - smj - 3316, // 695 - smj-no - 3322, // 696 - smj-se - 3328, // 697 - smn - 3331, // 698 - smn-fi - 3337, // 699 - sms - 3340, // 700 - sms-fi - 3346, // 701 - sn - 3348, // 702 - sn-latn - 3355, // 703 - sn-latn-zw - 3365, // 704 - so - 3367, // 705 - so-dj - 3372, // 706 - so-et - 3377, // 707 - so-ke - 3382, // 708 - so-so - 3387, // 709 - sq - 3389, // 710 - sq-al - 3394, // 711 - sq-mk - 3399, // 712 - sq-xk - 3404, // 713 - sr - 3406, // 714 - sr-cyrl - 3413, // 715 - sr-cyrl-ba - 3423, // 716 - sr-cyrl-cs - 3433, // 717 - sr-cyrl-me - 3443, // 718 - sr-cyrl-rs - 3453, // 719 - sr-cyrl-xk - 3463, // 720 - sr-latn - 3470, // 721 - sr-latn-ba - 3480, // 722 - sr-latn-cs - 3490, // 723 - sr-latn-me - 3500, // 724 - sr-latn-rs - 3510, // 725 - sr-latn-xk - 3520, // 726 - ss - 3522, // 727 - ss-sz - 3527, // 728 - ss-za - 3532, // 729 - ssy - 3535, // 730 - ssy-er - 3541, // 731 - st - 3543, // 732 - st-ls - 3548, // 733 - st-za - 3553, // 734 - sv - 3555, // 735 - sv-ax - 3560, // 736 - sv-fi - 3565, // 737 - sv-se - 3570, // 738 - sw - 3572, // 739 - sw-cd - 3577, // 740 - sw-ke - 3582, // 741 - sw-tz - 3587, // 742 - sw-ug - 3592, // 743 - swc - 3595, // 744 - swc-cd - 3601, // 745 - syr - 3604, // 746 - syr-sy - 3610, // 747 - ta - 3612, // 748 - ta-in - 3617, // 749 - ta-lk - 3622, // 750 - ta-my - 3627, // 751 - ta-sg - 3632, // 752 - te - 3634, // 753 - te-in - 3639, // 754 - teo - 3642, // 755 - teo-ke - 3648, // 756 - teo-ug - 3654, // 757 - tg - 3656, // 758 - tg-cyrl - 3663, // 759 - tg-cyrl-tj - 3673, // 760 - th - 3675, // 761 - th-th - 3680, // 762 - ti - 3682, // 763 - ti-er - 3687, // 764 - ti-et - 3692, // 765 - tig - 3695, // 766 - tig-er - 3701, // 767 - tk - 3703, // 768 - tk-tm - 3708, // 769 - tn - 3710, // 770 - tn-bw - 3715, // 771 - tn-za - 3720, // 772 - to - 3722, // 773 - to-to - 3727, // 774 - tr - 3729, // 775 - tr-cy - 3734, // 776 - tr-tr - 3739, // 777 - ts - 3741, // 778 - ts-za - 3746, // 779 - tt - 3748, // 780 - tt-ru - 3753, // 781 - twq - 3756, // 782 - twq-ne - 3762, // 783 - tzm - 3765, // 784 - tzm-arab - 3773, // 785 - tzm-arab-ma - 3784, // 786 - tzm-latn - 3792, // 787 - tzm-latn-dz - 3803, // 788 - tzm-latn-ma - 3814, // 789 - tzm-tfng - 3822, // 790 - tzm-tfng-ma - 3833, // 791 - ug - 3835, // 792 - ug-cn - 3840, // 793 - uk - 3842, // 794 - uk-ua - 3847, // 795 - ur - 3849, // 796 - ur-in - 3854, // 797 - ur-pk - 3859, // 798 - uz - 3861, // 799 - uz-arab - 3868, // 800 - uz-arab-af - 3878, // 801 - uz-cyrl - 3885, // 802 - uz-cyrl-uz - 3895, // 803 - uz-latn - 3902, // 804 - uz-latn-uz - 3912, // 805 - vai - 3915, // 806 - vai-latn - 3923, // 807 - vai-latn-lr - 3934, // 808 - vai-vaii - 3942, // 809 - vai-vaii-lr - 3953, // 810 - ve - 3955, // 811 - ve-za - 3960, // 812 - vi - 3962, // 813 - vi-vn - 3967, // 814 - vo - 3969, // 815 - vo-001 - 3975, // 816 - vun - 3978, // 817 - vun-tz - 3984, // 818 - wae - 3987, // 819 - wae-ch - 3993, // 820 - wal - 3996, // 821 - wal-et - 4002, // 822 - wo - 4004, // 823 - wo-sn - 4009, // 824 - x-iv_mathan - 4020, // 825 - xh - 4022, // 826 - xh-za - 4027, // 827 - xog - 4030, // 828 - xog-ug - 4036, // 829 - yav - 4039, // 830 - yav-cm - 4045, // 831 - yi - 4047, // 832 - yi-001 - 4053, // 833 - yo - 4055, // 834 - yo-bj - 4060, // 835 - yo-ng - 4065, // 836 - yue - 4068, // 837 - yue-hk - 4074, // 838 - zgh - 4077, // 839 - zgh-tfng - 4085, // 840 - zgh-tfng-ma - 4096, // 841 - zh - 4098, // 842 - zh-chs - 4104, // 843 - zh-cht - 4110, // 844 - zh-cn - 4115, // 845 - zh-cn_phoneb - 4127, // 846 - zh-cn_stroke - 4139, // 847 - zh-hans - 4146, // 848 - zh-hans-hk - 4156, // 849 - zh-hans-mo - 4166, // 850 - zh-hant - 4173, // 851 - zh-hk - 4178, // 852 - zh-hk_radstr - 4190, // 853 - zh-mo - 4195, // 854 - zh-mo_radstr - 4207, // 855 - zh-mo_stroke - 4219, // 856 - zh-sg - 4224, // 857 - zh-sg_phoneb - 4236, // 858 - zh-sg_stroke - 4248, // 859 - zh-tw - 4253, // 860 - zh-tw_pronun - 4265, // 861 - zh-tw_radstr - 4277, // 862 - zu - 4279, // 863 - zu-za - 4284 - }; - - private const int NUMERIC_LOCALE_DATA_COUNT_PER_ROW = 9; - // s_nameIndexToNumericData is mapping from index in s_localeNamesIndices to locale data. - // each row in the table will have the following data: - // Lcid, Ansi codepage, Oem codepage, MAC codepage, EBCDIC codepage, Geo Id, Digit Substitution, specific locale index, Console locale index - private static readonly int[] s_nameIndexToNumericData = new int[] - { - // Lcid, Ansi CP, Oem CP, MAC CP, EBCDIC CP, Geo Id, digit substitution, Specific culture index, keyboard Id, Console locale index // index - locale name - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x49 , 1 , 3 , 240 , // 0 - aa - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x3e , 1 , 1 , 240 , // 1 - aa-dj - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x47 , 1 , 2 , 240 , // 2 - aa-er - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x49 , 1 , 3 , 240 , // 3 - aa-et - 0x36 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd1 , 1 , 6 , 6 , // 4 - af - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xfe , 1 , 5 , 240 , // 5 - af-na - 0x436 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd1 , 1 , 6 , 6 , // 6 - af-za - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 8 , 240 , // 7 - agq - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 8 , 240 , // 8 - agq-cm - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x59 , 1 , 10 , 240 , // 9 - ak - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x59 , 1 , 10 , 240 , // 10 - ak-gh - 0x5e , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x49 , 1 , 12 , 143 , // 11 - am - 0x45e , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x49 , 1 , 12 , 143 , // 12 - am-et - 0x1 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xcd , 0 , 33 , 143 , // 13 - ar - 0x1000 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x989e, 0 , 14 , 240 , // 14 - ar-001 - 0x3801 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xe0 , 0 , 15 , 143 , // 15 - ar-ae - 0x3c01 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x11 , 0 , 16 , 143 , // 16 - ar-bh - 0x1000 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x3e , 0 , 17 , 240 , // 17 - ar-dj - 0x1401 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x4 , 1 , 18 , 300 , // 18 - ar-dz - 0xc01 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x43 , 0 , 19 , 143 , // 19 - ar-eg - 0x1000 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x47 , 0 , 20 , 240 , // 20 - ar-er - 0x1000 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x75 , 0 , 21 , 240 , // 21 - ar-il - 0x801 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x79 , 0 , 22 , 143 , // 22 - ar-iq - 0x2c01 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x7e , 0 , 23 , 143 , // 23 - ar-jo - 0x1000 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x32 , 0 , 24 , 240 , // 24 - ar-km - 0x3401 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x88 , 0 , 25 , 143 , // 25 - ar-kw - 0x3001 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x8b , 0 , 26 , 143 , // 26 - ar-lb - 0x1001 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x94 , 1 , 27 , 143 , // 27 - ar-ly - 0x1801 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x9f , 1 , 28 , 300 , // 28 - ar-ma - 0x1000 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xa2 , 0 , 29 , 240 , // 29 - ar-mr - 0x2001 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xa4 , 0 , 30 , 143 , // 30 - ar-om - 0x1000 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xb8 , 0 , 31 , 240 , // 31 - ar-ps - 0x4001 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xc5 , 0 , 32 , 143 , // 32 - ar-qa - 0x401 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xcd , 0 , 33 , 143 , // 33 - ar-sa - 0x1000 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xdb , 0 , 34 , 240 , // 34 - ar-sd - 0x1000 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xd8 , 0 , 35 , 240 , // 35 - ar-so - 0x1000 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x114 , 0 , 36 , 240 , // 36 - ar-ss - 0x2801 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xde , 0 , 37 , 143 , // 37 - ar-sy - 0x1000 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x29 , 0 , 38 , 240 , // 38 - ar-td - 0x1c01 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xea , 1 , 39 , 300 , // 39 - ar-tn - 0x2401 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x105 , 0 , 40 , 143 , // 40 - ar-ye - 0x7a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x2e , 1 , 42 , 42 , // 41 - arn - 0x47a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x2e , 1 , 42 , 42 , // 42 - arn-cl - 0x4d , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 44 , 143 , // 43 - as - 0x44d , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 44 , 143 , // 44 - as-in - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 46 , 240 , // 45 - asa - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 46 , 240 , // 46 - asa-tz - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd9 , 1 , 48 , 240 , // 47 - ast - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd9 , 1 , 48 , 240 , // 48 - ast-es - 0x2c , 0x4e6 , 0x359 , 0x2761, 0x51a9, 0x5 , 1 , 53 , 53 , // 49 - az - 0x742c , 0x4e3 , 0x362 , 0x2717, 0x5190, 0x5 , 1 , 51 , 51 , // 50 - az-cyrl - 0x82c , 0x4e3 , 0x362 , 0x2717, 0x5190, 0x5 , 1 , 51 , 51 , // 51 - az-cyrl-az - 0x782c , 0x4e6 , 0x359 , 0x2761, 0x51a9, 0x5 , 1 , 53 , 53 , // 52 - az-latn - 0x42c , 0x4e6 , 0x359 , 0x2761, 0x51a9, 0x5 , 1 , 53 , 53 , // 53 - az-latn-az - 0x6d , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xcb , 1 , 55 , 55 , // 54 - ba - 0x46d , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xcb , 1 , 55 , 55 , // 55 - ba-ru - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 57 , 240 , // 56 - bas - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 57 , 240 , // 57 - bas-cm - 0x23 , 0x4e3 , 0x362 , 0x2717, 0x1f4 , 0x1d , 1 , 59 , 59 , // 58 - be - 0x423 , 0x4e3 , 0x362 , 0x2717, 0x1f4 , 0x1d , 1 , 59 , 59 , // 59 - be-by - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x107 , 1 , 61 , 240 , // 60 - bem - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x107 , 1 , 61 , 240 , // 61 - bem-zm - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 63 , 240 , // 62 - bez - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 63 , 240 , // 63 - bez-tz - 0x2 , 0x4e3 , 0x362 , 0x2717, 0x5221, 0x23 , 1 , 65 , 65 , // 64 - bg - 0x402 , 0x4e3 , 0x362 , 0x2717, 0x5221, 0x23 , 1 , 65 , 65 , // 65 - bg-bg - 0x66 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xaf , 1 , 67 , 240 , // 66 - bin - 0x466 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xaf , 1 , 67 , 240 , // 67 - bin-ng - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9d , 1 , 70 , 240 , // 68 - bm - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9d , 1 , 70 , 240 , // 69 - bm-latn - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9d , 1 , 70 , 240 , // 70 - bm-latn-ml - 0x45 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x17 , 1 , 72 , 143 , // 71 - bn - 0x845 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x17 , 1 , 72 , 143 , // 72 - bn-bd - 0x445 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 73 , 143 , // 73 - bn-in - 0x51 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2d , 1 , 75 , 143 , // 74 - bo - 0x451 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2d , 1 , 75 , 143 , // 75 - bo-cn - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 76 , 240 , // 76 - bo-in - 0x7e , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x54 , 1 , 78 , 78 , // 77 - br - 0x47e , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x54 , 1 , 78 , 78 , // 78 - br-fr - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 80 , 240 , // 79 - brx - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 80 , 240 , // 80 - brx-in - 0x781a , 0x4e2 , 0x354 , 0x2762, 0x366 , 0x19 , 1 , 85 , 85 , // 81 - bs - 0x641a , 0x4e3 , 0x357 , 0x2762, 0x366 , 0x19 , 1 , 83 , 83 , // 82 - bs-cyrl - 0x201a , 0x4e3 , 0x357 , 0x2762, 0x366 , 0x19 , 1 , 83 , 83 , // 83 - bs-cyrl-ba - 0x681a , 0x4e2 , 0x354 , 0x2762, 0x366 , 0x19 , 1 , 85 , 85 , // 84 - bs-latn - 0x141a , 0x4e2 , 0x354 , 0x2762, 0x366 , 0x19 , 1 , 85 , 85 , // 85 - bs-latn-ba - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x47 , 1 , 87 , 240 , // 86 - byn - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x47 , 1 , 87 , 240 , // 87 - byn-er - 0x3 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd9 , 1 , 90 , 90 , // 88 - ca - 0x1000 , 0x4e4 , 0x352 , 0x2 , 0x1f4 , 0x8 , 1 , 89 , 240 , // 89 - ca-ad - 0x403 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd9 , 1 , 90 , 90 , // 90 - ca-es - 0x803 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd9 , 1 , 91 , 90 , // 91 - ca-es-valencia - 0x1000 , 0x4e4 , 0x352 , 0x2 , 0x1f4 , 0x54 , 1 , 92 , 240 , // 92 - ca-fr - 0x1000 , 0x4e4 , 0x352 , 0x2 , 0x1f4 , 0x76 , 1 , 93 , 240 , // 93 - ca-it - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xcb , 1 , 95 , 240 , // 94 - ce - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xcb , 1 , 95 , 240 , // 95 - ce-ru - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf0 , 1 , 97 , 240 , // 96 - cgg - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf0 , 1 , 97 , 240 , // 97 - cgg-ug - 0x5c , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf4 , 1 , 100 , 240 , // 98 - chr - 0x7c5c , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf4 , 1 , 100 , 240 , // 99 - chr-cher - 0x45c , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf4 , 1 , 100 , 240 , // 100 - chr-cher-us - 0x83 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x54 , 1 , 102 , 102 , // 101 - co - 0x483 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x54 , 1 , 102 , 102 , // 102 - co-fr - 0x5 , 0x4e2 , 0x354 , 0x272d, 0x1f4 , 0x4b , 1 , 104 , 104 , // 103 - cs - 0x405 , 0x4e2 , 0x354 , 0x272d, 0x1f4 , 0x4b , 1 , 104 , 104 , // 104 - cs-cz - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xcb , 1 , 106 , 240 , // 105 - cu - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xcb , 1 , 106 , 240 , // 106 - cu-ru - 0x52 , 0x4e4 , 0x352 , 0x2710, 0x4f3d, 0xf2 , 1 , 108 , 108 , // 107 - cy - 0x452 , 0x4e4 , 0x352 , 0x2710, 0x4f3d, 0xf2 , 1 , 108 , 108 , // 108 - cy-gb - 0x6 , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0x3d , 1 , 110 , 110 , // 109 - da - 0x406 , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0x3d , 1 , 110 , 110 , // 110 - da-dk - 0x1000 , 0x4e4 , 0x352 , 0x2 , 0x1f4 , 0x5d , 1 , 111 , 240 , // 111 - da-gl - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 113 , 240 , // 112 - dav - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 113 , 240 , // 113 - dav-ke - 0x7 , 0x4e4 , 0x352 , 0x2710, 0x4f31, 0x5e , 1 , 118 , 118 , // 114 - de - 0xc07 , 0x4e4 , 0x352 , 0x2710, 0x4f31, 0xe , 1 , 115 , 115 , // 115 - de-at - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f31, 0x15 , 1 , 116 , 240 , // 116 - de-be - 0x807 , 0x4e4 , 0x352 , 0x2710, 0x4f31, 0xdf , 1 , 117 , 117 , // 117 - de-ch - 0x407 , 0x4e4 , 0x352 , 0x2710, 0x4f31, 0x5e , 1 , 118 , 118 , // 118 - de-de - 0x10407, 0x4e4 , 0x352 , 0x2710, 0x4f31, 0x5e , 1 , 118 , 118 , // 119 - de-de_phoneb - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x76 , 1 , 120 , 240 , // 120 - de-it - 0x1407 , 0x4e4 , 0x352 , 0x2710, 0x4f31, 0x91 , 1 , 121 , 121 , // 121 - de-li - 0x1007 , 0x4e4 , 0x352 , 0x2710, 0x4f31, 0x93 , 1 , 122 , 122 , // 122 - de-lu - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xad , 1 , 124 , 240 , // 123 - dje - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xad , 1 , 124 , 240 , // 124 - dje-ne - 0x7c2e , 0x4e4 , 0x352 , 0x2710, 0x366 , 0x5e , 1 , 126 , 126 , // 125 - dsb - 0x82e , 0x4e4 , 0x352 , 0x2710, 0x366 , 0x5e , 1 , 126 , 126 , // 126 - dsb-de - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 128 , 240 , // 127 - dua - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 128 , 240 , // 128 - dua-cm - 0x65 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xa5 , 1 , 130 , 143 , // 129 - dv - 0x465 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xa5 , 1 , 130 , 143 , // 130 - dv-mv - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd2 , 1 , 132 , 240 , // 131 - dyo - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd2 , 1 , 132 , 240 , // 132 - dyo-sn - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x22 , 2 , 134 , 240 , // 133 - dz - 0xc51 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x22 , 2 , 134 , 240 , // 134 - dz-bt - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 136 , 240 , // 135 - ebu - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 136 , 240 , // 136 - ebu-ke - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x59 , 1 , 138 , 240 , // 137 - ee - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x59 , 1 , 138 , 240 , // 138 - ee-gh - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xe8 , 1 , 139 , 240 , // 139 - ee-tg - 0x8 , 0x4e5 , 0x2e1 , 0x2716, 0x4f31, 0x62 , 1 , 142 , 142 , // 140 - el - 0x1000 , 0x4e5 , 0x2e1 , 0x2716, 0x4f31, 0x3b , 1 , 141 , 240 , // 141 - el-cy - 0x408 , 0x4e5 , 0x2e1 , 0x2716, 0x4f31, 0x62 , 1 , 142 , 142 , // 142 - el-gr - 0x9 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xf4 , 1 , 240 , 240 , // 143 - en - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x989e, 1 , 144 , 240 , // 144 - en-001 - 0x2409 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x993248, 1 , 145 , 145 , // 145 - en-029 - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x292d, 1 , 146 , 240 , // 146 - en-150 - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x2 , 1 , 147 , 240 , // 147 - en-ag - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x12c , 1 , 148 , 240 , // 148 - en-ai - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xa , 1 , 149 , 240 , // 149 - en-as - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xe , 1 , 150 , 240 , // 150 - en-at - 0xc09 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xc , 1 , 151 , 151 , // 151 - en-au - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x12 , 1 , 152 , 240 , // 152 - en-bb - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x15 , 1 , 153 , 240 , // 153 - en-be - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x26 , 1 , 154 , 240 , // 154 - en-bi - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x14 , 1 , 155 , 240 , // 155 - en-bm - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x16 , 1 , 156 , 240 , // 156 - en-bs - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x13 , 1 , 157 , 240 , // 157 - en-bw - 0x2809 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x18 , 1 , 158 , 158 , // 158 - en-bz - 0x1009 , 0x4e4 , 0x352 , 0x2710, 0x25 , 0x27 , 1 , 159 , 159 , // 159 - en-ca - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x137 , 1 , 160 , 240 , // 160 - en-cc - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xdf , 1 , 161 , 240 , // 161 - en-ch - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x138 , 1 , 162 , 240 , // 162 - en-ck - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x31 , 1 , 163 , 240 , // 163 - en-cm - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x135 , 1 , 164 , 240 , // 164 - en-cx - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x3b , 1 , 165 , 240 , // 165 - en-cy - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x5e , 1 , 166 , 240 , // 166 - en-de - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x3d , 1 , 167 , 240 , // 167 - en-dk - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x3f , 1 , 168 , 240 , // 168 - en-dm - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x47 , 1 , 169 , 240 , // 169 - en-er - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x4d , 1 , 170 , 240 , // 170 - en-fi - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x4e , 1 , 171 , 240 , // 171 - en-fj - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x13b , 1 , 172 , 240 , // 172 - en-fk - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x50 , 1 , 173 , 240 , // 173 - en-fm - 0x809 , 0x4e4 , 0x352 , 0x2710, 0x4f3d, 0xf2 , 1 , 174 , 174 , // 174 - en-gb - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x5b , 1 , 175 , 240 , // 175 - en-gd - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x144 , 1 , 176 , 240 , // 176 - en-gg - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x59 , 1 , 177 , 240 , // 177 - en-gh - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x5a , 1 , 178 , 240 , // 178 - en-gi - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x56 , 1 , 179 , 240 , // 179 - en-gm - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x142 , 1 , 180 , 240 , // 180 - en-gu - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x65 , 1 , 181 , 240 , // 181 - en-gy - 0x3c09 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x68 , 1 , 182 , 240 , // 182 - en-hk - 0x3809 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x6f , 1 , 183 , 240 , // 183 - en-id - 0x1809 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x44 , 1 , 184 , 184 , // 184 - en-ie - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x75 , 1 , 185 , 240 , // 185 - en-il - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x3b16, 1 , 186 , 240 , // 186 - en-im - 0x4009 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0x71 , 1 , 187 , 187 , // 187 - en-in - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x72 , 1 , 188 , 240 , // 188 - en-io - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x148 , 1 , 189 , 240 , // 189 - en-je - 0x2009 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x7c , 1 , 190 , 190 , // 190 - en-jm - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x81 , 1 , 191 , 240 , // 191 - en-ke - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x85 , 1 , 192 , 240 , // 192 - en-ki - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xcf , 1 , 193 , 240 , // 193 - en-kn - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x133 , 1 , 194 , 240 , // 194 - en-ky - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xda , 1 , 195 , 240 , // 195 - en-lc - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x8e , 1 , 196 , 240 , // 196 - en-lr - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x92 , 1 , 197 , 240 , // 197 - en-ls - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x95 , 1 , 198 , 240 , // 198 - en-mg - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xc7 , 1 , 199 , 240 , // 199 - en-mh - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x97 , 1 , 200 , 240 , // 200 - en-mo - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x151 , 1 , 201 , 240 , // 201 - en-mp - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x14c , 1 , 202 , 240 , // 202 - en-ms - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xa3 , 1 , 203 , 240 , // 203 - en-mt - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xa0 , 1 , 204 , 240 , // 204 - en-mu - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x9c , 1 , 205 , 240 , // 205 - en-mw - 0x4409 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xa7 , 1 , 206 , 206 , // 206 - en-my - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xfe , 1 , 207 , 240 , // 207 - en-na - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x150 , 1 , 208 , 240 , // 208 - en-nf - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xaf , 1 , 209 , 240 , // 209 - en-ng - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xb0 , 1 , 210 , 240 , // 210 - en-nl - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xb4 , 1 , 211 , 240 , // 211 - en-nr - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x14f , 1 , 212 , 240 , // 212 - en-nu - 0x1409 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xb7 , 1 , 213 , 213 , // 213 - en-nz - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xc2 , 1 , 214 , 240 , // 214 - en-pg - 0x3409 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0xc9 , 1 , 215 , 215 , // 215 - en-ph - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xbe , 1 , 216 , 240 , // 216 - en-pk - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x153 , 1 , 217 , 240 , // 217 - en-pn - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xca , 1 , 218 , 240 , // 218 - en-pr - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xc3 , 1 , 219 , 240 , // 219 - en-pw - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xcc , 1 , 220 , 240 , // 220 - en-rw - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x1e , 1 , 221 , 240 , // 221 - en-sb - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd0 , 1 , 222 , 240 , // 222 - en-sc - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xdb , 1 , 223 , 240 , // 223 - en-sd - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xdd , 1 , 224 , 240 , // 224 - en-se - 0x4809 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xd7 , 1 , 225 , 225 , // 225 - en-sg - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x157 , 1 , 226 , 240 , // 226 - en-sh - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd4 , 1 , 227 , 240 , // 227 - en-si - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd5 , 1 , 228 , 240 , // 228 - en-sl - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x114 , 1 , 229 , 240 , // 229 - en-ss - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x78f7, 1 , 230 , 240 , // 230 - en-sx - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x104 , 1 , 231 , 240 , // 231 - en-sz - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x15d , 1 , 232 , 240 , // 232 - en-tc - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x15b , 1 , 233 , 240 , // 233 - en-tk - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xe7 , 1 , 234 , 240 , // 234 - en-to - 0x2c09 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xe1 , 1 , 235 , 235 , // 235 - en-tt - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xec , 1 , 236 , 240 , // 236 - en-tv - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xef , 1 , 237 , 240 , // 237 - en-tz - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xf0 , 1 , 238 , 240 , // 238 - en-ug - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x9a55d40, 1 , 239 , 240 , // 239 - en-um - 0x409 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xf4 , 1 , 240 , 240 , // 240 - en-us - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xf8 , 1 , 241 , 240 , // 241 - en-vc - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x15f , 1 , 242 , 240 , // 242 - en-vg - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xfc , 1 , 243 , 240 , // 243 - en-vi - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xae , 1 , 244 , 240 , // 244 - en-vu - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x103 , 1 , 245 , 240 , // 245 - en-ws - 0x1c09 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0xd1 , 1 , 246 , 246 , // 246 - en-za - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x107 , 1 , 247 , 240 , // 247 - en-zm - 0x3009 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0x108 , 1 , 248 , 248 , // 248 - en-zw - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x989e, 1 , 250 , 240 , // 249 - eo - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x989e, 1 , 250 , 240 , // 250 - eo-001 - 0xa , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xd9 , 1 , 262 , 262 , // 251 - es - 0x580a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x9a55d41, 1 , 252 , 240 , // 252 - es-419 - 0x2c0a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xb , 1 , 253 , 253 , // 253 - es-ar - 0x400a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x1a , 1 , 254 , 254 , // 254 - es-bo - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x20 , 1 , 255 , 240 , // 255 - es-br - 0x340a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x2e , 1 , 256 , 256 , // 256 - es-cl - 0x240a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x33 , 1 , 257 , 257 , // 257 - es-co - 0x140a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x36 , 1 , 258 , 258 , // 258 - es-cr - 0x5c0a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x38 , 1 , 259 , 240 , // 259 - es-cu - 0x1c0a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x41 , 1 , 260 , 260 , // 260 - es-do - 0x300a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x42 , 1 , 261 , 261 , // 261 - es-ec - 0xc0a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xd9 , 1 , 262 , 262 , // 262 - es-es - 0x40a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xd9 , 1 , 263 , 263 , // 263 - es-es_tradnl - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x45 , 1 , 264 , 240 , // 264 - es-gq - 0x100a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x63 , 1 , 265 , 265 , // 265 - es-gt - 0x480a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x6a , 1 , 266 , 266 , // 266 - es-hn - 0x80a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xa6 , 1 , 267 , 267 , // 267 - es-mx - 0x4c0a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xb6 , 1 , 268 , 268 , // 268 - es-ni - 0x180a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xc0 , 1 , 269 , 269 , // 269 - es-pa - 0x280a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xbb , 1 , 270 , 270 , // 270 - es-pe - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xc9 , 1 , 271 , 240 , // 271 - es-ph - 0x500a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xca , 1 , 272 , 272 , // 272 - es-pr - 0x3c0a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xb9 , 1 , 273 , 273 , // 273 - es-py - 0x440a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x48 , 1 , 274 , 274 , // 274 - es-sv - 0x540a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xf4 , 1 , 275 , 275 , // 275 - es-us - 0x380a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xf6 , 1 , 276 , 276 , // 276 - es-uy - 0x200a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xf9 , 1 , 277 , 277 , // 277 - es-ve - 0x25 , 0x4e9 , 0x307 , 0x272d, 0x1f4 , 0x46 , 1 , 279 , 279 , // 278 - et - 0x425 , 0x4e9 , 0x307 , 0x272d, 0x1f4 , 0x46 , 1 , 279 , 279 , // 279 - et-ee - 0x2d , 0x4e4 , 0x352 , 0x2 , 0x1f4 , 0xd9 , 1 , 281 , 240 , // 280 - eu - 0x42d , 0x4e4 , 0x352 , 0x2 , 0x1f4 , 0xd9 , 1 , 281 , 240 , // 281 - eu-es - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 283 , 240 , // 282 - ewo - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 283 , 240 , // 283 - ewo-cm - 0x29 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x74 , 0 , 285 , 143 , // 284 - fa - 0x429 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x74 , 0 , 285 , 143 , // 285 - fa-ir - 0x67 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xd2 , 1 , 290 , 290 , // 286 - ff - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x31 , 1 , 287 , 240 , // 287 - ff-cm - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x64 , 1 , 288 , 240 , // 288 - ff-gn - 0x7c67 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xd2 , 1 , 290 , 290 , // 289 - ff-latn - 0x867 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xd2 , 1 , 290 , 290 , // 290 - ff-latn-sn - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xa2 , 1 , 291 , 240 , // 291 - ff-mr - 0x467 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xaf , 1 , 292 , 240 , // 292 - ff-ng - 0xb , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0x4d , 1 , 294 , 294 , // 293 - fi - 0x40b , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0x4d , 1 , 294 , 294 , // 294 - fi-fi - 0x64 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0xc9 , 1 , 296 , 296 , // 295 - fil - 0x464 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0xc9 , 1 , 296 , 296 , // 296 - fil-ph - 0x38 , 0x4e4 , 0x352 , 0x275f, 0x4f35, 0x51 , 1 , 299 , 299 , // 297 - fo - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x3d , 1 , 298 , 240 , // 298 - fo-dk - 0x438 , 0x4e4 , 0x352 , 0x275f, 0x4f35, 0x51 , 1 , 299 , 299 , // 299 - fo-fo - 0xc , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x54 , 1 , 316 , 316 , // 300 - fr - 0x1c0c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x993248, 1 , 301 , 316 , // 301 - fr-029 - 0x80c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x15 , 1 , 302 , 302 , // 302 - fr-be - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xf5 , 1 , 303 , 240 , // 303 - fr-bf - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x26 , 1 , 304 , 240 , // 304 - fr-bi - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x1c , 1 , 305 , 240 , // 305 - fr-bj - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x9a55c4f, 1 , 306 , 240 , // 306 - fr-bl - 0xc0c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x27 , 1 , 307 , 307 , // 307 - fr-ca - 0x240c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x2c , 1 , 308 , 240 , // 308 - fr-cd - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x37 , 1 , 309 , 240 , // 309 - fr-cf - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x2b , 1 , 310 , 240 , // 310 - fr-cg - 0x100c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xdf , 1 , 311 , 311 , // 311 - fr-ch - 0x300c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x77 , 1 , 312 , 240 , // 312 - fr-ci - 0x2c0c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x31 , 1 , 313 , 240 , // 313 - fr-cm - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x3e , 1 , 314 , 240 , // 314 - fr-dj - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x4 , 1 , 315 , 240 , // 315 - fr-dz - 0x40c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x54 , 1 , 316 , 316 , // 316 - fr-fr - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x57 , 1 , 317 , 240 , // 317 - fr-ga - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x13d , 1 , 318 , 240 , // 318 - fr-gf - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x64 , 1 , 319 , 240 , // 319 - fr-gn - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x141 , 1 , 320 , 240 , // 320 - fr-gp - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x45 , 1 , 321 , 240 , // 321 - fr-gq - 0x3c0c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x67 , 1 , 322 , 240 , // 322 - fr-ht - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x32 , 1 , 323 , 240 , // 323 - fr-km - 0x140c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x93 , 1 , 324 , 324 , // 324 - fr-lu - 0x380c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x9f , 1 , 325 , 240 , // 325 - fr-ma - 0x180c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x9e , 1 , 326 , 326 , // 326 - fr-mc - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x7bda, 1 , 327 , 240 , // 327 - fr-mf - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x95 , 1 , 328 , 240 , // 328 - fr-mg - 0x340c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x9d , 1 , 329 , 240 , // 329 - fr-ml - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x14a , 1 , 330 , 240 , // 330 - fr-mq - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xa2 , 1 , 331 , 240 , // 331 - fr-mr - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xa0 , 1 , 332 , 240 , // 332 - fr-mu - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x14e , 1 , 333 , 240 , // 333 - fr-nc - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xad , 1 , 334 , 240 , // 334 - fr-ne - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x13e , 1 , 335 , 240 , // 335 - fr-pf - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xce , 1 , 336 , 240 , // 336 - fr-pm - 0x200c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xc6 , 1 , 337 , 240 , // 337 - fr-re - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xcc , 1 , 338 , 240 , // 338 - fr-rw - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xd0 , 1 , 339 , 240 , // 339 - fr-sc - 0x280c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xd2 , 1 , 340 , 240 , // 340 - fr-sn - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xde , 1 , 341 , 240 , // 341 - fr-sy - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x29 , 1 , 342 , 240 , // 342 - fr-td - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xe8 , 1 , 343 , 240 , // 343 - fr-tg - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xea , 1 , 344 , 240 , // 344 - fr-tn - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xae , 1 , 345 , 240 , // 345 - fr-vu - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x160 , 1 , 346 , 240 , // 346 - fr-wf - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x14b , 1 , 347 , 240 , // 347 - fr-yt - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x76 , 1 , 349 , 240 , // 348 - fur - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x76 , 1 , 349 , 240 , // 349 - fur-it - 0x62 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xb0 , 1 , 351 , 351 , // 350 - fy - 0x462 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xb0 , 1 , 351 , 351 , // 351 - fy-nl - 0x3c , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x44 , 1 , 353 , 353 , // 352 - ga - 0x83c , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x44 , 1 , 353 , 353 , // 353 - ga-ie - 0x91 , 0x4e4 , 0x352 , 0x2710, 0x4f3d, 0xf2 , 1 , 355 , 355 , // 354 - gd - 0x491 , 0x4e4 , 0x352 , 0x2710, 0x4f3d, 0xf2 , 1 , 355 , 355 , // 355 - gd-gb - 0x56 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd9 , 1 , 357 , 357 , // 356 - gl - 0x456 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd9 , 1 , 357 , 357 , // 357 - gl-es - 0x74 , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xb9 , 1 , 359 , 359 , // 358 - gn - 0x474 , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xb9 , 1 , 359 , 359 , // 359 - gn-py - 0x84 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xdf , 1 , 361 , 240 , // 360 - gsw - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xdf , 1 , 361 , 240 , // 361 - gsw-ch - 0x484 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x54 , 1 , 362 , 362 , // 362 - gsw-fr - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x91 , 1 , 363 , 240 , // 363 - gsw-li - 0x47 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 365 , 143 , // 364 - gu - 0x447 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 365 , 143 , // 365 - gu-in - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 367 , 240 , // 366 - guz - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 367 , 240 , // 367 - guz-ke - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x3b16, 1 , 369 , 240 , // 368 - gv - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x3b16, 1 , 369 , 240 , // 369 - gv-im - 0x68 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xaf , 1 , 374 , 374 , // 370 - ha - 0x7c68 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xaf , 1 , 374 , 374 , // 371 - ha-latn - 0x1000 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0x59 , 1 , 372 , 240 , // 372 - ha-latn-gh - 0x1000 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0xad , 1 , 373 , 240 , // 373 - ha-latn-ne - 0x468 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xaf , 1 , 374 , 374 , // 374 - ha-latn-ng - 0x75 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xf4 , 1 , 376 , 376 , // 375 - haw - 0x475 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xf4 , 1 , 376 , 376 , // 376 - haw-us - 0xd , 0x4e7 , 0x35e , 0x2715, 0x1f4 , 0x75 , 1 , 378 , 143 , // 377 - he - 0x40d , 0x4e7 , 0x35e , 0x2715, 0x1f4 , 0x75 , 1 , 378 , 143 , // 378 - he-il - 0x39 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 380 , 143 , // 379 - hi - 0x439 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 380 , 143 , // 380 - hi-in - 0x1a , 0x4e2 , 0x354 , 0x2762, 0x1f4 , 0x6c , 1 , 383 , 383 , // 381 - hr - 0x101a , 0x4e2 , 0x354 , 0x2762, 0x366 , 0x19 , 1 , 382 , 382 , // 382 - hr-ba - 0x41a , 0x4e2 , 0x354 , 0x2762, 0x1f4 , 0x6c , 1 , 383 , 383 , // 383 - hr-hr - 0x2e , 0x4e4 , 0x352 , 0x2710, 0x366 , 0x5e , 1 , 385 , 385 , // 384 - hsb - 0x42e , 0x4e4 , 0x352 , 0x2710, 0x366 , 0x5e , 1 , 385 , 385 , // 385 - hsb-de - 0xe , 0x4e2 , 0x354 , 0x272d, 0x1f4 , 0x6d , 1 , 387 , 387 , // 386 - hu - 0x40e , 0x4e2 , 0x354 , 0x272d, 0x1f4 , 0x6d , 1 , 387 , 387 , // 387 - hu-hu - 0x1040e, 0x4e2 , 0x354 , 0x272d, 0x1f4 , 0x6d , 1 , 387 , 387 , // 388 - hu-hu_technl - 0x2b , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x7 , 1 , 390 , 390 , // 389 - hy - 0x42b , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x7 , 1 , 390 , 390 , // 390 - hy-am - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x54 , 1 , 393 , 240 , // 391 - ia - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x989e, 1 , 392 , 240 , // 392 - ia-001 - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x54 , 1 , 393 , 240 , // 393 - ia-fr - 0x69 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xaf , 1 , 395 , 240 , // 394 - ibb - 0x469 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xaf , 1 , 395 , 240 , // 395 - ibb-ng - 0x21 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x6f , 1 , 397 , 397 , // 396 - id - 0x421 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x6f , 1 , 397 , 397 , // 397 - id-id - 0x70 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xaf , 1 , 399 , 399 , // 398 - ig - 0x470 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xaf , 1 , 399 , 399 , // 399 - ig-ng - 0x78 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2d , 1 , 401 , 143 , // 400 - ii - 0x478 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2d , 1 , 401 , 143 , // 401 - ii-cn - 0xf , 0x4e4 , 0x352 , 0x275f, 0x5187, 0x6e , 1 , 403 , 403 , // 402 - is - 0x40f , 0x4e4 , 0x352 , 0x275f, 0x5187, 0x6e , 1 , 403 , 403 , // 403 - is-is - 0x10 , 0x4e4 , 0x352 , 0x2710, 0x4f38, 0x76 , 1 , 406 , 406 , // 404 - it - 0x810 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xdf , 1 , 405 , 405 , // 405 - it-ch - 0x410 , 0x4e4 , 0x352 , 0x2710, 0x4f38, 0x76 , 1 , 406 , 406 , // 406 - it-it - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f38, 0xd6 , 1 , 407 , 240 , // 407 - it-sm - 0x5d , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0x27 , 1 , 412 , 412 , // 408 - iu - 0x785d , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x27 , 1 , 410 , 143 , // 409 - iu-cans - 0x45d , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x27 , 1 , 410 , 143 , // 410 - iu-cans-ca - 0x7c5d , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0x27 , 1 , 412 , 412 , // 411 - iu-latn - 0x85d , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0x27 , 1 , 412 , 412 , // 412 - iu-latn-ca - 0x11 , 0x3a4 , 0x3a4 , 0x2711, 0x4f42, 0x7a , 1 , 414 , 414 , // 413 - ja - 0x411 , 0x3a4 , 0x3a4 , 0x2711, 0x4f42, 0x7a , 1 , 414 , 414 , // 414 - ja-jp - 0x40411, 0x3a4 , 0x3a4 , 0x2711, 0x4f42, 0x7a , 1 , 414 , 414 , // 415 - ja-jp_radstr - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 417 , 240 , // 416 - jgo - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 417 , 240 , // 417 - jgo-cm - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 419 , 240 , // 418 - jmc - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 419 , 240 , // 419 - jmc-tz - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x6f , 1 , 424 , 424 , // 420 - jv - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x6f , 1 , 422 , 424 , // 421 - jv-java - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x6f , 1 , 422 , 424 , // 422 - jv-java-id - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x6f , 1 , 424 , 424 , // 423 - jv-latn - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x6f , 1 , 424 , 424 , // 424 - jv-latn-id - 0x37 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x58 , 1 , 426 , 426 , // 425 - ka - 0x437 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x58 , 1 , 426 , 426 , // 426 - ka-ge - 0x10437, 0x0 , 0x1 , 0x2 , 0x1f4 , 0x58 , 1 , 426 , 426 , // 427 - ka-ge_modern - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x4 , 1 , 429 , 240 , // 428 - kab - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x4 , 1 , 429 , 240 , // 429 - kab-dz - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 431 , 240 , // 430 - kam - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 431 , 240 , // 431 - kam-ke - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 433 , 240 , // 432 - kde - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 433 , 240 , // 433 - kde-tz - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x39 , 1 , 435 , 240 , // 434 - kea - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x39 , 1 , 435 , 240 , // 435 - kea-cv - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9d , 1 , 437 , 240 , // 436 - khq - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9d , 1 , 437 , 240 , // 437 - khq-ml - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 439 , 240 , // 438 - ki - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 439 , 240 , // 439 - ki-ke - 0x3f , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x89 , 1 , 441 , 441 , // 440 - kk - 0x43f , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x89 , 1 , 441 , 441 , // 441 - kk-kz - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 443 , 240 , // 442 - kkj - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 443 , 240 , // 443 - kkj-cm - 0x6f , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0x5d , 1 , 445 , 445 , // 444 - kl - 0x46f , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0x5d , 1 , 445 , 445 , // 445 - kl-gl - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 447 , 240 , // 446 - kln - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 447 , 240 , // 447 - kln-ke - 0x53 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x28 , 2 , 449 , 143 , // 448 - km - 0x453 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x28 , 2 , 449 , 143 , // 449 - km-kh - 0x4b , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 451 , 143 , // 450 - kn - 0x44b , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 451 , 143 , // 451 - kn-in - 0x12 , 0x3b5 , 0x3b5 , 0x2713, 0x5161, 0x86 , 1 , 454 , 454 , // 452 - ko - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x83 , 1 , 453 , 240 , // 453 - ko-kp - 0x412 , 0x3b5 , 0x3b5 , 0x2713, 0x5161, 0x86 , 1 , 454 , 454 , // 454 - ko-kr - 0x57 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 456 , 143 , // 455 - kok - 0x457 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 456 , 143 , // 456 - kok-in - 0x71 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xaf , 1 , 458 , 240 , // 457 - kr - 0x471 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xaf , 1 , 458 , 240 , // 458 - kr-ng - 0x60 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 2 , 461 , 240 , // 459 - ks - 0x460 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 2 , 461 , 240 , // 460 - ks-arab - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 2 , 461 , 240 , // 461 - ks-arab-in - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 463 , 187 , // 462 - ks-deva - 0x860 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 463 , 187 , // 463 - ks-deva-in - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 465 , 240 , // 464 - ksb - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 465 , 240 , // 465 - ksb-tz - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 467 , 240 , // 466 - ksf - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 467 , 240 , // 467 - ksf-cm - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x5e , 1 , 469 , 240 , // 468 - ksh - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x5e , 1 , 469 , 240 , // 469 - ksh-de - 0x92 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x79 , 0 , 472 , 143 , // 470 - ku - 0x7c92 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x79 , 0 , 472 , 143 , // 471 - ku-arab - 0x492 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x79 , 0 , 472 , 143 , // 472 - ku-arab-iq - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x74 , 0 , 473 , 240 , // 473 - ku-arab-ir - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf2 , 1 , 475 , 240 , // 474 - kw - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf2 , 1 , 475 , 240 , // 475 - kw-gb - 0x40 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0x82 , 1 , 477 , 477 , // 476 - ky - 0x440 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0x82 , 1 , 477 , 477 , // 477 - ky-kg - 0x76 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0x989e, 1 , 479 , 143 , // 478 - la - 0x476 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0x989e, 1 , 479 , 143 , // 479 - la-001 - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 481 , 240 , // 480 - lag - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 481 , 240 , // 481 - lag-tz - 0x6e , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x93 , 1 , 483 , 483 , // 482 - lb - 0x46e , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x93 , 1 , 483 , 483 , // 483 - lb-lu - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf0 , 1 , 485 , 240 , // 484 - lg - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf0 , 1 , 485 , 240 , // 485 - lg-ug - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf4 , 1 , 487 , 240 , // 486 - lkt - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf4 , 1 , 487 , 240 , // 487 - lkt-us - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2c , 1 , 490 , 240 , // 488 - ln - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9 , 1 , 489 , 240 , // 489 - ln-ao - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2c , 1 , 490 , 240 , // 490 - ln-cd - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x37 , 1 , 491 , 240 , // 491 - ln-cf - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2b , 1 , 492 , 240 , // 492 - ln-cg - 0x54 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x8a , 1 , 494 , 143 , // 493 - lo - 0x454 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x8a , 1 , 494 , 143 , // 494 - lo-la - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x74 , 2 , 497 , 240 , // 495 - lrc - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x79 , 2 , 496 , 240 , // 496 - lrc-iq - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x74 , 2 , 497 , 240 , // 497 - lrc-ir - 0x27 , 0x4e9 , 0x307 , 0x272d, 0x1f4 , 0x8d , 1 , 499 , 499 , // 498 - lt - 0x427 , 0x4e9 , 0x307 , 0x272d, 0x1f4 , 0x8d , 1 , 499 , 499 , // 499 - lt-lt - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2c , 1 , 501 , 240 , // 500 - lu - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2c , 1 , 501 , 240 , // 501 - lu-cd - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 503 , 240 , // 502 - luo - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 503 , 240 , // 503 - luo-ke - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 505 , 240 , // 504 - luy - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 505 , 240 , // 505 - luy-ke - 0x26 , 0x4e9 , 0x307 , 0x272d, 0x1f4 , 0x8c , 1 , 507 , 507 , // 506 - lv - 0x426 , 0x4e9 , 0x307 , 0x272d, 0x1f4 , 0x8c , 1 , 507 , 507 , // 507 - lv-lv - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 509 , 240 , // 508 - mas - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 509 , 240 , // 509 - mas-ke - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 510 , 240 , // 510 - mas-tz - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 512 , 240 , // 511 - mer - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 512 , 240 , // 512 - mer-ke - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xa0 , 1 , 514 , 240 , // 513 - mfe - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xa0 , 1 , 514 , 240 , // 514 - mfe-mu - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x95 , 1 , 516 , 240 , // 515 - mg - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x95 , 1 , 516 , 240 , // 516 - mg-mg - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xa8 , 1 , 518 , 240 , // 517 - mgh - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xa8 , 1 , 518 , 240 , // 518 - mgh-mz - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 520 , 240 , // 519 - mgo - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 520 , 240 , // 520 - mgo-cm - 0x81 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xb7 , 1 , 522 , 522 , // 521 - mi - 0x481 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xb7 , 1 , 522 , 522 , // 522 - mi-nz - 0x2f , 0x4e3 , 0x362 , 0x2717, 0x1f4 , 0x4ca2, 1 , 524 , 524 , // 523 - mk - 0x42f , 0x4e3 , 0x362 , 0x2717, 0x1f4 , 0x4ca2, 1 , 524 , 524 , // 524 - mk-mk - 0x4c , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 526 , 143 , // 525 - ml - 0x44c , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 526 , 143 , // 526 - ml-in - 0x50 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0x9a , 1 , 529 , 529 , // 527 - mn - 0x7850 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0x9a , 1 , 529 , 529 , // 528 - mn-cyrl - 0x450 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0x9a , 1 , 529 , 529 , // 529 - mn-mn - 0x7c50 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2d , 1 , 531 , 531 , // 530 - mn-mong - 0x850 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2d , 1 , 531 , 531 , // 531 - mn-mong-cn - 0xc50 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9a , 1 , 532 , 532 , // 532 - mn-mong-mn - 0x58 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 534 , 187 , // 533 - mni - 0x458 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 534 , 187 , // 534 - mni-in - 0x7c , 0x4e4 , 0x352 , 0x2710, 0x25 , 0x27 , 1 , 536 , 240 , // 535 - moh - 0x47c , 0x4e4 , 0x352 , 0x2710, 0x25 , 0x27 , 1 , 536 , 240 , // 536 - moh-ca - 0x4e , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 538 , 143 , // 537 - mr - 0x44e , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 538 , 143 , // 538 - mr-in - 0x3e , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xa7 , 1 , 541 , 541 , // 539 - ms - 0x83e , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x25 , 1 , 540 , 540 , // 540 - ms-bn - 0x43e , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xa7 , 1 , 541 , 541 , // 541 - ms-my - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd7 , 1 , 542 , 240 , // 542 - ms-sg - 0x3a , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xa3 , 1 , 544 , 544 , // 543 - mt - 0x43a , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xa3 , 1 , 544 , 544 , // 544 - mt-mt - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 546 , 240 , // 545 - mua - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 546 , 240 , // 546 - mua-cm - 0x55 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x1b , 2 , 548 , 240 , // 547 - my - 0x455 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x1b , 2 , 548 , 240 , // 548 - my-mm - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x74 , 2 , 550 , 240 , // 549 - mzn - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x74 , 2 , 550 , 240 , // 550 - mzn-ir - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xfe , 1 , 552 , 240 , // 551 - naq - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xfe , 1 , 552 , 240 , // 552 - naq-na - 0x7c14 , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0xb1 , 1 , 554 , 554 , // 553 - nb - 0x414 , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0xb1 , 1 , 554 , 554 , // 554 - nb-no - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0xdc , 1 , 555 , 240 , // 555 - nb-sj - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x108 , 1 , 557 , 240 , // 556 - nd - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x108 , 1 , 557 , 240 , // 557 - nd-zw - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x5e , 1 , 559 , 240 , // 558 - nds - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x5e , 1 , 559 , 240 , // 559 - nds-de - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xb0 , 1 , 560 , 240 , // 560 - nds-nl - 0x61 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xb2 , 1 , 563 , 143 , // 561 - ne - 0x861 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 2 , 562 , 240 , // 562 - ne-in - 0x461 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xb2 , 1 , 563 , 143 , // 563 - ne-np - 0x13 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xb0 , 1 , 569 , 569 , // 564 - nl - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x12e , 1 , 565 , 240 , // 565 - nl-aw - 0x813 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x15 , 1 , 566 , 566 , // 566 - nl-be - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x9a55d42, 1 , 567 , 240 , // 567 - nl-bq - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x111 , 1 , 568 , 240 , // 568 - nl-cw - 0x413 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xb0 , 1 , 569 , 569 , // 569 - nl-nl - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xb5 , 1 , 570 , 240 , // 570 - nl-sr - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x78f7, 1 , 571 , 240 , // 571 - nl-sx - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 573 , 240 , // 572 - nmg - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 573 , 240 , // 573 - nmg-cm - 0x7814 , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0xb1 , 1 , 575 , 575 , // 574 - nn - 0x814 , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0xb1 , 1 , 575 , 575 , // 575 - nn-no - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 577 , 240 , // 576 - nnh - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 577 , 240 , // 577 - nnh-cm - 0x14 , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0xb1 , 1 , 554 , 554 , // 578 - no - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x64 , 2 , 580 , 143 , // 579 - nqo - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x64 , 2 , 580 , 143 , // 580 - nqo-gn - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd1 , 1 , 582 , 240 , // 581 - nr - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd1 , 1 , 582 , 240 , // 582 - nr-za - 0x6c , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd1 , 1 , 584 , 584 , // 583 - nso - 0x46c , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd1 , 1 , 584 , 584 , // 584 - nso-za - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x114 , 1 , 586 , 240 , // 585 - nus - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x114 , 1 , 586 , 240 , // 586 - nus-ss - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf0 , 1 , 588 , 240 , // 587 - nyn - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf0 , 1 , 588 , 240 , // 588 - nyn-ug - 0x82 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x54 , 1 , 590 , 590 , // 589 - oc - 0x482 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x54 , 1 , 590 , 590 , // 590 - oc-fr - 0x72 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x49 , 1 , 592 , 240 , // 591 - om - 0x472 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x49 , 1 , 592 , 240 , // 592 - om-et - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 593 , 240 , // 593 - om-ke - 0x48 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 595 , 143 , // 594 - or - 0x448 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 595 , 143 , // 595 - or-in - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x58 , 1 , 597 , 240 , // 596 - os - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x58 , 1 , 597 , 240 , // 597 - os-ge - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xcb , 1 , 598 , 240 , // 598 - os-ru - 0x46 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 602 , 143 , // 599 - pa - 0x7c46 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xbe , 2 , 601 , 143 , // 600 - pa-arab - 0x846 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xbe , 2 , 601 , 143 , // 601 - pa-arab-pk - 0x446 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 602 , 143 , // 602 - pa-in - 0x79 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x993248, 1 , 604 , 145 , // 603 - pap - 0x479 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x993248, 1 , 604 , 145 , // 604 - pap-029 - 0x15 , 0x4e2 , 0x354 , 0x272d, 0x5190, 0xbf , 1 , 606 , 606 , // 605 - pl - 0x415 , 0x4e2 , 0x354 , 0x272d, 0x5190, 0xbf , 1 , 606 , 606 , // 606 - pl-pl - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x989e, 1 , 608 , 240 , // 607 - prg - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x989e, 1 , 608 , 240 , // 608 - prg-001 - 0x8c , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x3 , 2 , 610 , 143 , // 609 - prs - 0x48c , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x3 , 2 , 610 , 143 , // 610 - prs-af - 0x63 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x3 , 2 , 612 , 143 , // 611 - ps - 0x463 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x3 , 2 , 612 , 143 , // 612 - ps-af - 0x16 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x20 , 1 , 615 , 615 , // 613 - pt - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x9 , 1 , 614 , 240 , // 614 - pt-ao - 0x416 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x20 , 1 , 615 , 615 , // 615 - pt-br - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xdf , 1 , 616 , 240 , // 616 - pt-ch - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x39 , 1 , 617 , 240 , // 617 - pt-cv - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x45 , 1 , 618 , 240 , // 618 - pt-gq - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xc4 , 1 , 619 , 240 , // 619 - pt-gw - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x93 , 1 , 620 , 240 , // 620 - pt-lu - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x97 , 1 , 621 , 240 , // 621 - pt-mo - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xa8 , 1 , 622 , 240 , // 622 - pt-mz - 0x816 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xc1 , 1 , 623 , 623 , // 623 - pt-pt - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xe9 , 1 , 624 , 240 , // 624 - pt-st - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x6f60e7, 1 , 625 , 240 , // 625 - pt-tl - 0x901 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x7c , 1 , 626 , 190 , // 626 - qps-latn-x-sh - 0x501 , 0x4e2 , 0x354 , 0x272d, 0x5190, 0xf4 , 1 , 627 , 627 , // 627 - qps-ploc - 0x5fe , 0x3a4 , 0x3a4 , 0x2711, 0x4f42, 0x7a , 1 , 628 , 628 , // 628 - qps-ploca - 0x9ff , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xcd , 0 , 629 , 143 , // 629 - qps-plocm - 0x86 , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x63 , 1 , 632 , 632 , // 630 - quc - 0x7c86 , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x63 , 1 , 632 , 632 , // 631 - quc-latn - 0x486 , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x63 , 1 , 632 , 632 , // 632 - quc-latn-gt - 0x6b , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x1a , 1 , 634 , 634 , // 633 - quz - 0x46b , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x1a , 1 , 634 , 634 , // 634 - quz-bo - 0x86b , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x42 , 1 , 635 , 635 , // 635 - quz-ec - 0xc6b , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xbb , 1 , 636 , 636 , // 636 - quz-pe - 0x17 , 0x4e4 , 0x352 , 0x2710, 0x4f31, 0xdf , 1 , 638 , 638 , // 637 - rm - 0x417 , 0x4e4 , 0x352 , 0x2710, 0x4f31, 0xdf , 1 , 638 , 638 , // 638 - rm-ch - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x26 , 1 , 640 , 240 , // 639 - rn - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x26 , 1 , 640 , 240 , // 640 - rn-bi - 0x18 , 0x4e2 , 0x354 , 0x272d, 0x5190, 0xc8 , 1 , 643 , 643 , // 641 - ro - 0x818 , 0x4e2 , 0x354 , 0x2 , 0x1f4 , 0x98 , 1 , 642 , 240 , // 642 - ro-md - 0x418 , 0x4e2 , 0x354 , 0x272d, 0x5190, 0xc8 , 1 , 643 , 643 , // 643 - ro-ro - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 645 , 240 , // 644 - rof - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 645 , 240 , // 645 - rof-tz - 0x19 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xcb , 1 , 651 , 651 , // 646 - ru - 0x1000 , 0x4e3 , 0x362 , 0x2 , 0x1f4 , 0x1d , 1 , 647 , 240 , // 647 - ru-by - 0x1000 , 0x4e3 , 0x362 , 0x2 , 0x1f4 , 0x82 , 1 , 648 , 240 , // 648 - ru-kg - 0x1000 , 0x4e3 , 0x362 , 0x2 , 0x1f4 , 0x89 , 1 , 649 , 240 , // 649 - ru-kz - 0x819 , 0x4e3 , 0x362 , 0x2 , 0x1f4 , 0x98 , 1 , 650 , 240 , // 650 - ru-md - 0x419 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xcb , 1 , 651 , 651 , // 651 - ru-ru - 0x1000 , 0x4e3 , 0x362 , 0x2 , 0x1f4 , 0xf1 , 1 , 652 , 240 , // 652 - ru-ua - 0x87 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xcc , 1 , 654 , 654 , // 653 - rw - 0x487 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xcc , 1 , 654 , 654 , // 654 - rw-rw - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 656 , 240 , // 655 - rwk - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 656 , 240 , // 656 - rwk-tz - 0x4f , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 658 , 143 , // 657 - sa - 0x44f , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 658 , 143 , // 658 - sa-in - 0x85 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xcb , 1 , 660 , 660 , // 659 - sah - 0x485 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xcb , 1 , 660 , 660 , // 660 - sah-ru - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 662 , 240 , // 661 - saq - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 662 , 240 , // 662 - saq-ke - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 664 , 240 , // 663 - sbp - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 664 , 240 , // 664 - sbp-tz - 0x59 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xbe , 2 , 667 , 143 , // 665 - sd - 0x7c59 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xbe , 2 , 667 , 143 , // 666 - sd-arab - 0x859 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xbe , 2 , 667 , 143 , // 667 - sd-arab-pk - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 669 , 187 , // 668 - sd-deva - 0x459 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 669 , 187 , // 669 - sd-deva-in - 0x3b , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0xb1 , 1 , 672 , 672 , // 670 - se - 0xc3b , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0x4d , 1 , 671 , 671 , // 671 - se-fi - 0x43b , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0xb1 , 1 , 672 , 672 , // 672 - se-no - 0x83b , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0xdd , 1 , 673 , 673 , // 673 - se-se - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xa8 , 1 , 675 , 240 , // 674 - seh - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xa8 , 1 , 675 , 240 , // 675 - seh-mz - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9d , 1 , 677 , 240 , // 676 - ses - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9d , 1 , 677 , 240 , // 677 - ses-ml - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x37 , 1 , 679 , 240 , // 678 - sg - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x37 , 1 , 679 , 240 , // 679 - sg-cf - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9f , 1 , 684 , 240 , // 680 - shi - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9f , 1 , 682 , 240 , // 681 - shi-latn - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9f , 1 , 682 , 240 , // 682 - shi-latn-ma - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9f , 1 , 684 , 240 , // 683 - shi-tfng - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9f , 1 , 684 , 240 , // 684 - shi-tfng-ma - 0x5b , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2a , 1 , 686 , 143 , // 685 - si - 0x45b , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2a , 1 , 686 , 143 , // 686 - si-lk - 0x1b , 0x4e2 , 0x354 , 0x272d, 0x5190, 0x8f , 1 , 688 , 688 , // 687 - sk - 0x41b , 0x4e2 , 0x354 , 0x272d, 0x5190, 0x8f , 1 , 688 , 688 , // 688 - sk-sk - 0x24 , 0x4e2 , 0x354 , 0x272d, 0x5190, 0xd4 , 1 , 690 , 690 , // 689 - sl - 0x424 , 0x4e2 , 0x354 , 0x272d, 0x5190, 0xd4 , 1 , 690 , 690 , // 690 - sl-si - 0x783b , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0xdd , 1 , 693 , 693 , // 691 - sma - 0x183b , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0xb1 , 1 , 692 , 692 , // 692 - sma-no - 0x1c3b , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0xdd , 1 , 693 , 693 , // 693 - sma-se - 0x7c3b , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0xdd , 1 , 696 , 696 , // 694 - smj - 0x103b , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0xb1 , 1 , 695 , 695 , // 695 - smj-no - 0x143b , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0xdd , 1 , 696 , 696 , // 696 - smj-se - 0x703b , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0x4d , 1 , 698 , 698 , // 697 - smn - 0x243b , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0x4d , 1 , 698 , 698 , // 698 - smn-fi - 0x743b , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0x4d , 1 , 700 , 700 , // 699 - sms - 0x203b , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0x4d , 1 , 700 , 700 , // 700 - sms-fi - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x108 , 1 , 703 , 240 , // 701 - sn - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x108 , 1 , 703 , 240 , // 702 - sn-latn - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x108 , 1 , 703 , 240 , // 703 - sn-latn-zw - 0x77 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd8 , 1 , 708 , 240 , // 704 - so - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x3e , 1 , 705 , 240 , // 705 - so-dj - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x49 , 1 , 706 , 240 , // 706 - so-et - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 707 , 240 , // 707 - so-ke - 0x477 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd8 , 1 , 708 , 240 , // 708 - so-so - 0x1c , 0x4e2 , 0x354 , 0x272d, 0x5190, 0x6 , 1 , 710 , 710 , // 709 - sq - 0x41c , 0x4e2 , 0x354 , 0x272d, 0x5190, 0x6 , 1 , 710 , 710 , // 710 - sq-al - 0x1000 , 0x4e2 , 0x354 , 0x272d, 0x5190, 0x4ca2, 1 , 711 , 240 , // 711 - sq-mk - 0x1000 , 0x4e2 , 0x354 , 0x272d, 0x5190, 0x974941, 1 , 712 , 240 , // 712 - sq-xk - 0x7c1a , 0x4e2 , 0x354 , 0x272d, 0x1f4 , 0x10f , 1 , 724 , 724 , // 713 - sr - 0x6c1a , 0x4e3 , 0x357 , 0x2717, 0x5221, 0x10f , 1 , 718 , 718 , // 714 - sr-cyrl - 0x1c1a , 0x4e3 , 0x357 , 0x2717, 0x5221, 0x19 , 1 , 715 , 715 , // 715 - sr-cyrl-ba - 0xc1a , 0x4e3 , 0x357 , 0x2717, 0x5221, 0x10d , 1 , 716 , 716 , // 716 - sr-cyrl-cs - 0x301a , 0x4e3 , 0x357 , 0x2717, 0x5221, 0x10e , 1 , 717 , 717 , // 717 - sr-cyrl-me - 0x281a , 0x4e3 , 0x357 , 0x2717, 0x5221, 0x10f , 1 , 718 , 718 , // 718 - sr-cyrl-rs - 0x1000 , 0x4e3 , 0x357 , 0x2717, 0x5221, 0x974941, 1 , 719 , 240 , // 719 - sr-cyrl-xk - 0x701a , 0x4e2 , 0x354 , 0x272d, 0x1f4 , 0x10f , 1 , 724 , 724 , // 720 - sr-latn - 0x181a , 0x4e2 , 0x354 , 0x2762, 0x366 , 0x19 , 1 , 721 , 721 , // 721 - sr-latn-ba - 0x81a , 0x4e2 , 0x354 , 0x272d, 0x1f4 , 0x10d , 1 , 722 , 722 , // 722 - sr-latn-cs - 0x2c1a , 0x4e2 , 0x354 , 0x272d, 0x1f4 , 0x10e , 1 , 723 , 723 , // 723 - sr-latn-me - 0x241a , 0x4e2 , 0x354 , 0x272d, 0x1f4 , 0x10f , 1 , 724 , 724 , // 724 - sr-latn-rs - 0x1000 , 0x4e2 , 0x354 , 0x272d, 0x1f4 , 0x974941, 1 , 725 , 240 , // 725 - sr-latn-xk - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd1 , 1 , 728 , 240 , // 726 - ss - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x104 , 1 , 727 , 240 , // 727 - ss-sz - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd1 , 1 , 728 , 240 , // 728 - ss-za - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x47 , 1 , 730 , 240 , // 729 - ssy - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x47 , 1 , 730 , 240 , // 730 - ssy-er - 0x30 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd1 , 1 , 733 , 240 , // 731 - st - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x92 , 1 , 732 , 240 , // 732 - st-ls - 0x430 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd1 , 1 , 733 , 240 , // 733 - st-za - 0x1d , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0xdd , 1 , 737 , 737 , // 734 - sv - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0x9906f5, 1 , 735 , 240 , // 735 - sv-ax - 0x81d , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0x4d , 1 , 736 , 736 , // 736 - sv-fi - 0x41d , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0xdd , 1 , 737 , 737 , // 737 - sv-se - 0x41 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0x81 , 1 , 740 , 740 , // 738 - sw - 0x1000 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0x2c , 1 , 739 , 740 , // 739 - sw-cd - 0x441 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0x81 , 1 , 740 , 740 , // 740 - sw-ke - 0x1000 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0xef , 1 , 741 , 240 , // 741 - sw-tz - 0x1000 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0xf0 , 1 , 742 , 240 , // 742 - sw-ug - 0x1000 , 0x0 , 0x1 , 0x0 , 0x1f4 , 0x2c , 1 , 744 , 240 , // 743 - swc - 0x1000 , 0x0 , 0x1 , 0x0 , 0x1f4 , 0x2c , 1 , 744 , 240 , // 744 - swc-cd - 0x5a , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xde , 1 , 746 , 143 , // 745 - syr - 0x45a , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xde , 1 , 746 , 143 , // 746 - syr-sy - 0x49 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 748 , 143 , // 747 - ta - 0x449 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 748 , 143 , // 748 - ta-in - 0x849 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2a , 1 , 749 , 143 , // 749 - ta-lk - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xa7 , 1 , 750 , 240 , // 750 - ta-my - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd7 , 1 , 751 , 240 , // 751 - ta-sg - 0x4a , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 753 , 143 , // 752 - te - 0x44a , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 753 , 143 , // 753 - te-in - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf0 , 1 , 756 , 240 , // 754 - teo - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 755 , 240 , // 755 - teo-ke - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf0 , 1 , 756 , 240 , // 756 - teo-ug - 0x28 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xe4 , 1 , 759 , 759 , // 757 - tg - 0x7c28 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xe4 , 1 , 759 , 759 , // 758 - tg-cyrl - 0x428 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xe4 , 1 , 759 , 759 , // 759 - tg-cyrl-tj - 0x1e , 0x36a , 0x36a , 0x2725, 0x5166, 0xe3 , 1 , 761 , 143 , // 760 - th - 0x41e , 0x36a , 0x36a , 0x2725, 0x5166, 0xe3 , 1 , 761 , 143 , // 761 - th-th - 0x73 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x47 , 1 , 763 , 143 , // 762 - ti - 0x873 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x47 , 1 , 763 , 143 , // 763 - ti-er - 0x473 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x49 , 1 , 764 , 143 , // 764 - ti-et - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x47 , 1 , 766 , 240 , // 765 - tig - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x47 , 1 , 766 , 240 , // 766 - tig-er - 0x42 , 0x4e2 , 0x354 , 0x272d, 0x5190, 0xee , 1 , 768 , 768 , // 767 - tk - 0x442 , 0x4e2 , 0x354 , 0x272d, 0x5190, 0xee , 1 , 768 , 768 , // 768 - tk-tm - 0x32 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd1 , 1 , 771 , 771 , // 769 - tn - 0x832 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x13 , 1 , 770 , 770 , // 770 - tn-bw - 0x432 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd1 , 1 , 771 , 771 , // 771 - tn-za - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xe7 , 1 , 773 , 240 , // 772 - to - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xe7 , 1 , 773 , 240 , // 773 - to-to - 0x1f , 0x4e6 , 0x359 , 0x2761, 0x51a9, 0xeb , 1 , 776 , 776 , // 774 - tr - 0x1000 , 0x4e6 , 0x359 , 0x2761, 0x51a9, 0x3b , 1 , 775 , 240 , // 775 - tr-cy - 0x41f , 0x4e6 , 0x359 , 0x2761, 0x51a9, 0xeb , 1 , 776 , 776 , // 776 - tr-tr - 0x31 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd1 , 1 , 778 , 240 , // 777 - ts - 0x431 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd1 , 1 , 778 , 240 , // 778 - ts-za - 0x44 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xcb , 1 , 780 , 780 , // 779 - tt - 0x444 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xcb , 1 , 780 , 780 , // 780 - tt-ru - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xad , 1 , 782 , 240 , // 781 - twq - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xad , 1 , 782 , 240 , // 782 - twq-ne - 0x5f , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x4 , 1 , 787 , 787 , // 783 - tzm - 0x1000 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x9f , 1 , 785 , 240 , // 784 - tzm-arab - 0x45f , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x9f , 1 , 785 , 240 , // 785 - tzm-arab-ma - 0x7c5f , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x4 , 1 , 787 , 787 , // 786 - tzm-latn - 0x85f , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x4 , 1 , 787 , 787 , // 787 - tzm-latn-dz - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9f , 1 , 788 , 240 , // 788 - tzm-latn-ma - 0x785f , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9f , 1 , 790 , 316 , // 789 - tzm-tfng - 0x105f , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9f , 1 , 790 , 316 , // 790 - tzm-tfng-ma - 0x80 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x2d , 1 , 792 , 143 , // 791 - ug - 0x480 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x2d , 1 , 792 , 143 , // 792 - ug-cn - 0x22 , 0x4e3 , 0x362 , 0x2721, 0x1f4 , 0xf1 , 1 , 794 , 794 , // 793 - uk - 0x422 , 0x4e3 , 0x362 , 0x2721, 0x1f4 , 0xf1 , 1 , 794 , 794 , // 794 - uk-ua - 0x20 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xbe , 1 , 797 , 143 , // 795 - ur - 0x820 , 0x4e8 , 0x2d0 , 0x2 , 0x1f4 , 0x71 , 2 , 796 , 240 , // 796 - ur-in - 0x420 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xbe , 1 , 797 , 143 , // 797 - ur-pk - 0x43 , 0x4e6 , 0x359 , 0x272d, 0x1f4 , 0xf7 , 1 , 804 , 804 , // 798 - uz - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x3 , 2 , 800 , 240 , // 799 - uz-arab - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x3 , 2 , 800 , 240 , // 800 - uz-arab-af - 0x7843 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xf7 , 1 , 802 , 802 , // 801 - uz-cyrl - 0x843 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xf7 , 1 , 802 , 802 , // 802 - uz-cyrl-uz - 0x7c43 , 0x4e6 , 0x359 , 0x272d, 0x1f4 , 0xf7 , 1 , 804 , 804 , // 803 - uz-latn - 0x443 , 0x4e6 , 0x359 , 0x272d, 0x1f4 , 0xf7 , 1 , 804 , 804 , // 804 - uz-latn-uz - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x8e , 1 , 809 , 240 , // 805 - vai - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x8e , 1 , 807 , 240 , // 806 - vai-latn - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x8e , 1 , 807 , 240 , // 807 - vai-latn-lr - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x8e , 1 , 809 , 240 , // 808 - vai-vaii - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x8e , 1 , 809 , 240 , // 809 - vai-vaii-lr - 0x33 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd1 , 1 , 811 , 240 , // 810 - ve - 0x433 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd1 , 1 , 811 , 240 , // 811 - ve-za - 0x2a , 0x4ea , 0x4ea , 0x2710, 0x1f4 , 0xfb , 1 , 813 , 143 , // 812 - vi - 0x42a , 0x4ea , 0x4ea , 0x2710, 0x1f4 , 0xfb , 1 , 813 , 143 , // 813 - vi-vn - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x989e, 1 , 815 , 240 , // 814 - vo - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x989e, 1 , 815 , 240 , // 815 - vo-001 - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 817 , 240 , // 816 - vun - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 817 , 240 , // 817 - vun-tz - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xdf , 1 , 819 , 240 , // 818 - wae - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xdf , 1 , 819 , 240 , // 819 - wae-ch - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x49 , 1 , 821 , 240 , // 820 - wal - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x49 , 1 , 821 , 240 , // 821 - wal-et - 0x88 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xd2 , 1 , 823 , 823 , // 822 - wo - 0x488 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xd2 , 1 , 823 , 823 , // 823 - wo-sn - 0x1007f, 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xf4 , 1 , -1 , -1 , // 824 - x-iv_mathan - 0x34 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd1 , 1 , 826 , 826 , // 825 - xh - 0x434 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd1 , 1 , 826 , 826 , // 826 - xh-za - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf0 , 1 , 828 , 240 , // 827 - xog - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf0 , 1 , 828 , 240 , // 828 - xog-ug - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 830 , 240 , // 829 - yav - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 830 , 240 , // 830 - yav-cm - 0x3d , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x989e, 1 , 832 , 240 , // 831 - yi - 0x43d , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x989e, 1 , 832 , 240 , // 832 - yi-001 - 0x6a , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xaf , 1 , 835 , 835 , // 833 - yo - 0x1000 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0x1c , 1 , 834 , 240 , // 834 - yo-bj - 0x46a , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xaf , 1 , 835 , 835 , // 835 - yo-ng - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x68 , 1 , 837 , 240 , // 836 - yue - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x68 , 1 , 837 , 240 , // 837 - yue-hk - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9f , 1 , 840 , 316 , // 838 - zgh - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9f , 1 , 840 , 316 , // 839 - zgh-tfng - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9f , 1 , 840 , 316 , // 840 - zgh-tfng-ma - 0x7804 , 0x3a8 , 0x3a8 , 0x2718, 0x1f4 , 0x2d , 1 , 844 , 844 , // 841 - zh - 0x4 , 0x3a8 , 0x3a8 , 0x0 , 0x1f4 , 0x2d , 1 , 844 , 844 , // 842 - zh-chs - 0x7c04 , 0x3b6 , 0x3b6 , 0x0 , 0x1f4 , 0x68 , 1 , 851 , 851 , // 843 - zh-cht - 0x804 , 0x3a8 , 0x3a8 , 0x2718, 0x1f4 , 0x2d , 1 , 844 , 844 , // 844 - zh-cn - 0x50804, 0x3a8 , 0x3a8 , 0x2718, 0x1f4 , 0x2d , 1 , 844 , 844 , // 845 - zh-cn_phoneb - 0x20804, 0x3a8 , 0x3a8 , 0x2718, 0x1f4 , 0x2d , 1 , 844 , 844 , // 846 - zh-cn_stroke - 0x4 , 0x3a8 , 0x3a8 , 0x2718, 0x1f4 , 0x2d , 1 , 844 , 844 , // 847 - zh-hans - 0x1000 , 0x3a8 , 0x3a8 , 0x2718, 0x1f4 , 0x68 , 1 , 848 , 240 , // 848 - zh-hans-hk - 0x1000 , 0x3a8 , 0x3a8 , 0x2718, 0x1f4 , 0x97 , 1 , 849 , 240 , // 849 - zh-hans-mo - 0x7c04 , 0x3b6 , 0x3b6 , 0x2712, 0x1f4 , 0x68 , 1 , 851 , 851 , // 850 - zh-hant - 0xc04 , 0x3b6 , 0x3b6 , 0x2712, 0x1f4 , 0x68 , 1 , 851 , 851 , // 851 - zh-hk - 0x40c04, 0x3b6 , 0x3b6 , 0x2712, 0x1f4 , 0x68 , 1 , 851 , 851 , // 852 - zh-hk_radstr - 0x1404 , 0x3b6 , 0x3b6 , 0x2712, 0x1f4 , 0x97 , 1 , 853 , 853 , // 853 - zh-mo - 0x41404, 0x3b6 , 0x3b6 , 0x2712, 0x1f4 , 0x97 , 1 , 853 , 853 , // 854 - zh-mo_radstr - 0x21404, 0x3b6 , 0x3b6 , 0x2712, 0x1f4 , 0x97 , 1 , 853 , 853 , // 855 - zh-mo_stroke - 0x1004 , 0x3a8 , 0x3a8 , 0x2718, 0x1f4 , 0xd7 , 1 , 856 , 856 , // 856 - zh-sg - 0x51004, 0x3a8 , 0x3a8 , 0x2718, 0x1f4 , 0xd7 , 1 , 856 , 856 , // 857 - zh-sg_phoneb - 0x21004, 0x3a8 , 0x3a8 , 0x2718, 0x1f4 , 0xd7 , 1 , 856 , 856 , // 858 - zh-sg_stroke - 0x404 , 0x3b6 , 0x3b6 , 0x2712, 0x1f4 , 0xed , 1 , 859 , 859 , // 859 - zh-tw - 0x30404, 0x3b6 , 0x3b6 , 0x2712, 0x1f4 , 0xed , 1 , 859 , 859 , // 860 - zh-tw_pronun - 0x40404, 0x3b6 , 0x3b6 , 0x2712, 0x1f4 , 0xed , 1 , 859 , 859 , // 861 - zh-tw_radstr - 0x35 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd1 , 1 , 863 , 863 , // 862 - zu - 0x435 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd1 , 1 , 863 , 863 , // 863 - zu-za - }; - - // s_lcids list all supported lcids. used to binary search and we use the index of the matched lcid to - // get the index in s_localeNamesIndices using s_lcidToCultureNameIndices - private static readonly int[] s_lcids = new int[] - { - // Lcid , index - index in c_localeNames - 0x1 , // 0 - 52 - 0x2 , // 1 - 301 - 0x3 , // 2 - 421 - 0x4 , // 3 - 4139 - 0x5 , // 4 - 502 - 0x6 , // 5 - 523 - 0x7 , // 6 - 544 - 0x8 , // 7 - 664 - 0x9 , // 8 - 676 - 0xa , // 9 - 1214 - 0xb , // 10 - 1423 - 0xc , // 11 - 1451 - 0xd , // 12 - 1825 - 0xe , // 13 - 1860 - 0xf , // 14 - 1929 - 0x10 , // 15 - 1936 - 0x11 , // 16 - 1989 - 0x12 , // 17 - 2179 - 0x13 , // 18 - 2685 - 0x14 , // 19 - 2747 - 0x15 , // 20 - 2864 - 0x16 , // 21 - 2897 - 0x17 , // 22 - 3041 - 0x18 , // 23 - 3055 - 0x19 , // 24 - 3076 - 0x1a , // 25 - 1839 - 0x1b , // 26 - 3284 - 0x1c , // 27 - 3387 - 0x1d , // 28 - 3553 - 0x1e , // 29 - 3673 - 0x1f , // 30 - 3727 - 0x20 , // 31 - 3847 - 0x21 , // 32 - 1908 - 0x22 , // 33 - 3840 - 0x23 , // 34 - 276 - 0x24 , // 35 - 3291 - 0x25 , // 36 - 1354 - 0x26 , // 37 - 2429 - 0x27 , // 38 - 2397 - 0x28 , // 39 - 3654 - 0x29 , // 40 - 1377 - 0x2a , // 41 - 3960 - 0x2b , // 42 - 1879 - 0x2c , // 43 - 224 - 0x2d , // 44 - 1361 - 0x2e , // 45 - 1851 - 0x2f , // 46 - 2501 - 0x30 , // 47 - 3541 - 0x31 , // 48 - 3739 - 0x32 , // 49 - 3708 - 0x33 , // 50 - 3953 - 0x34 , // 51 - 4020 - 0x35 , // 52 - 4277 - 0x36 , // 53 - 17 - 0x37 , // 54 - 2062 - 0x38 , // 55 - 1439 - 0x39 , // 56 - 1832 - 0x3a , // 57 - 2598 - 0x3b , // 58 - 3194 - 0x3c , // 59 - 1705 - 0x3d , // 60 - 4045 - 0x3e , // 61 - 2581 - 0x3f , // 62 - 2133 - 0x40 , // 63 - 2306 - 0x41 , // 64 - 3570 - 0x42 , // 65 - 3701 - 0x43 , // 66 - 3859 - 0x44 , // 67 - 3746 - 0x45 , // 68 - 336 - 0x46 , // 69 - 2830 - 0x47 , // 70 - 1754 - 0x48 , // 71 - 2811 - 0x49 , // 72 - 3610 - 0x4a , // 73 - 3632 - 0x4b , // 74 - 2172 - 0x4c , // 75 - 2508 - 0x4d , // 76 - 199 - 0x4e , // 77 - 2574 - 0x4f , // 78 - 3124 - 0x50 , // 79 - 2515 - 0x51 , // 80 - 348 - 0x52 , // 81 - 516 - 0x53 , // 82 - 2165 - 0x54 , // 83 - 2375 - 0x55 , // 84 - 2614 - 0x56 , // 85 - 1719 - 0x57 , // 86 - 2191 - 0x58 , // 87 - 2556 - 0x59 , // 88 - 3158 - 0x5a , // 89 - 3601 - 0x5b , // 90 - 3277 - 0x5c , // 91 - 473 - 0x5d , // 92 - 1953 - 0x5e , // 93 - 45 - 0x5f , // 94 - 3762 - 0x60 , // 95 - 2207 - 0x61 , // 96 - 2673 - 0x62 , // 97 - 1698 - 0x63 , // 98 - 2890 - 0x64 , // 99 - 1430 - 0x65 , // 100 - 620 - 0x66 , // 101 - 308 - 0x67 , // 102 - 1384 - 0x68 , // 103 - 1777 - 0x69 , // 104 - 1899 - 0x6a , // 105 - 4053 - 0x6b , // 106 - 3020 - 0x6c , // 107 - 2765 - 0x6d , // 108 - 260 - 0x6e , // 109 - 2330 - 0x6f , // 110 - 2149 - 0x70 , // 111 - 1915 - 0x71 , // 112 - 2200 - 0x72 , // 113 - 2799 - 0x73 , // 114 - 3680 - 0x74 , // 115 - 1726 - 0x75 , // 116 - 1816 - 0x76 , // 117 - 2313 - 0x77 , // 118 - 3365 - 0x78 , // 119 - 1922 - 0x79 , // 120 - 2854 - 0x7a , // 121 - 190 - 0x7c , // 122 - 2565 - 0x7e , // 123 - 360 - 0x80 , // 124 - 3833 - 0x81 , // 125 - 2494 - 0x82 , // 126 - 2792 - 0x83 , // 127 - 495 - 0x84 , // 128 - 1733 - 0x85 , // 129 - 3131 - 0x86 , // 130 - 2998 - 0x87 , // 131 - 3108 - 0x88 , // 132 - 4002 - 0x8c , // 133 - 2881 - 0x91 , // 134 - 1712 - 0x92 , // 135 - 2270 - 0x401 , // 136 - 150 - 0x402 , // 137 - 303 - 0x403 , // 138 - 428 - 0x404 , // 139 - 4248 - 0x405 , // 140 - 504 - 0x406 , // 141 - 525 - 0x407 , // 142 - 561 - 0x408 , // 143 - 671 - 0x409 , // 144 - 1161 - 0x40a , // 145 - 1272 - 0x40b , // 146 - 1425 - 0x40c , // 147 - 1529 - 0x40d , // 148 - 1827 - 0x40e , // 149 - 1862 - 0x40f , // 150 - 1931 - 0x410 , // 151 - 1943 - 0x411 , // 152 - 1991 - 0x412 , // 153 - 2186 - 0x413 , // 154 - 2707 - 0x414 , // 155 - 2641 - 0x415 , // 156 - 2866 - 0x416 , // 157 - 2904 - 0x417 , // 158 - 3043 - 0x418 , // 159 - 3062 - 0x419 , // 160 - 3098 - 0x41a , // 161 - 1846 - 0x41b , // 162 - 3286 - 0x41c , // 163 - 3389 - 0x41d , // 164 - 3565 - 0x41e , // 165 - 3675 - 0x41f , // 166 - 3734 - 0x420 , // 167 - 3854 - 0x421 , // 168 - 1910 - 0x422 , // 169 - 3842 - 0x423 , // 170 - 278 - 0x424 , // 171 - 3293 - 0x425 , // 172 - 1356 - 0x426 , // 173 - 2431 - 0x427 , // 174 - 2399 - 0x428 , // 175 - 3663 - 0x429 , // 176 - 1379 - 0x42a , // 177 - 3962 - 0x42b , // 178 - 1881 - 0x42c , // 179 - 250 - 0x42d , // 180 - 1363 - 0x42e , // 181 - 1854 - 0x42f , // 182 - 2503 - 0x430 , // 183 - 3548 - 0x431 , // 184 - 3741 - 0x432 , // 185 - 3715 - 0x433 , // 186 - 3955 - 0x434 , // 187 - 4022 - 0x435 , // 188 - 4279 - 0x436 , // 189 - 24 - 0x437 , // 190 - 2064 - 0x438 , // 191 - 1446 - 0x439 , // 192 - 1834 - 0x43a , // 193 - 2600 - 0x43b , // 194 - 3201 - 0x43d , // 195 - 4047 - 0x43e , // 196 - 2588 - 0x43f , // 197 - 2135 - 0x440 , // 198 - 2308 - 0x441 , // 199 - 3577 - 0x442 , // 200 - 3703 - 0x443 , // 201 - 3902 - 0x444 , // 202 - 3748 - 0x445 , // 203 - 343 - 0x446 , // 204 - 2849 - 0x447 , // 205 - 1756 - 0x448 , // 206 - 2813 - 0x449 , // 207 - 3612 - 0x44a , // 208 - 3634 - 0x44b , // 209 - 2174 - 0x44c , // 210 - 2510 - 0x44d , // 211 - 201 - 0x44e , // 212 - 2576 - 0x44f , // 213 - 3126 - 0x450 , // 214 - 2524 - 0x451 , // 215 - 350 - 0x452 , // 216 - 518 - 0x453 , // 217 - 2167 - 0x454 , // 218 - 2377 - 0x455 , // 219 - 2616 - 0x456 , // 220 - 1721 - 0x457 , // 221 - 2194 - 0x458 , // 222 - 2559 - 0x459 , // 223 - 3184 - 0x45a , // 224 - 3604 - 0x45b , // 225 - 3279 - 0x45c , // 226 - 484 - 0x45d , // 227 - 1962 - 0x45e , // 228 - 47 - 0x45f , // 229 - 3773 - 0x460 , // 230 - 2209 - 0x461 , // 231 - 2680 - 0x462 , // 232 - 1700 - 0x463 , // 233 - 2892 - 0x464 , // 234 - 1433 - 0x465 , // 235 - 622 - 0x466 , // 236 - 311 - 0x467 , // 237 - 1418 - 0x468 , // 238 - 1806 - 0x469 , // 239 - 1902 - 0x46a , // 240 - 4060 - 0x46b , // 241 - 3023 - 0x46c , // 242 - 2768 - 0x46d , // 243 - 262 - 0x46e , // 244 - 2332 - 0x46f , // 245 - 2151 - 0x470 , // 246 - 1917 - 0x471 , // 247 - 2202 - 0x472 , // 248 - 2801 - 0x473 , // 249 - 3687 - 0x474 , // 250 - 1728 - 0x475 , // 251 - 1819 - 0x476 , // 252 - 2315 - 0x477 , // 253 - 3382 - 0x478 , // 254 - 1924 - 0x479 , // 255 - 2857 - 0x47a , // 256 - 193 - 0x47c , // 257 - 2568 - 0x47e , // 258 - 362 - 0x480 , // 259 - 3835 - 0x481 , // 260 - 2496 - 0x482 , // 261 - 2794 - 0x483 , // 262 - 497 - 0x484 , // 263 - 1742 - 0x485 , // 264 - 3134 - 0x486 , // 265 - 3009 - 0x487 , // 266 - 3110 - 0x488 , // 267 - 4004 - 0x48c , // 268 - 2884 - 0x491 , // 269 - 1714 - 0x492 , // 270 - 2279 - 0x501 , // 271 - 2972 - 0x5fe , // 272 - 2980 - 0x801 , // 273 - 95 - 0x803 , // 274 - 433 - 0x804 , // 275 - 4110 - 0x807 , // 276 - 556 - 0x809 , // 277 - 831 - 0x80a , // 278 - 1299 - 0x80c , // 279 - 1459 - 0x810 , // 280 - 1938 - 0x813 , // 281 - 2692 - 0x814 , // 282 - 2733 - 0x816 , // 283 - 2944 - 0x818 , // 284 - 3057 - 0x819 , // 285 - 3093 - 0x81a , // 286 - 3480 - 0x81d , // 287 - 3560 - 0x820 , // 288 - 3849 - 0x82c , // 289 - 233 - 0x82e , // 290 - 605 - 0x832 , // 291 - 3710 - 0x83b , // 292 - 3206 - 0x83c , // 293 - 1707 - 0x83e , // 294 - 2583 - 0x843 , // 295 - 3885 - 0x845 , // 296 - 338 - 0x846 , // 297 - 2839 - 0x849 , // 298 - 3617 - 0x850 , // 299 - 2536 - 0x859 , // 300 - 3167 - 0x85d , // 301 - 1979 - 0x85f , // 302 - 3792 - 0x860 , // 303 - 2233 - 0x861 , // 304 - 2675 - 0x867 , // 305 - 1403 - 0x86b , // 306 - 3029 - 0x873 , // 307 - 3682 - 0x901 , // 308 - 2959 - 0x9ff , // 309 - 2989 - 0xc01 , // 310 - 80 - 0xc04 , // 311 - 4173 - 0xc07 , // 312 - 546 - 0xc09 , // 313 - 716 - 0xc0a , // 314 - 1267 - 0xc0c , // 315 - 1484 - 0xc1a , // 316 - 3423 - 0xc3b , // 317 - 3196 - 0xc50 , // 318 - 2546 - 0xc51 , // 319 - 638 - 0xc6b , // 320 - 3035 - 0x1001 , // 321 - 120 - 0x1004 , // 322 - 4219 - 0x1007 , // 323 - 588 - 0x1009 , // 324 - 756 - 0x100a , // 325 - 1289 - 0x100c , // 326 - 1504 - 0x101a , // 327 - 1841 - 0x103b , // 328 - 3316 - 0x105f , // 329 - 3822 - 0x1401 , // 330 - 75 - 0x1404 , // 331 - 4190 - 0x1407 , // 332 - 583 - 0x1409 , // 333 - 1026 - 0x140a , // 334 - 1247 - 0x140c , // 335 - 1569 - 0x141a , // 336 - 402 - 0x143b , // 337 - 3322 - 0x1801 , // 338 - 125 - 0x1809 , // 339 - 881 - 0x180a , // 340 - 1309 - 0x180c , // 341 - 1579 - 0x181a , // 342 - 3470 - 0x183b , // 343 - 3301 - 0x1c01 , // 344 - 180 - 0x1c09 , // 345 - 1191 - 0x1c0a , // 346 - 1257 - 0x1c0c , // 347 - 1453 - 0x1c1a , // 348 - 3413 - 0x1c3b , // 349 - 3307 - 0x2001 , // 350 - 135 - 0x2009 , // 351 - 911 - 0x200a , // 352 - 1349 - 0x200c , // 353 - 1634 - 0x201a , // 354 - 385 - 0x203b , // 355 - 3340 - 0x2401 , // 356 - 185 - 0x2409 , // 357 - 684 - 0x240a , // 358 - 1242 - 0x240c , // 359 - 1489 - 0x241a , // 360 - 3500 - 0x243b , // 361 - 3331 - 0x2801 , // 362 - 170 - 0x2809 , // 363 - 751 - 0x280a , // 364 - 1314 - 0x280c , // 365 - 1649 - 0x281a , // 366 - 3443 - 0x2c01 , // 367 - 100 - 0x2c09 , // 368 - 1136 - 0x2c0a , // 369 - 1222 - 0x2c0c , // 370 - 1514 - 0x2c1a , // 371 - 3490 - 0x3001 , // 372 - 115 - 0x3009 , // 373 - 1201 - 0x300a , // 374 - 1262 - 0x300c , // 375 - 1509 - 0x301a , // 376 - 3433 - 0x3401 , // 377 - 110 - 0x3409 , // 378 - 1036 - 0x340a , // 379 - 1237 - 0x340c , // 380 - 1594 - 0x3801 , // 381 - 60 - 0x3809 , // 382 - 876 - 0x380a , // 383 - 1344 - 0x380c , // 384 - 1574 - 0x3c01 , // 385 - 65 - 0x3c09 , // 386 - 871 - 0x3c0a , // 387 - 1329 - 0x3c0c , // 388 - 1559 - 0x4001 , // 389 - 145 - 0x4009 , // 390 - 896 - 0x400a , // 391 - 1227 - 0x4409 , // 392 - 991 - 0x440a , // 393 - 1334 - 0x4809 , // 394 - 1086 - 0x480a , // 395 - 1294 - 0x4c0a , // 396 - 1304 - 0x500a , // 397 - 1324 - 0x540a , // 398 - 1339 - 0x580a , // 399 - 1216 - 0x5c0a , // 400 - 1252 - 0x641a , // 401 - 378 - 0x681a , // 402 - 395 - 0x6c1a , // 403 - 3406 - 0x701a , // 404 - 3463 - 0x703b , // 405 - 3328 - 0x742c , // 406 - 226 - 0x743b , // 407 - 3337 - 0x7804 , // 408 - 4096 - 0x7814 , // 409 - 2731 - 0x781a , // 410 - 376 - 0x782c , // 411 - 243 - 0x783b , // 412 - 3298 - 0x7843 , // 413 - 3878 - 0x7850 , // 414 - 2517 - 0x785d , // 415 - 1955 - 0x785f , // 416 - 3814 - 0x7c04 , // 417 - 4166 - 0x7c14 , // 418 - 2639 - 0x7c1a , // 419 - 3404 - 0x7c28 , // 420 - 3656 - 0x7c2e , // 421 - 602 - 0x7c3b , // 422 - 3313 - 0x7c43 , // 423 - 3895 - 0x7c46 , // 424 - 2832 - 0x7c50 , // 425 - 2529 - 0x7c59 , // 426 - 3160 - 0x7c5c , // 427 - 476 - 0x7c5d , // 428 - 1972 - 0x7c5f , // 429 - 3784 - 0x7c67 , // 430 - 1396 - 0x7c68 , // 431 - 1779 - 0x7c86 , // 432 - 3001 - 0x7c92 , // 433 - 2272 - 0x1007f, // 434 - 4009 - 0x10407, // 435 - 566 - 0x1040e, // 436 - 1867 - 0x10437, // 437 - 2069 - 0x20804, // 438 - 4127 - 0x21004, // 439 - 4236 - 0x21404, // 440 - 4207 - 0x30404, // 441 - 4253 - 0x40404, // 442 - 4265 - 0x40411, // 443 - 1996 - 0x40c04, // 444 - 4178 - 0x41404, // 445 - 4195 - 0x50804, // 446 - 4115 - 0x51004 // 447 - 4224 - }; - // each element in s_lcidToCultureNameIndices is index to s_localeNamesIndices - private static readonly int[] s_lcidToCultureNameIndices = new int[] - { - // Index to s_localeNamesIndices, index to this array - lcid - index to the c_localeNames - 13 , // 0 - 1 - 52 - 64 , // 1 - 2 - 301 - 88 , // 2 - 3 - 421 - 847 , // 3 - 4 - 4139 - 103 , // 4 - 5 - 502 - 109 , // 5 - 6 - 523 - 114 , // 6 - 7 - 544 - 140 , // 7 - 8 - 664 - 143 , // 8 - 9 - 676 - 251 , // 9 - a - 1214 - 293 , // 10 - b - 1423 - 300 , // 11 - c - 1451 - 377 , // 12 - d - 1825 - 386 , // 13 - e - 1860 - 402 , // 14 - f - 1929 - 404 , // 15 - 10 - 1936 - 413 , // 16 - 11 - 1989 - 452 , // 17 - 12 - 2179 - 564 , // 18 - 13 - 2685 - 578 , // 19 - 14 - 2747 - 605 , // 20 - 15 - 2864 - 613 , // 21 - 16 - 2897 - 637 , // 22 - 17 - 3041 - 641 , // 23 - 18 - 3055 - 646 , // 24 - 19 - 3076 - 381 , // 25 - 1a - 1839 - 687 , // 26 - 1b - 3284 - 709 , // 27 - 1c - 3387 - 734 , // 28 - 1d - 3553 - 760 , // 29 - 1e - 3673 - 774 , // 30 - 1f - 3727 - 795 , // 31 - 20 - 3847 - 396 , // 32 - 21 - 1908 - 793 , // 33 - 22 - 3840 - 58 , // 34 - 23 - 276 - 689 , // 35 - 24 - 3291 - 278 , // 36 - 25 - 1354 - 506 , // 37 - 26 - 2429 - 498 , // 38 - 27 - 2397 - 757 , // 39 - 28 - 3654 - 284 , // 40 - 29 - 1377 - 812 , // 41 - 2a - 3960 - 389 , // 42 - 2b - 1879 - 49 , // 43 - 2c - 224 - 280 , // 44 - 2d - 1361 - 384 , // 45 - 2e - 1851 - 523 , // 46 - 2f - 2501 - 731 , // 47 - 30 - 3541 - 777 , // 48 - 31 - 3739 - 769 , // 49 - 32 - 3708 - 810 , // 50 - 33 - 3953 - 825 , // 51 - 34 - 4020 - 862 , // 52 - 35 - 4277 - 4 , // 53 - 36 - 17 - 425 , // 54 - 37 - 2062 - 297 , // 55 - 38 - 1439 - 379 , // 56 - 39 - 1832 - 543 , // 57 - 3a - 2598 - 670 , // 58 - 3b - 3194 - 352 , // 59 - 3c - 1705 - 831 , // 60 - 3d - 4045 - 539 , // 61 - 3e - 2581 - 440 , // 62 - 3f - 2133 - 476 , // 63 - 40 - 2306 - 738 , // 64 - 41 - 3570 - 767 , // 65 - 42 - 3701 - 798 , // 66 - 43 - 3859 - 779 , // 67 - 44 - 3746 - 71 , // 68 - 45 - 336 - 599 , // 69 - 46 - 2830 - 364 , // 70 - 47 - 1754 - 594 , // 71 - 48 - 2811 - 747 , // 72 - 49 - 3610 - 752 , // 73 - 4a - 3632 - 450 , // 74 - 4b - 2172 - 525 , // 75 - 4c - 2508 - 43 , // 76 - 4d - 199 - 537 , // 77 - 4e - 2574 - 657 , // 78 - 4f - 3124 - 527 , // 79 - 50 - 2515 - 74 , // 80 - 51 - 348 - 107 , // 81 - 52 - 516 - 448 , // 82 - 53 - 2165 - 493 , // 83 - 54 - 2375 - 547 , // 84 - 55 - 2614 - 356 , // 85 - 56 - 1719 - 455 , // 86 - 57 - 2191 - 533 , // 87 - 58 - 2556 - 665 , // 88 - 59 - 3158 - 745 , // 89 - 5a - 3601 - 685 , // 90 - 5b - 3277 - 98 , // 91 - 5c - 473 - 408 , // 92 - 5d - 1953 - 11 , // 93 - 5e - 45 - 783 , // 94 - 5f - 3762 - 459 , // 95 - 60 - 2207 - 561 , // 96 - 61 - 2673 - 350 , // 97 - 62 - 1698 - 611 , // 98 - 63 - 2890 - 295 , // 99 - 64 - 1430 - 129 , // 100 - 65 - 620 - 66 , // 101 - 66 - 308 - 286 , // 102 - 67 - 1384 - 370 , // 103 - 68 - 1777 - 394 , // 104 - 69 - 1899 - 833 , // 105 - 6a - 4053 - 633 , // 106 - 6b - 3020 - 583 , // 107 - 6c - 2765 - 54 , // 108 - 6d - 260 - 482 , // 109 - 6e - 2330 - 444 , // 110 - 6f - 2149 - 398 , // 111 - 70 - 1915 - 457 , // 112 - 71 - 2200 - 591 , // 113 - 72 - 2799 - 762 , // 114 - 73 - 3680 - 358 , // 115 - 74 - 1726 - 375 , // 116 - 75 - 1816 - 478 , // 117 - 76 - 2313 - 704 , // 118 - 77 - 3365 - 400 , // 119 - 78 - 1922 - 603 , // 120 - 79 - 2854 - 41 , // 121 - 7a - 190 - 535 , // 122 - 7c - 2565 - 77 , // 123 - 7e - 360 - 791 , // 124 - 80 - 3833 - 521 , // 125 - 81 - 2494 - 589 , // 126 - 82 - 2792 - 101 , // 127 - 83 - 495 - 360 , // 128 - 84 - 1733 - 659 , // 129 - 85 - 3131 - 630 , // 130 - 86 - 2998 - 653 , // 131 - 87 - 3108 - 822 , // 132 - 88 - 4002 - 609 , // 133 - 8c - 2881 - 354 , // 134 - 91 - 1712 - 470 , // 135 - 92 - 2270 - 33 , // 136 - 401 - 150 - 65 , // 137 - 402 - 303 - 90 , // 138 - 403 - 428 - 859 , // 139 - 404 - 4248 - 104 , // 140 - 405 - 504 - 110 , // 141 - 406 - 525 - 118 , // 142 - 407 - 561 - 142 , // 143 - 408 - 671 - 240 , // 144 - 409 - 1161 - 263 , // 145 - 40a - 1272 - 294 , // 146 - 40b - 1425 - 316 , // 147 - 40c - 1529 - 378 , // 148 - 40d - 1827 - 387 , // 149 - 40e - 1862 - 403 , // 150 - 40f - 1931 - 406 , // 151 - 410 - 1943 - 414 , // 152 - 411 - 1991 - 454 , // 153 - 412 - 2186 - 569 , // 154 - 413 - 2707 - 554 , // 155 - 414 - 2641 - 606 , // 156 - 415 - 2866 - 615 , // 157 - 416 - 2904 - 638 , // 158 - 417 - 3043 - 643 , // 159 - 418 - 3062 - 651 , // 160 - 419 - 3098 - 383 , // 161 - 41a - 1846 - 688 , // 162 - 41b - 3286 - 710 , // 163 - 41c - 3389 - 737 , // 164 - 41d - 3565 - 761 , // 165 - 41e - 3675 - 776 , // 166 - 41f - 3734 - 797 , // 167 - 420 - 3854 - 397 , // 168 - 421 - 1910 - 794 , // 169 - 422 - 3842 - 59 , // 170 - 423 - 278 - 690 , // 171 - 424 - 3293 - 279 , // 172 - 425 - 1356 - 507 , // 173 - 426 - 2431 - 499 , // 174 - 427 - 2399 - 759 , // 175 - 428 - 3663 - 285 , // 176 - 429 - 1379 - 813 , // 177 - 42a - 3962 - 390 , // 178 - 42b - 1881 - 53 , // 179 - 42c - 250 - 281 , // 180 - 42d - 1363 - 385 , // 181 - 42e - 1854 - 524 , // 182 - 42f - 2503 - 733 , // 183 - 430 - 3548 - 778 , // 184 - 431 - 3741 - 771 , // 185 - 432 - 3715 - 811 , // 186 - 433 - 3955 - 826 , // 187 - 434 - 4022 - 863 , // 188 - 435 - 4279 - 6 , // 189 - 436 - 24 - 426 , // 190 - 437 - 2064 - 299 , // 191 - 438 - 1446 - 380 , // 192 - 439 - 1834 - 544 , // 193 - 43a - 2600 - 672 , // 194 - 43b - 3201 - 832 , // 195 - 43d - 4047 - 541 , // 196 - 43e - 2588 - 441 , // 197 - 43f - 2135 - 477 , // 198 - 440 - 2308 - 740 , // 199 - 441 - 3577 - 768 , // 200 - 442 - 3703 - 804 , // 201 - 443 - 3902 - 780 , // 202 - 444 - 3748 - 73 , // 203 - 445 - 343 - 602 , // 204 - 446 - 2849 - 365 , // 205 - 447 - 1756 - 595 , // 206 - 448 - 2813 - 748 , // 207 - 449 - 3612 - 753 , // 208 - 44a - 3634 - 451 , // 209 - 44b - 2174 - 526 , // 210 - 44c - 2510 - 44 , // 211 - 44d - 201 - 538 , // 212 - 44e - 2576 - 658 , // 213 - 44f - 3126 - 529 , // 214 - 450 - 2524 - 75 , // 215 - 451 - 350 - 108 , // 216 - 452 - 518 - 449 , // 217 - 453 - 2167 - 494 , // 218 - 454 - 2377 - 548 , // 219 - 455 - 2616 - 357 , // 220 - 456 - 1721 - 456 , // 221 - 457 - 2194 - 534 , // 222 - 458 - 2559 - 669 , // 223 - 459 - 3184 - 746 , // 224 - 45a - 3604 - 686 , // 225 - 45b - 3279 - 100 , // 226 - 45c - 484 - 410 , // 227 - 45d - 1962 - 12 , // 228 - 45e - 47 - 785 , // 229 - 45f - 3773 - 460 , // 230 - 460 - 2209 - 563 , // 231 - 461 - 2680 - 351 , // 232 - 462 - 1700 - 612 , // 233 - 463 - 2892 - 296 , // 234 - 464 - 1433 - 130 , // 235 - 465 - 622 - 67 , // 236 - 466 - 311 - 292 , // 237 - 467 - 1418 - 374 , // 238 - 468 - 1806 - 395 , // 239 - 469 - 1902 - 835 , // 240 - 46a - 4060 - 634 , // 241 - 46b - 3023 - 584 , // 242 - 46c - 2768 - 55 , // 243 - 46d - 262 - 483 , // 244 - 46e - 2332 - 445 , // 245 - 46f - 2151 - 399 , // 246 - 470 - 1917 - 458 , // 247 - 471 - 2202 - 592 , // 248 - 472 - 2801 - 764 , // 249 - 473 - 3687 - 359 , // 250 - 474 - 1728 - 376 , // 251 - 475 - 1819 - 479 , // 252 - 476 - 2315 - 708 , // 253 - 477 - 3382 - 401 , // 254 - 478 - 1924 - 604 , // 255 - 479 - 2857 - 42 , // 256 - 47a - 193 - 536 , // 257 - 47c - 2568 - 78 , // 258 - 47e - 362 - 792 , // 259 - 480 - 3835 - 522 , // 260 - 481 - 2496 - 590 , // 261 - 482 - 2794 - 102 , // 262 - 483 - 497 - 362 , // 263 - 484 - 1742 - 660 , // 264 - 485 - 3134 - 632 , // 265 - 486 - 3009 - 654 , // 266 - 487 - 3110 - 823 , // 267 - 488 - 4004 - 610 , // 268 - 48c - 2884 - 355 , // 269 - 491 - 1714 - 472 , // 270 - 492 - 2279 - 627 , // 271 - 501 - 2972 - 628 , // 272 - 5fe - 2980 - 22 , // 273 - 801 - 95 - 91 , // 274 - 803 - 433 - 844 , // 275 - 804 - 4110 - 117 , // 276 - 807 - 556 - 174 , // 277 - 809 - 831 - 267 , // 278 - 80a - 1299 - 302 , // 279 - 80c - 1459 - 405 , // 280 - 810 - 1938 - 566 , // 281 - 813 - 2692 - 575 , // 282 - 814 - 2733 - 623 , // 283 - 816 - 2944 - 642 , // 284 - 818 - 3057 - 650 , // 285 - 819 - 3093 - 722 , // 286 - 81a - 3480 - 736 , // 287 - 81d - 3560 - 796 , // 288 - 820 - 3849 - 51 , // 289 - 82c - 233 - 126 , // 290 - 82e - 605 - 770 , // 291 - 832 - 3710 - 673 , // 292 - 83b - 3206 - 353 , // 293 - 83c - 1707 - 540 , // 294 - 83e - 2583 - 802 , // 295 - 843 - 3885 - 72 , // 296 - 845 - 338 - 601 , // 297 - 846 - 2839 - 749 , // 298 - 849 - 3617 - 531 , // 299 - 850 - 2536 - 667 , // 300 - 859 - 3167 - 412 , // 301 - 85d - 1979 - 787 , // 302 - 85f - 3792 - 463 , // 303 - 860 - 2233 - 562 , // 304 - 861 - 2675 - 290 , // 305 - 867 - 1403 - 635 , // 306 - 86b - 3029 - 763 , // 307 - 873 - 3682 - 626 , // 308 - 901 - 2959 - 629 , // 309 - 9ff - 2989 - 19 , // 310 - c01 - 80 - 851 , // 311 - c04 - 4173 - 115 , // 312 - c07 - 546 - 151 , // 313 - c09 - 716 - 262 , // 314 - c0a - 1267 - 307 , // 315 - c0c - 1484 - 716 , // 316 - c1a - 3423 - 671 , // 317 - c3b - 3196 - 532 , // 318 - c50 - 2546 - 134 , // 319 - c51 - 638 - 636 , // 320 - c6b - 3035 - 27 , // 321 - 1001 - 120 - 856 , // 322 - 1004 - 4219 - 122 , // 323 - 1007 - 588 - 159 , // 324 - 1009 - 756 - 265 , // 325 - 100a - 1289 - 311 , // 326 - 100c - 1504 - 382 , // 327 - 101a - 1841 - 695 , // 328 - 103b - 3316 - 790 , // 329 - 105f - 3822 - 18 , // 330 - 1401 - 75 - 853 , // 331 - 1404 - 4190 - 121 , // 332 - 1407 - 583 - 213 , // 333 - 1409 - 1026 - 258 , // 334 - 140a - 1247 - 324 , // 335 - 140c - 1569 - 85 , // 336 - 141a - 402 - 696 , // 337 - 143b - 3322 - 28 , // 338 - 1801 - 125 - 184 , // 339 - 1809 - 881 - 269 , // 340 - 180a - 1309 - 326 , // 341 - 180c - 1579 - 721 , // 342 - 181a - 3470 - 692 , // 343 - 183b - 3301 - 39 , // 344 - 1c01 - 180 - 246 , // 345 - 1c09 - 1191 - 260 , // 346 - 1c0a - 1257 - 301 , // 347 - 1c0c - 1453 - 715 , // 348 - 1c1a - 3413 - 693 , // 349 - 1c3b - 3307 - 30 , // 350 - 2001 - 135 - 190 , // 351 - 2009 - 911 - 277 , // 352 - 200a - 1349 - 337 , // 353 - 200c - 1634 - 83 , // 354 - 201a - 385 - 700 , // 355 - 203b - 3340 - 40 , // 356 - 2401 - 185 - 145 , // 357 - 2409 - 684 - 257 , // 358 - 240a - 1242 - 308 , // 359 - 240c - 1489 - 724 , // 360 - 241a - 3500 - 698 , // 361 - 243b - 3331 - 37 , // 362 - 2801 - 170 - 158 , // 363 - 2809 - 751 - 270 , // 364 - 280a - 1314 - 340 , // 365 - 280c - 1649 - 718 , // 366 - 281a - 3443 - 23 , // 367 - 2c01 - 100 - 235 , // 368 - 2c09 - 1136 - 253 , // 369 - 2c0a - 1222 - 313 , // 370 - 2c0c - 1514 - 723 , // 371 - 2c1a - 3490 - 26 , // 372 - 3001 - 115 - 248 , // 373 - 3009 - 1201 - 261 , // 374 - 300a - 1262 - 312 , // 375 - 300c - 1509 - 717 , // 376 - 301a - 3433 - 25 , // 377 - 3401 - 110 - 215 , // 378 - 3409 - 1036 - 256 , // 379 - 340a - 1237 - 329 , // 380 - 340c - 1594 - 15 , // 381 - 3801 - 60 - 183 , // 382 - 3809 - 876 - 276 , // 383 - 380a - 1344 - 325 , // 384 - 380c - 1574 - 16 , // 385 - 3c01 - 65 - 182 , // 386 - 3c09 - 871 - 273 , // 387 - 3c0a - 1329 - 322 , // 388 - 3c0c - 1559 - 32 , // 389 - 4001 - 145 - 187 , // 390 - 4009 - 896 - 254 , // 391 - 400a - 1227 - 206 , // 392 - 4409 - 991 - 274 , // 393 - 440a - 1334 - 225 , // 394 - 4809 - 1086 - 266 , // 395 - 480a - 1294 - 268 , // 396 - 4c0a - 1304 - 272 , // 397 - 500a - 1324 - 275 , // 398 - 540a - 1339 - 252 , // 399 - 580a - 1216 - 259 , // 400 - 5c0a - 1252 - 82 , // 401 - 641a - 378 - 84 , // 402 - 681a - 395 - 714 , // 403 - 6c1a - 3406 - 720 , // 404 - 701a - 3463 - 697 , // 405 - 703b - 3328 - 50 , // 406 - 742c - 226 - 699 , // 407 - 743b - 3337 - 841 , // 408 - 7804 - 4096 - 574 , // 409 - 7814 - 2731 - 81 , // 410 - 781a - 376 - 52 , // 411 - 782c - 243 - 691 , // 412 - 783b - 3298 - 801 , // 413 - 7843 - 3878 - 528 , // 414 - 7850 - 2517 - 409 , // 415 - 785d - 1955 - 789 , // 416 - 785f - 3814 - 850 , // 417 - 7c04 - 4166 - 553 , // 418 - 7c14 - 2639 - 713 , // 419 - 7c1a - 3404 - 758 , // 420 - 7c28 - 3656 - 125 , // 421 - 7c2e - 602 - 694 , // 422 - 7c3b - 3313 - 803 , // 423 - 7c43 - 3895 - 600 , // 424 - 7c46 - 2832 - 530 , // 425 - 7c50 - 2529 - 666 , // 426 - 7c59 - 3160 - 99 , // 427 - 7c5c - 476 - 411 , // 428 - 7c5d - 1972 - 786 , // 429 - 7c5f - 3784 - 289 , // 430 - 7c67 - 1396 - 371 , // 431 - 7c68 - 1779 - 631 , // 432 - 7c86 - 3001 - 471 , // 433 - 7c92 - 2272 - 824 , // 434 - 1007f - 4009 - 119 , // 435 - 10407 - 566 - 388 , // 436 - 1040e - 1867 - 427 , // 437 - 10437 - 2069 - 846 , // 438 - 20804 - 4127 - 858 , // 439 - 21004 - 4236 - 855 , // 440 - 21404 - 4207 - 860 , // 441 - 30404 - 4253 - 861 , // 442 - 40404 - 4265 - 415 , // 443 - 40411 - 1996 - 852 , // 444 - 40c04 - 4178 - 854 , // 445 - 41404 - 4195 - 845 , // 446 - 50804 - 4115 - 857 // 447 - 51004 - 4224 - }; - - internal static string? LCIDToLocaleName(int culture) - { - int left = 0; - int right = s_lcids.Length - 1; - int index; - - Debug.Assert(s_lcids.Length == s_lcidToCultureNameIndices.Length); - - while (left <= right) - { - index = (right + left) / 2; - - if (culture == s_lcids[index]) - { - int indexToLocaleNamesIndices = s_lcidToCultureNameIndices[index]; - Debug.Assert(indexToLocaleNamesIndices < s_localeNamesIndices.Length - 1); - - return c_localeNames.Substring(s_localeNamesIndices[indexToLocaleNamesIndices], - s_localeNamesIndices[indexToLocaleNamesIndices + 1] - - s_localeNamesIndices[indexToLocaleNamesIndices]); - } - else if (culture < s_lcids[index]) - { - right = index - 1; - } - else - { - left = index + 1; - } - } - - return null; - } - - internal static int GetLocaleDataNumericPart(string cultureName, LocaleDataParts part) - { - int index = SearchCultureName(cultureName); - if (index < 0) - { - return -1; - } - - Debug.Assert((s_localeNamesIndices.Length-1 == (s_nameIndexToNumericData.Length/NUMERIC_LOCALE_DATA_COUNT_PER_ROW)) && - index < s_localeNamesIndices.Length); - - return s_nameIndexToNumericData[index * NUMERIC_LOCALE_DATA_COUNT_PER_ROW + (int) part]; - } - - internal static string? GetThreeLetterWindowsLanguageName(string cultureName) - { - int index = SearchCultureName(cultureName); - if (index < 0) - { - return null; - } - - Debug.Assert(s_localeNamesIndices.Length-1 == (c_threeLetterWindowsLanguageName.Length / 3)); - return c_threeLetterWindowsLanguageName.Substring(index * 3, 3); - } - - internal static string GetLocaleDataMappedCulture(string cultureName, LocaleDataParts part) - { - int indexToIndicesTable = GetLocaleDataNumericPart(cultureName, part); - if (indexToIndicesTable < 0) - { - return ""; // fallback to invariant - } - - Debug.Assert(indexToIndicesTable < s_localeNamesIndices.Length-1); - - return c_localeNames.Substring(s_localeNamesIndices[indexToIndicesTable], - s_localeNamesIndices[indexToIndicesTable+1] - s_localeNamesIndices[indexToIndicesTable]); - } - - internal static string GetSpecificCultureName(string cultureName) - { - return GetLocaleDataMappedCulture(cultureName, LocaleDataParts.SpecificLocaleIndex); - } - - internal static string GetConsoleUICulture(string cultureName) - { - return GetLocaleDataMappedCulture(cultureName, LocaleDataParts.ConsoleLocaleIndex); - } - - // SearchCultureName will binary search c_localeNames using s_localeNamesIndices. - // return index in s_localeNamesIndices, or -1 if it fail finding any match - private static int SearchCultureName(string name) - { - int left = 0; - int right = s_localeNamesIndices.Length - 2; - int index; - int result; - - Debug.Assert(s_localeNamesIndices[s_localeNamesIndices.Length - 1] == c_localeNames.Length); - - name = CultureData.AnsiToLower(name); - - // Binary search the array until we have only a couple of elements left and then - // just walk those elements. - while ((right - left) > 3) - { - index = ((right - left) / 2) + left; - - Debug.Assert(index < s_localeNamesIndices.Length - 1); - result = CompareOrdinal(name, c_localeNames, s_localeNamesIndices[index], s_localeNamesIndices[index + 1] - s_localeNamesIndices[index]); - if (result == 0) - { - return index; - } - else if (result < 0) - { - right = index; - } - else - { - left = index; - } - } - - // Walk the remaining elements (it'll be 3 or fewer). - for (; left <= right; left++) - { - Debug.Assert(left < s_localeNamesIndices.Length - 1); - if (CompareOrdinal(name, c_localeNames, s_localeNamesIndices[left], s_localeNamesIndices[left + 1] - s_localeNamesIndices[left]) == 0) - { - return (left); - } - } - - // couldn't find culture name - return -1; - } - - // optimized to avoid parameters checking - private static int CompareOrdinal(string s1, string s2, int index, int length) - { - int count = s1.Length; - if (count > length) - count = length; - - int i = 0; - while (i < count && s1[i] == s2[index + i]) - i++; - - if (i < count) - return (int)(s1[i] - s2[index + i]); - - return s1.Length - length; - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/Normalization.Unix.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/Normalization.Unix.cs deleted file mode 100644 index 37c9024c33d..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/Normalization.Unix.cs +++ /dev/null @@ -1,134 +0,0 @@ -// 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; -using System.Text; - -namespace System.Globalization -{ - internal static partial class Normalization - { - internal static bool IsNormalized(string strInput, NormalizationForm normalizationForm) - { - if (GlobalizationMode.Invariant) - { - // In Invariant mode we assume all characters are normalized. - // This is because we don't support any linguistic operation on the strings - return true; - } - - ValidateArguments(strInput, normalizationForm); - - int ret = Interop.Globalization.IsNormalized(normalizationForm, strInput, strInput.Length); - - if (ret == -1) - { - throw new ArgumentException(SR.Argument_InvalidCharSequenceNoIndex, nameof(strInput)); - } - - return ret == 1; - } - - internal static string Normalize(string strInput, NormalizationForm normalizationForm) - { - if (GlobalizationMode.Invariant) - { - // In Invariant mode we assume all characters are normalized. - // This is because we don't support any linguistic operation on the strings - return strInput; - } - - ValidateArguments(strInput, normalizationForm); - - char[] buf = new char[strInput.Length]; - - for (int attempts = 2; attempts > 0; attempts--) - { - int realLen = Interop.Globalization.NormalizeString(normalizationForm, strInput, strInput.Length, buf, buf.Length); - - if (realLen == -1) - { - throw new ArgumentException(SR.Argument_InvalidCharSequenceNoIndex, nameof(strInput)); - } - - if (realLen <= buf.Length) - { - return new string(buf, 0, realLen); - } - - buf = new char[realLen]; - } - - throw new ArgumentException(SR.Argument_InvalidCharSequenceNoIndex, nameof(strInput)); - } - - // ----------------------------- - // ---- PAL layer ends here ---- - // ----------------------------- - - private static void ValidateArguments(string strInput, NormalizationForm normalizationForm) - { - Debug.Assert(strInput != null); - - if (normalizationForm != NormalizationForm.FormC && normalizationForm != NormalizationForm.FormD && - normalizationForm != NormalizationForm.FormKC && normalizationForm != NormalizationForm.FormKD) - { - throw new ArgumentException(SR.Argument_InvalidNormalizationForm, nameof(normalizationForm)); - } - - if (HasInvalidUnicodeSequence(strInput)) - { - throw new ArgumentException(SR.Argument_InvalidCharSequenceNoIndex, nameof(strInput)); - } - } - - /// <summary> - /// ICU does not signal an error during normalization if the input string has invalid unicode, - /// unlike Windows (which uses the ERROR_NO_UNICODE_TRANSLATION error value to signal an error). - /// - /// We walk the string ourselves looking for these bad sequences so we can continue to throw - /// ArgumentException in these cases. - /// </summary> - private static bool HasInvalidUnicodeSequence(string s) - { - for (int i = 0; i < s.Length; i++) - { - char c = s[i]; - - if (c < '\ud800') - { - continue; - } - - if (c == '\uFFFE') - { - return true; - } - - // If we see low surrogate before a high one, the string is invalid. - if (char.IsLowSurrogate(c)) - { - return true; - } - - if (char.IsHighSurrogate(c)) - { - if (i + 1 >= s.Length || !char.IsLowSurrogate(s[i + 1])) - { - // A high surrogate at the end of the string or a high surrogate - // not followed by a low surrogate - return true; - } - else - { - i++; // consume the low surrogate. - continue; - } - } - } - - return false; - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/Normalization.Windows.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/Normalization.Windows.cs deleted file mode 100644 index e96789d1695..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/Normalization.Windows.cs +++ /dev/null @@ -1,148 +0,0 @@ -// 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; -using System.Runtime.InteropServices; -using System.Text; - -namespace System.Globalization -{ - internal static partial class Normalization - { - internal static bool IsNormalized(string strInput, NormalizationForm normalizationForm) - { - if (GlobalizationMode.Invariant) - { - // In Invariant mode we assume all characters are normalized. - // This is because we don't support any linguistic operation on the strings - return true; - } - - Debug.Assert(strInput != null); - - // The only way to know if IsNormalizedString failed is through checking the Win32 last error - // IsNormalizedString pinvoke has SetLastError attribute property which will set the last error - // to 0 (ERROR_SUCCESS) before executing the calls. - bool result = Interop.Normaliz.IsNormalizedString((int)normalizationForm, strInput, strInput.Length); - - int lastError = Marshal.GetLastWin32Error(); - switch (lastError) - { - case Interop.Errors.ERROR_SUCCESS: - break; - - case Interop.Errors.ERROR_INVALID_PARAMETER: - case Interop.Errors.ERROR_NO_UNICODE_TRANSLATION: - if (normalizationForm != NormalizationForm.FormC && - normalizationForm != NormalizationForm.FormD && - normalizationForm != NormalizationForm.FormKC && - normalizationForm != NormalizationForm.FormKD) - { - throw new ArgumentException(SR.Argument_InvalidNormalizationForm, nameof(normalizationForm)); - } - - throw new ArgumentException(SR.Argument_InvalidCharSequenceNoIndex, nameof(strInput)); - - case Interop.Errors.ERROR_NOT_ENOUGH_MEMORY: - throw new OutOfMemoryException(); - - default: - throw new InvalidOperationException(SR.Format(SR.UnknownError_Num, lastError)); - } - - return result; - } - - internal static string Normalize(string strInput, NormalizationForm normalizationForm) - { - if (GlobalizationMode.Invariant) - { - // In Invariant mode we assume all characters are normalized. - // This is because we don't support any linguistic operation on the strings - return strInput; - } - - Debug.Assert(strInput != null); - - // we depend on Win32 last error when calling NormalizeString - // NormalizeString pinvoke has SetLastError attribute property which will set the last error - // to 0 (ERROR_SUCCESS) before executing the calls. - - // Guess our buffer size first - int iLength = Interop.Normaliz.NormalizeString((int)normalizationForm, strInput, strInput.Length, null, 0); - - int lastError = Marshal.GetLastWin32Error(); - // Could have an error (actually it'd be quite hard to have an error here) - if ((lastError != Interop.Errors.ERROR_SUCCESS) || iLength < 0) - { - if (lastError == Interop.Errors.ERROR_INVALID_PARAMETER) - { - if (normalizationForm != NormalizationForm.FormC && - normalizationForm != NormalizationForm.FormD && - normalizationForm != NormalizationForm.FormKC && - normalizationForm != NormalizationForm.FormKD) - { - throw new ArgumentException(SR.Argument_InvalidNormalizationForm, nameof(normalizationForm)); - } - - throw new ArgumentException(SR.Argument_InvalidCharSequenceNoIndex, nameof(strInput)); - } - - // We shouldn't really be able to get here..., guessing length is - // a trivial math function... - // Can't really be Out of Memory, but just in case: - if (lastError == Interop.Errors.ERROR_NOT_ENOUGH_MEMORY) - throw new OutOfMemoryException(); - - // Who knows what happened? Not us! - throw new InvalidOperationException(SR.Format(SR.UnknownError_Num, lastError)); - } - - // Don't break for empty strings (only possible for D & KD and not really possible at that) - if (iLength == 0) return string.Empty; - - // Someplace to stick our buffer - char[] cBuffer; - - while (true) - { - // (re)allocation buffer and normalize string - cBuffer = new char[iLength]; - - // NormalizeString pinvoke has SetLastError attribute property which will set the last error - // to 0 (ERROR_SUCCESS) before executing the calls. - iLength = Interop.Normaliz.NormalizeString((int)normalizationForm, strInput, strInput.Length, cBuffer, cBuffer.Length); - lastError = Marshal.GetLastWin32Error(); - - if (lastError == Interop.Errors.ERROR_SUCCESS) - break; - - // Could have an error (actually it'd be quite hard to have an error here) - switch (lastError) - { - // Do appropriate stuff for the individual errors: - case Interop.Errors.ERROR_INSUFFICIENT_BUFFER: - iLength = Math.Abs(iLength); - Debug.Assert(iLength > cBuffer.Length, "Buffer overflow should have iLength > cBuffer.Length"); - continue; - - case Interop.Errors.ERROR_INVALID_PARAMETER: - case Interop.Errors.ERROR_NO_UNICODE_TRANSLATION: - // Illegal code point or order found. Ie: FFFE or D800 D800, etc. - throw new ArgumentException(SR.Argument_InvalidCharSequenceNoIndex, nameof(strInput)); - - case Interop.Errors.ERROR_NOT_ENOUGH_MEMORY: - throw new OutOfMemoryException(); - - default: - // We shouldn't get here... - throw new InvalidOperationException(SR.Format(SR.UnknownError_Num, lastError)); - } - } - - // Copy our buffer into our new string, which will be the appropriate size - return new string(cBuffer, 0, iLength); - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/NumberFormatInfo.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/NumberFormatInfo.cs deleted file mode 100644 index d5fa16edcdc..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/NumberFormatInfo.cs +++ /dev/null @@ -1,750 +0,0 @@ -// 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 -{ - /// <remarks> - /// Property Default Description - /// PositiveSign '+' Character used to indicate positive values. - /// NegativeSign '-' Character used to indicate negative values. - /// NumberDecimalSeparator '.' The character used as the decimal separator. - /// NumberGroupSeparator ',' The character used to separate groups of - /// digits to the left of the decimal point. - /// NumberDecimalDigits 2 The default number of decimal places. - /// NumberGroupSizes 3 The number of digits in each group to the - /// left of the decimal point. - /// NaNSymbol "NaN" The string used to represent NaN values. - /// PositiveInfinitySymbol"Infinity" The string used to represent positive - /// infinities. - /// NegativeInfinitySymbol"-Infinity" The string used to represent negative - /// infinities. - /// - /// Property Default Description - /// CurrencyDecimalSeparator '.' The character used as the decimal - /// separator. - /// CurrencyGroupSeparator ',' The character used to separate groups - /// of digits to the left of the decimal - /// point. - /// CurrencyDecimalDigits 2 The default number of decimal places. - /// CurrencyGroupSizes 3 The number of digits in each group to - /// the left of the decimal point. - /// CurrencyPositivePattern 0 The format of positive values. - /// CurrencyNegativePattern 0 The format of negative values. - /// CurrencySymbol "$" String used as local monetary symbol. - /// </remarks> - public sealed class NumberFormatInfo : IFormatProvider, ICloneable - { - private static volatile NumberFormatInfo? s_invariantInfo; - - internal int[] _numberGroupSizes = new int[] { 3 }; - internal int[] _currencyGroupSizes = new int[] { 3 }; - internal int[] _percentGroupSizes = new int[] { 3 }; - internal string _positiveSign = "+"; - internal string _negativeSign = "-"; - internal string _numberDecimalSeparator = "."; - internal string _numberGroupSeparator = ","; - internal string _currencyGroupSeparator = ","; - internal string _currencyDecimalSeparator = "."; - internal string _currencySymbol = "\x00a4"; // U+00a4 is the symbol for International Monetary Fund. - internal string _nanSymbol = "NaN"; - internal string _positiveInfinitySymbol = "Infinity"; - internal string _negativeInfinitySymbol = "-Infinity"; - internal string _percentDecimalSeparator = "."; - internal string _percentGroupSeparator = ","; - internal string _percentSymbol = "%"; - internal string _perMilleSymbol = "\u2030"; - - internal string[] _nativeDigits = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" }; - - internal int _numberDecimalDigits = 2; - internal int _currencyDecimalDigits = 2; - internal int _currencyPositivePattern = 0; - internal int _currencyNegativePattern = 0; - internal int _numberNegativePattern = 1; - internal int _percentPositivePattern = 0; - internal int _percentNegativePattern = 0; - internal int _percentDecimalDigits = 2; - - internal int _digitSubstitution = (int)DigitShapes.None; - - internal bool _isReadOnly = false; - - private bool _hasInvariantNumberSigns = true; - - public NumberFormatInfo() - { - } - - private static void VerifyDecimalSeparator(string decSep, string propertyName) - { - if (decSep == null) - { - throw new ArgumentNullException(propertyName); - } - - if (decSep.Length == 0) - { - throw new ArgumentException(SR.Argument_EmptyDecString, propertyName); - } - } - - private static void VerifyGroupSeparator(string groupSep, string propertyName) - { - if (groupSep == null) - { - throw new ArgumentNullException(propertyName); - } - } - - private static void VerifyNativeDigits(string[] nativeDig, string propertyName) - { - if (nativeDig == null) - { - throw new ArgumentNullException(propertyName, SR.ArgumentNull_Array); - } - - if (nativeDig.Length != 10) - { - throw new ArgumentException(SR.Argument_InvalidNativeDigitCount, propertyName); - } - - for (int i = 0; i < nativeDig.Length; i++) - { - if (nativeDig[i] == null) - { - throw new ArgumentNullException(propertyName, SR.ArgumentNull_ArrayValue); - } - - if (nativeDig[i].Length != 1) - { - if (nativeDig[i].Length != 2) - { - // Not 1 or 2 UTF-16 code points - throw new ArgumentException(SR.Argument_InvalidNativeDigitValue, propertyName); - } - else if (!char.IsSurrogatePair(nativeDig[i][0], nativeDig[i][1])) - { - // 2 UTF-6 code points, but not a surrogate pair - throw new ArgumentException(SR.Argument_InvalidNativeDigitValue, propertyName); - } - } - - if (CharUnicodeInfo.GetDecimalDigitValue(nativeDig[i], 0) != i && - CharUnicodeInfo.GetUnicodeCategory(nativeDig[i], 0) != UnicodeCategory.PrivateUse) - { - // Not the appropriate digit according to the Unicode data properties - // (Digit 0 must be a 0, etc.). - throw new ArgumentException(SR.Argument_InvalidNativeDigitValue, propertyName); - } - } - } - - private static void VerifyDigitSubstitution(DigitShapes digitSub, string propertyName) - { - switch (digitSub) - { - case DigitShapes.Context: - case DigitShapes.None: - case DigitShapes.NativeNational: - // Success. - break; - - default: - throw new ArgumentException(SR.Argument_InvalidDigitSubstitution, propertyName); - } - } - - internal bool HasInvariantNumberSigns => _hasInvariantNumberSigns; - - private void UpdateHasInvariantNumberSigns() - { - _hasInvariantNumberSigns = _positiveSign == "+" && _negativeSign == "-"; - } - - internal NumberFormatInfo(CultureData? cultureData) - { - if (cultureData != null) - { - // We directly use fields here since these data is coming from data table or Win32, so we - // don't need to verify their values (except for invalid parsing situations). - cultureData.GetNFIValues(this); - - UpdateHasInvariantNumberSigns(); - } - } - - private void VerifyWritable() - { - if (_isReadOnly) - { - throw new InvalidOperationException(SR.InvalidOperation_ReadOnly); - } - } - - /// <summary> - /// Returns a default NumberFormatInfo that will be universally - /// supported and constant irrespective of the current culture. - /// Used by FromString methods. - /// </summary> - public static NumberFormatInfo InvariantInfo => s_invariantInfo ??= - // Lazy create the invariant info. This cannot be done in a .cctor because exceptions can - // be thrown out of a .cctor stack that will need this. - new NumberFormatInfo { _isReadOnly = true }; - - public static NumberFormatInfo GetInstance(IFormatProvider? formatProvider) - { - return formatProvider == null ? - CurrentInfo : // Fast path for a null provider - GetProviderNonNull(formatProvider); - - static NumberFormatInfo GetProviderNonNull(IFormatProvider provider) - { - // Fast path for a regular CultureInfo - if (provider is CultureInfo cultureProvider && !cultureProvider._isInherited) - { - return cultureProvider._numInfo ?? cultureProvider.NumberFormat; - } - - return - provider as NumberFormatInfo ?? // Fast path for an NFI - provider.GetFormat(typeof(NumberFormatInfo)) as NumberFormatInfo ?? - CurrentInfo; - } - } - - public object Clone() - { - NumberFormatInfo n = (NumberFormatInfo)MemberwiseClone(); - n._isReadOnly = false; - return n; - } - - public int CurrencyDecimalDigits - { - get => _currencyDecimalDigits; - set - { - if (value < 0 || value > 99) - { - throw new ArgumentOutOfRangeException( - nameof(value), - value, - SR.Format(SR.ArgumentOutOfRange_Range, 0, 99)); - } - - VerifyWritable(); - _currencyDecimalDigits = value; - } - } - - public string CurrencyDecimalSeparator - { - get => _currencyDecimalSeparator; - set - { - VerifyWritable(); - VerifyDecimalSeparator(value, nameof(value)); - _currencyDecimalSeparator = value; - } - } - - public bool IsReadOnly => _isReadOnly; - - /// <summary> - /// Check the values of the groupSize array. - /// Every element in the groupSize array should be between 1 and 9 - /// except the last element could be zero. - /// </summary> - internal static void CheckGroupSize(string propName, int[] groupSize) - { - for (int i = 0; i < groupSize.Length; i++) - { - if (groupSize[i] < 1) - { - if (i == groupSize.Length - 1 && groupSize[i] == 0) - { - return; - } - - throw new ArgumentException(SR.Argument_InvalidGroupSize, propName); - } - else if (groupSize[i] > 9) - { - throw new ArgumentException(SR.Argument_InvalidGroupSize, propName); - } - } - } - - public int[] CurrencyGroupSizes - { - get => (int[])_currencyGroupSizes.Clone(); - set - { - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - - VerifyWritable(); - - int[] inputSizes = (int[])value.Clone(); - CheckGroupSize(nameof(value), inputSizes); - _currencyGroupSizes = inputSizes; - } - } - - public int[] NumberGroupSizes - { - get => (int[])_numberGroupSizes.Clone(); - set - { - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - - VerifyWritable(); - - int[] inputSizes = (int[])value.Clone(); - CheckGroupSize(nameof(value), inputSizes); - _numberGroupSizes = inputSizes; - } - } - - public int[] PercentGroupSizes - { - get => (int[])_percentGroupSizes.Clone(); - set - { - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - - VerifyWritable(); - int[] inputSizes = (int[])value.Clone(); - CheckGroupSize(nameof(value), inputSizes); - _percentGroupSizes = inputSizes; - } - } - - public string CurrencyGroupSeparator - { - get => _currencyGroupSeparator; - set - { - VerifyWritable(); - VerifyGroupSeparator(value, nameof(value)); - _currencyGroupSeparator = value; - } - } - - public string CurrencySymbol - { - get => _currencySymbol; - set - { - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - - VerifyWritable(); - _currencySymbol = value; - } - } - - /// <summary> - /// Returns the current culture's NumberFormatInfo. Used by Parse methods. - /// </summary> - - public static NumberFormatInfo CurrentInfo - { - get - { - System.Globalization.CultureInfo culture = CultureInfo.CurrentCulture; - if (!culture._isInherited) - { - NumberFormatInfo? info = culture._numInfo; - if (info != null) - { - return info; - } - } - // returns non-nullable when passed typeof(NumberFormatInfo) - return (NumberFormatInfo)culture.GetFormat(typeof(NumberFormatInfo))!; - } - } - - public string NaNSymbol - { - get => _nanSymbol; - set - { - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - - VerifyWritable(); - _nanSymbol = value; - } - } - - public int CurrencyNegativePattern - { - get => _currencyNegativePattern; - set - { - if (value < 0 || value > 15) - { - throw new ArgumentOutOfRangeException( - nameof(value), - value, - SR.Format(SR.ArgumentOutOfRange_Range, 0, 15)); - } - - VerifyWritable(); - _currencyNegativePattern = value; - } - } - - public int NumberNegativePattern - { - get => _numberNegativePattern; - set - { - // NOTENOTE: the range of value should correspond to negNumberFormats[] in vm\COMNumber.cpp. - if (value < 0 || value > 4) - { - throw new ArgumentOutOfRangeException( - nameof(value), - value, - SR.Format(SR.ArgumentOutOfRange_Range, 0, 4)); - } - - VerifyWritable(); - _numberNegativePattern = value; - } - } - - public int PercentPositivePattern - { - get => _percentPositivePattern; - set - { - // NOTENOTE: the range of value should correspond to posPercentFormats[] in vm\COMNumber.cpp. - if (value < 0 || value > 3) - { - throw new ArgumentOutOfRangeException( - nameof(value), - value, - SR.Format(SR.ArgumentOutOfRange_Range, 0, 3)); - } - - VerifyWritable(); - _percentPositivePattern = value; - } - } - - public int PercentNegativePattern - { - get => _percentNegativePattern; - set - { - // NOTENOTE: the range of value should correspond to posPercentFormats[] in vm\COMNumber.cpp. - if (value < 0 || value > 11) - { - throw new ArgumentOutOfRangeException( - nameof(value), - value, - SR.Format(SR.ArgumentOutOfRange_Range, 0, 11)); - } - - VerifyWritable(); - _percentNegativePattern = value; - } - } - - public string NegativeInfinitySymbol - { - get => _negativeInfinitySymbol; - set - { - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - - VerifyWritable(); - _negativeInfinitySymbol = value; - } - } - - public string NegativeSign - { - get => _negativeSign; - set - { - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - - VerifyWritable(); - _negativeSign = value; - UpdateHasInvariantNumberSigns(); - } - } - - public int NumberDecimalDigits - { - get => _numberDecimalDigits; - set - { - if (value < 0 || value > 99) - { - throw new ArgumentOutOfRangeException( - nameof(value), - value, - SR.Format(SR.ArgumentOutOfRange_Range, 0, 99)); - } - - VerifyWritable(); - _numberDecimalDigits = value; - } - } - - public string NumberDecimalSeparator - { - get => _numberDecimalSeparator; - set - { - VerifyWritable(); - VerifyDecimalSeparator(value, nameof(value)); - _numberDecimalSeparator = value; - } - } - - public string NumberGroupSeparator - { - get => _numberGroupSeparator; - set - { - VerifyWritable(); - VerifyGroupSeparator(value, nameof(value)); - _numberGroupSeparator = value; - } - } - - public int CurrencyPositivePattern - { - get => _currencyPositivePattern; - set - { - if (value < 0 || value > 3) - { - throw new ArgumentOutOfRangeException( - nameof(value), - value, - SR.Format(SR.ArgumentOutOfRange_Range, 0, 3)); - } - - VerifyWritable(); - _currencyPositivePattern = value; - } - } - - public string PositiveInfinitySymbol - { - get => _positiveInfinitySymbol; - set - { - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - - VerifyWritable(); - _positiveInfinitySymbol = value; - } - } - - public string PositiveSign - { - get => _positiveSign; - set - { - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - - VerifyWritable(); - _positiveSign = value; - UpdateHasInvariantNumberSigns(); - } - } - - public int PercentDecimalDigits - { - get => _percentDecimalDigits; - set - { - if (value < 0 || value > 99) - { - throw new ArgumentOutOfRangeException( - nameof(value), - value, - SR.Format(SR.ArgumentOutOfRange_Range, 0, 99)); - } - - VerifyWritable(); - _percentDecimalDigits = value; - } - } - - public string PercentDecimalSeparator - { - get => _percentDecimalSeparator; - set - { - VerifyWritable(); - VerifyDecimalSeparator(value, nameof(value)); - _percentDecimalSeparator = value; - } - } - - public string PercentGroupSeparator - { - get => _percentGroupSeparator; - set - { - VerifyWritable(); - VerifyGroupSeparator(value, nameof(value)); - _percentGroupSeparator = value; - } - } - - public string PercentSymbol - { - get => _percentSymbol; - set - { - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - - VerifyWritable(); - _percentSymbol = value; - } - } - - public string PerMilleSymbol - { - get => _perMilleSymbol; - set - { - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - - VerifyWritable(); - _perMilleSymbol = value; - } - } - - public string[] NativeDigits - { - get => (string[])_nativeDigits.Clone(); - set - { - VerifyWritable(); - VerifyNativeDigits(value, nameof(value)); - _nativeDigits = value; - } - } - - public DigitShapes DigitSubstitution - { - get => (DigitShapes)_digitSubstitution; - set - { - VerifyWritable(); - VerifyDigitSubstitution(value, nameof(value)); - _digitSubstitution = (int)value; - } - } - - public object? GetFormat(Type? formatType) - { - return formatType == typeof(NumberFormatInfo) ? this : null; - } - - public static NumberFormatInfo ReadOnly(NumberFormatInfo nfi) - { - if (nfi == null) - { - throw new ArgumentNullException(nameof(nfi)); - } - - if (nfi.IsReadOnly) - { - return nfi; - } - - NumberFormatInfo info = (NumberFormatInfo)(nfi.MemberwiseClone()); - info._isReadOnly = true; - return info; - } - - // private const NumberStyles InvalidNumberStyles = unchecked((NumberStyles) 0xFFFFFC00); - private const NumberStyles InvalidNumberStyles = ~(NumberStyles.AllowLeadingWhite | NumberStyles.AllowTrailingWhite - | NumberStyles.AllowLeadingSign | NumberStyles.AllowTrailingSign - | NumberStyles.AllowParentheses | NumberStyles.AllowDecimalPoint - | NumberStyles.AllowThousands | NumberStyles.AllowExponent - | NumberStyles.AllowCurrencySymbol | NumberStyles.AllowHexSpecifier); - - internal static void ValidateParseStyleInteger(NumberStyles style) - { - // Check for undefined flags or invalid hex number flags - if ((style & (InvalidNumberStyles | NumberStyles.AllowHexSpecifier)) != 0 - && (style & ~NumberStyles.HexNumber) != 0) - { - throwInvalid(style); - - void throwInvalid(NumberStyles value) - { - if ((value & InvalidNumberStyles) != 0) - { - throw new ArgumentException(SR.Argument_InvalidNumberStyles, nameof(style)); - } - - throw new ArgumentException(SR.Arg_InvalidHexStyle); - } - } - } - - internal static void ValidateParseStyleFloatingPoint(NumberStyles style) - { - // Check for undefined flags or hex number - if ((style & (InvalidNumberStyles | NumberStyles.AllowHexSpecifier)) != 0) - { - throwInvalid(style); - - void throwInvalid(NumberStyles value) - { - if ((value & InvalidNumberStyles) != 0) - { - throw new ArgumentException(SR.Argument_InvalidNumberStyles, nameof(style)); - } - - throw new ArgumentException(SR.Arg_HexStyleNotSupported); - } - } - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/NumberStyles.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/NumberStyles.cs deleted file mode 100644 index cf5a081016a..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/NumberStyles.cs +++ /dev/null @@ -1,70 +0,0 @@ -// 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 -{ - /// <summary> - /// Contains valid formats for Numbers recognized by the Number - /// class' parsing code. - /// </summary> - [Flags] - public enum NumberStyles - { - None = 0x00000000, - - /// <summary> - /// Bit flag indicating that leading whitespace is allowed. Character values - /// 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, and 0x0020 are considered to be - /// whitespace. - /// </summary> - AllowLeadingWhite = 0x00000001, - - /// <summary> - /// Bitflag indicating trailing whitespace is allowed. - /// </summary> - AllowTrailingWhite = 0x00000002, - - /// <summary> - /// Can the number start with a sign char specified by - /// NumberFormatInfo.PositiveSign and NumberFormatInfo.NegativeSign - /// </summary> - AllowLeadingSign = 0x00000004, - - /// <summary> - /// Allow the number to end with a sign char - /// </summary> - AllowTrailingSign = 0x00000008, - - /// <summary> - /// Allow the number to be enclosed in parens - /// </summary> - AllowParentheses = 0x00000010, - - AllowDecimalPoint = 0x00000020, - - AllowThousands = 0x00000040, - - AllowExponent = 0x00000080, - - AllowCurrencySymbol = 0x00000100, - - AllowHexSpecifier = 0x00000200, - - Integer = AllowLeadingWhite | AllowTrailingWhite | AllowLeadingSign, - - HexNumber = AllowLeadingWhite | AllowTrailingWhite | AllowHexSpecifier, - - Number = AllowLeadingWhite | AllowTrailingWhite | AllowLeadingSign | AllowTrailingSign | - AllowDecimalPoint | AllowThousands, - - Float = AllowLeadingWhite | AllowTrailingWhite | AllowLeadingSign | - AllowDecimalPoint | AllowExponent, - - Currency = AllowLeadingWhite | AllowTrailingWhite | AllowLeadingSign | AllowTrailingSign | - AllowParentheses | AllowDecimalPoint | AllowThousands | AllowCurrencySymbol, - - Any = AllowLeadingWhite | AllowTrailingWhite | AllowLeadingSign | AllowTrailingSign | - AllowParentheses | AllowDecimalPoint | AllowThousands | AllowCurrencySymbol | AllowExponent, - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/PersianCalendar.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/PersianCalendar.cs deleted file mode 100644 index 40268efb18d..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/PersianCalendar.cs +++ /dev/null @@ -1,418 +0,0 @@ -// 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; - -namespace System.Globalization -{ - /// <summary> - /// Modern Persian calendar is a solar observation based calendar. Each new year begins on the day when the vernal equinox occurs before noon. - /// The epoch is the date of the vernal equinox prior to the epoch of the Islamic calendar (March 19, 622 Julian or March 22, 622 Gregorian) - /// There is no Persian year 0. Ordinary years have 365 days. Leap years have 366 days with the last month (Esfand) gaining the extra day. - /// </summary> - /// <remarks> - /// Calendar support range: - /// Calendar Minimum Maximum - /// ========== ========== ========== - /// Gregorian 0622/03/22 9999/12/31 - /// Persian 0001/01/01 9378/10/13 - /// </remarks> - public class PersianCalendar : Calendar - { - public static readonly int PersianEra = 1; - - private static readonly long s_persianEpoch = new DateTime(622, 3, 22).Ticks / GregorianCalendar.TicksPerDay; - private const int ApproximateHalfYear = 180; - - private const int DatePartYear = 0; - private const int DatePartDayOfYear = 1; - private const int DatePartMonth = 2; - private const int DatePartDay = 3; - private const int MonthsPerYear = 12; - - private static readonly int[] s_daysToMonth = { 0, 31, 62, 93, 124, 155, 186, 216, 246, 276, 306, 336, 366 }; - - private const int MaxCalendarYear = 9378; - private const int MaxCalendarMonth = 10; - private const int MaxCalendarDay = 13; - - // Persian calendar (year: 1, month: 1, day:1 ) = Gregorian (year: 622, month: 3, day: 22) - // This is the minimal Gregorian date that we support in the PersianCalendar. - private static readonly DateTime s_minDate = new DateTime(622, 3, 22); - private static readonly DateTime s_maxDate = DateTime.MaxValue; - - public override DateTime MinSupportedDateTime => s_minDate; - - public override DateTime MaxSupportedDateTime => s_maxDate; - - public override CalendarAlgorithmType AlgorithmType => CalendarAlgorithmType.SolarCalendar; - - public PersianCalendar() - { - } - - internal override CalendarId BaseCalendarID => CalendarId.GREGORIAN; - - internal override CalendarId ID => CalendarId.PERSIAN; - - private long GetAbsoluteDatePersian(int year, int month, int day) - { - if (year < 1 || year > MaxCalendarYear || month < 1 || month > 12) - { - throw new ArgumentOutOfRangeException(null, SR.ArgumentOutOfRange_BadYearMonthDay); - } - - // day is one based, make 0 based since this will be the number of days we add to beginning of year below - int ordinalDay = DaysInPreviousMonths(month) + day - 1; - int approximateDaysFromEpochForYearStart = (int)(CalendricalCalculationsHelper.MeanTropicalYearInDays * (year - 1)); - long yearStart = CalendricalCalculationsHelper.PersianNewYearOnOrBefore(s_persianEpoch + approximateDaysFromEpochForYearStart + ApproximateHalfYear); - yearStart += ordinalDay; - return yearStart; - } - - internal static void CheckTicksRange(long ticks) - { - if (ticks < s_minDate.Ticks || ticks > s_maxDate.Ticks) - { - throw new ArgumentOutOfRangeException( - "time", - ticks, - SR.Format(SR.ArgumentOutOfRange_CalendarRange, s_minDate, s_maxDate)); - } - } - - internal static void CheckEraRange(int era) - { - if (era != CurrentEra && era != PersianEra) - { - throw new ArgumentOutOfRangeException(nameof(era), era, SR.ArgumentOutOfRange_InvalidEraValue); - } - } - - internal static void CheckYearRange(int year, int era) - { - CheckEraRange(era); - if (year < 1 || year > MaxCalendarYear) - { - throw new ArgumentOutOfRangeException( - nameof(year), - year, - SR.Format(SR.ArgumentOutOfRange_Range, 1, MaxCalendarYear)); - } - } - - internal static void CheckYearMonthRange(int year, int month, int era) - { - CheckYearRange(year, era); - if (year == MaxCalendarYear) - { - if (month > MaxCalendarMonth) - { - throw new ArgumentOutOfRangeException( - nameof(month), - month, - SR.Format(SR.ArgumentOutOfRange_Range, 1, MaxCalendarMonth)); - } - } - - if (month < 1 || month > 12) - { - throw new ArgumentOutOfRangeException(nameof(month), month, SR.ArgumentOutOfRange_Month); - } - } - - private static int MonthFromOrdinalDay(int ordinalDay) - { - Debug.Assert(ordinalDay <= 366); - int index = 0; - while (ordinalDay > s_daysToMonth[index]) - { - index++; - } - - return index; - } - - private static int DaysInPreviousMonths(int month) - { - Debug.Assert(1 <= month && month <= 12); - // months are one based but for calculations use 0 based - --month; - return s_daysToMonth[month]; - } - - internal int GetDatePart(long ticks, int part) - { - CheckTicksRange(ticks); - - // Get the absolute date. The absolute date is the number of days from January 1st, 1 A.D. - // 1/1/0001 is absolute date 1. - long numDays = ticks / GregorianCalendar.TicksPerDay + 1; - - // Calculate the appromixate Persian Year. - long yearStart = CalendricalCalculationsHelper.PersianNewYearOnOrBefore(numDays); - int y = (int)(Math.Floor(((yearStart - s_persianEpoch) / CalendricalCalculationsHelper.MeanTropicalYearInDays) + 0.5)) + 1; - Debug.Assert(y >= 1); - - if (part == DatePartYear) - { - return y; - } - - // Calculate the Persian Month. - int ordinalDay = (int)(numDays - CalendricalCalculationsHelper.GetNumberOfDays(this.ToDateTime(y, 1, 1, 0, 0, 0, 0, 1))); - if (part == DatePartDayOfYear) - { - return ordinalDay; - } - - int m = MonthFromOrdinalDay(ordinalDay); - Debug.Assert(ordinalDay >= 1); - Debug.Assert(m >= 1 && m <= 12); - if (part == DatePartMonth) - { - return m; - } - - int d = ordinalDay - DaysInPreviousMonths(m); - Debug.Assert(1 <= d); - Debug.Assert(d <= 31); - - // Calculate the Persian Day. - if (part == DatePartDay) - { - return d; - } - - // Incorrect part value. - throw new InvalidOperationException(SR.InvalidOperation_DateTimeParsing); - } - - public override DateTime AddMonths(DateTime time, int months) - { - if (months < -120000 || months > 120000) - { - throw new ArgumentOutOfRangeException( - nameof(months), - months, - SR.Format(SR.ArgumentOutOfRange_Range, -120000, 120000)); - } - - // Get the date in Persian calendar. - int y = GetDatePart(time.Ticks, DatePartYear); - int m = GetDatePart(time.Ticks, DatePartMonth); - int d = GetDatePart(time.Ticks, DatePartDay); - int i = m - 1 + months; - if (i >= 0) - { - m = i % 12 + 1; - y += i / 12; - } - else - { - m = 12 + (i + 1) % 12; - y += (i - 11) / 12; - } - int days = GetDaysInMonth(y, m); - if (d > days) - { - d = days; - } - - long ticks = GetAbsoluteDatePersian(y, m, d) * TicksPerDay + time.Ticks % TicksPerDay; - Calendar.CheckAddResult(ticks, MinSupportedDateTime, MaxSupportedDateTime); - return new DateTime(ticks); - } - - public override DateTime AddYears(DateTime time, int years) - { - return AddMonths(time, years * 12); - } - - public override int GetDayOfMonth(DateTime time) - { - return GetDatePart(time.Ticks, DatePartDay); - } - - public override DayOfWeek GetDayOfWeek(DateTime time) - { - return (DayOfWeek)((int)(time.Ticks / TicksPerDay + 1) % 7); - } - - public override int GetDayOfYear(DateTime time) - { - return GetDatePart(time.Ticks, DatePartDayOfYear); - } - - public override int GetDaysInMonth(int year, int month, int era) - { - CheckYearMonthRange(year, month, era); - - if ((month == MaxCalendarMonth) && (year == MaxCalendarYear)) - { - return MaxCalendarDay; - } - - int daysInMonth = s_daysToMonth[month] - s_daysToMonth[month - 1]; - if ((month == MonthsPerYear) && !IsLeapYear(year)) - { - Debug.Assert(daysInMonth == 30); - --daysInMonth; - } - - return daysInMonth; - } - - public override int GetDaysInYear(int year, int era) - { - CheckYearRange(year, era); - if (year == MaxCalendarYear) - { - return s_daysToMonth[MaxCalendarMonth - 1] + MaxCalendarDay; - } - - return IsLeapYear(year, CurrentEra) ? 366 : 365; - } - - public override int GetEra(DateTime time) - { - CheckTicksRange(time.Ticks); - return PersianEra; - } - - public override int[] Eras => new int[] { PersianEra }; - - public override int GetMonth(DateTime time) - { - return GetDatePart(time.Ticks, DatePartMonth); - } - - public override int GetMonthsInYear(int year, int era) - { - CheckYearRange(year, era); - if (year == MaxCalendarYear) - { - return MaxCalendarMonth; - } - - return 12; - } - - public override int GetYear(DateTime time) - { - return GetDatePart(time.Ticks, DatePartYear); - } - - public override bool IsLeapDay(int year, int month, int day, int era) - { - // The year/month/era value checking is done in GetDaysInMonth(). - int daysInMonth = GetDaysInMonth(year, month, era); - if (day < 1 || day > daysInMonth) - { - throw new ArgumentOutOfRangeException( - nameof(day), - day, - SR.Format(SR.ArgumentOutOfRange_Day, daysInMonth, month)); - } - - return IsLeapYear(year, era) && month == 12 && day == 30; - } - - public override int GetLeapMonth(int year, int era) - { - CheckYearRange(year, era); - return 0; - } - - public override bool IsLeapMonth(int year, int month, int era) - { - CheckYearMonthRange(year, month, era); - return false; - } - - public override bool IsLeapYear(int year, int era) - { - CheckYearRange(year, era); - - if (year == MaxCalendarYear) - { - return false; - } - - return (GetAbsoluteDatePersian(year + 1, 1, 1) - GetAbsoluteDatePersian(year, 1, 1)) == 366; - } - - public override DateTime ToDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int era) - { - // The year/month/era checking is done in GetDaysInMonth(). - int daysInMonth = GetDaysInMonth(year, month, era); - if (day < 1 || day > daysInMonth) - { - throw new ArgumentOutOfRangeException( - nameof(day), - day, - SR.Format(SR.ArgumentOutOfRange_Day, daysInMonth, month)); - } - - long lDate = GetAbsoluteDatePersian(year, month, day); - - if (lDate < 0) - { - throw new ArgumentOutOfRangeException(null, SR.ArgumentOutOfRange_BadYearMonthDay); - } - - return new DateTime(lDate * GregorianCalendar.TicksPerDay + TimeToTicks(hour, minute, second, millisecond)); - } - - private const int DefaultTwoDigitYearMax = 1410; - - public override int TwoDigitYearMax - { - get - { - if (_twoDigitYearMax == -1) - { - _twoDigitYearMax = GetSystemTwoDigitYearSetting(ID, DefaultTwoDigitYearMax); - } - - return _twoDigitYearMax; - } - set - { - VerifyWritable(); - if (value < 99 || value > MaxCalendarYear) - { - throw new ArgumentOutOfRangeException( - nameof(value), - value, - SR.Format(SR.ArgumentOutOfRange_Range, 99, MaxCalendarYear)); - } - - _twoDigitYearMax = value; - } - } - - public override int ToFourDigitYear(int year) - { - if (year < 0) - { - throw new ArgumentOutOfRangeException(nameof(year), year, SR.ArgumentOutOfRange_NeedNonNegNum); - } - if (year < 100) - { - return base.ToFourDigitYear(year); - } - - if (year > MaxCalendarYear) - { - throw new ArgumentOutOfRangeException( - nameof(year), - year, - SR.Format(SR.ArgumentOutOfRange_Range, 1, MaxCalendarYear)); - } - - return year; - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/RegionInfo.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/RegionInfo.cs deleted file mode 100644 index ccaa806adb6..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/RegionInfo.cs +++ /dev/null @@ -1,198 +0,0 @@ -// 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; - -namespace System.Globalization -{ - /// <summary> - /// This class represents settings specified by de jure or de facto - /// standards for a particular country/region. In contrast to - /// CultureInfo, the RegionInfo does not represent preferences of the - /// user and does not depend on the user's language or culture. - /// </summary> - public class RegionInfo - { - // Name of this region (ie: es-US): serialized, the field used for deserialization - private string _name; - - // The CultureData instance that we are going to read data from. - private readonly CultureData _cultureData; - - // The RegionInfo for our current region - internal static volatile RegionInfo? s_currentRegionInfo; - - public RegionInfo(string name) - { - if (name == null) - { - throw new ArgumentNullException(nameof(name)); - } - - // The InvariantCulture has no matching region - if (name.Length == 0) - { - throw new ArgumentException(SR.Argument_NoRegionInvariantCulture, nameof(name)); - } - - // For CoreCLR we only want the region names that are full culture names - _cultureData = CultureData.GetCultureDataForRegion(name, true) ?? - throw new ArgumentException(SR.Format(SR.Argument_InvalidCultureName, name), nameof(name)); - - // Not supposed to be neutral - if (_cultureData.IsNeutralCulture) - { - throw new ArgumentException(SR.Format(SR.Argument_InvalidNeutralRegionName, name), nameof(name)); - } - - _name = _cultureData.RegionName; - } - - public RegionInfo(int culture) - { - // The InvariantCulture has no matching region - if (culture == CultureInfo.LOCALE_INVARIANT) - { - throw new ArgumentException(SR.Argument_NoRegionInvariantCulture); - } - - if (culture == CultureInfo.LOCALE_NEUTRAL) - { - // Not supposed to be neutral - throw new ArgumentException(SR.Format(SR.Argument_CultureIsNeutral, culture), nameof(culture)); - } - - if (culture == CultureInfo.LOCALE_CUSTOM_DEFAULT) - { - // Not supposed to be neutral - throw new ArgumentException(SR.Format(SR.Argument_CustomCultureCannotBePassedByNumber, culture), nameof(culture)); - } - - _cultureData = CultureData.GetCultureData(culture, true); - _name = _cultureData.RegionName; - - if (_cultureData.IsNeutralCulture) - { - // Not supposed to be neutral - throw new ArgumentException(SR.Format(SR.Argument_CultureIsNeutral, culture), nameof(culture)); - } - } - - internal RegionInfo(CultureData cultureData) - { - _cultureData = cultureData; - _name = _cultureData.RegionName; - } - - /// <summary> - /// This instance provides methods based on the current user settings. - /// These settings are volatile and may change over the lifetime of the - /// </summary> - public static RegionInfo CurrentRegion - { - get - { - RegionInfo? temp = s_currentRegionInfo; - if (temp == null) - { - temp = new RegionInfo(CultureInfo.CurrentCulture._cultureData); - - // Need full name for custom cultures - temp._name = temp._cultureData.RegionName; - s_currentRegionInfo = temp; - } - return temp; - } - } - - /// <summary> - /// Returns the name of the region (ie: en-US) - /// </summary> - public virtual string Name - { - get - { - Debug.Assert(_name != null, "Expected RegionInfo._name to be populated already"); - return _name; - } - } - - /// <summary> - /// Returns the name of the region in English. (ie: United States) - /// </summary> - public virtual string EnglishName => _cultureData.EnglishCountryName; - - /// <summary> - /// Returns the display name (localized) of the region. (ie: United States - /// if the current UI language is en-US) - /// </summary> - public virtual string DisplayName => _cultureData.LocalizedCountryName; - - /// <summary> - /// Returns the native name of the region. (ie: Deutschland) - /// WARNING: You need a full locale name for this to make sense. - /// </summary> - public virtual string NativeName => _cultureData.NativeCountryName; - - /// <summary> - /// Returns the two letter ISO region name (ie: US) - /// </summary> - public virtual string TwoLetterISORegionName => _cultureData.TwoLetterISOCountryName; - - /// <summary> - /// Returns the three letter ISO region name (ie: USA) - /// </summary> - public virtual string ThreeLetterISORegionName => _cultureData.ThreeLetterISOCountryName; - - /// <summary> - /// Returns the three letter windows region name (ie: USA) - /// </summary> - public virtual string ThreeLetterWindowsRegionName => ThreeLetterISORegionName; - - - /// <summary> - /// Returns true if this region uses the metric measurement system - /// </summary> - public virtual bool IsMetric => _cultureData.MeasurementSystem == 0; - - public virtual int GeoId => _cultureData.GeoId; - - /// <summary> - /// English name for this region's currency, ie: Swiss Franc - /// </summary> - public virtual string CurrencyEnglishName => _cultureData.CurrencyEnglishName; - - /// <summary> - /// Native name for this region's currency, ie: Schweizer Franken - /// WARNING: You need a full locale name for this to make sense. - /// </summary> - public virtual string CurrencyNativeName => _cultureData.CurrencyNativeName; - - /// <summary> - /// Currency Symbol for this locale, ie: Fr. or $ - /// </summary> - public virtual string CurrencySymbol => _cultureData.CurrencySymbol; - - /// <summary> - /// ISO Currency Symbol for this locale, ie: CHF - /// </summary> - public virtual string ISOCurrencySymbol => _cultureData.ISOCurrencySymbol; - - /// <summary> - /// Implements Object.Equals(). Returns a boolean indicating whether - /// or not object refers to the same RegionInfo as the current instance. - /// RegionInfos are considered equal if and only if they have the same name - /// (ie: en-US) - /// </summary> - public override bool Equals(object? value) - { - return value is RegionInfo otherRegion - && Name.Equals(otherRegion.Name); - } - - public override int GetHashCode() => Name.GetHashCode(); - - public override string ToString() => Name; - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/SortKey.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/SortKey.cs deleted file mode 100644 index b69cf9f5513..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/SortKey.cs +++ /dev/null @@ -1,110 +0,0 @@ -// 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; - -namespace System.Globalization -{ - /// <summary> - /// This class implements a set of methods for retrieving - /// </summary> - public partial class SortKey - { - private readonly string _localeName; - private readonly CompareOptions _options; - private readonly string _string; - private readonly byte[] _keyData; - - /// <summary> - /// The following constructor is designed to be called from CompareInfo to get the - /// the sort key of specific string for synthetic culture - /// </summary> - internal SortKey(string localeName, string str, CompareOptions options, byte[] keyData) - { - _keyData = keyData; - _localeName = localeName; - _options = options; - _string = str; - } - - /// <summary> - /// Returns the original string used to create the current instance - /// of SortKey. - /// </summary> - public virtual string OriginalString => _string; - - /// <summary> - /// Returns a byte array representing the current instance of the - /// sort key. - /// </summary> - public virtual byte[] KeyData => (byte[])_keyData.Clone(); - - /// <summary> - /// Compares the two sort keys. Returns 0 if the two sort keys are - /// equal, a number less than 0 if sortkey1 is less than sortkey2, - /// and a number greater than 0 if sortkey1 is greater than sortkey2. - /// </summary> - public static int Compare(SortKey sortkey1, SortKey sortkey2) - { - if (sortkey1 == null) - { - throw new ArgumentNullException(nameof(sortkey1)); - } - if (sortkey2 == null) - { - throw new ArgumentNullException(nameof(sortkey2)); - } - - byte[] key1Data = sortkey1._keyData; - byte[] key2Data = sortkey2._keyData; - - Debug.Assert(key1Data != null, "key1Data != null"); - Debug.Assert(key2Data != null, "key2Data != null"); - - if (key1Data.Length == 0) - { - if (key2Data.Length == 0) - { - return 0; - } - - return -1; - } - if (key2Data.Length == 0) - { - return 1; - } - - int compLen = (key1Data.Length < key2Data.Length) ? key1Data.Length : key2Data.Length; - for (int i = 0; i < compLen; i++) - { - if (key1Data[i] > key2Data[i]) - { - return 1; - } - if (key1Data[i] < key2Data[i]) - { - return -1; - } - } - - return 0; - } - - public override bool Equals(object? value) - { - return value is SortKey otherSortKey && Compare(this, otherSortKey) == 0; - } - - public override int GetHashCode() - { - return CompareInfo.GetCompareInfo(_localeName).GetHashCodeOfString(_string, _options); - } - - public override string ToString() - { - return "SortKey - " + _localeName + ", " + _options + ", " + _string; - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/SortVersion.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/SortVersion.cs deleted file mode 100644 index 2cac2389d9f..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/SortVersion.cs +++ /dev/null @@ -1,83 +0,0 @@ -// 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.CompilerServices; - -namespace System.Globalization -{ - [Serializable] - [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] - public sealed class SortVersion : -#nullable disable // to enable use with both T and T? for reference types due to IEquatable<T> being invariant - IEquatable<SortVersion> -#nullable restore - { - private readonly int m_NlsVersion; // Do not rename (binary serialization) - private Guid m_SortId; // Do not rename (binary serialization) - - public int FullVersion => m_NlsVersion; - - public Guid SortId => m_SortId; - - public SortVersion(int fullVersion, Guid sortId) - { - m_SortId = sortId; - m_NlsVersion = fullVersion; - } - - internal SortVersion(int nlsVersion, int effectiveId, Guid customVersion) - { - m_NlsVersion = nlsVersion; - - if (customVersion == Guid.Empty) - { - byte b1 = (byte)(effectiveId >> 24); - byte b2 = (byte)((effectiveId & 0x00FF0000) >> 16); - byte b3 = (byte)((effectiveId & 0x0000FF00) >> 8); - byte b4 = (byte)(effectiveId & 0xFF); - customVersion = new Guid(0, 0, 0, 0, 0, 0, 0, b1, b2, b3, b4); - } - - m_SortId = customVersion; - } - - public override bool Equals(object? obj) - { - return obj is SortVersion otherVersion && Equals(otherVersion); - } - - public bool Equals(SortVersion? other) - { - if (other == null) - { - return false; - } - - return m_NlsVersion == other.m_NlsVersion && m_SortId == other.m_SortId; - } - - public override int GetHashCode() - { - return m_NlsVersion * 7 | m_SortId.GetHashCode(); - } - - // Force inline as the true/false ternary takes it above ALWAYS_INLINE size even though the asm ends up smaller - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(SortVersion? left, SortVersion? right) - { - // Test "right" first to allow branch elimination when inlined for null checks (== null) - // so it can become a simple test - if (right is null) - { - // return true/false not the test result https://github.com/dotnet/coreclr/issues/914 - return (left is null) ? true : false; - } - - return right.Equals(left); - } - - public static bool operator !=(SortVersion? left, SortVersion? right) => - !(left == right); - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/StringInfo.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/StringInfo.cs deleted file mode 100644 index f82d3f618c1..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/StringInfo.cs +++ /dev/null @@ -1,296 +0,0 @@ -// 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; - -namespace System.Globalization -{ - /// <summary> - /// This class defines behaviors specific to a writing system. - /// A writing system is the collection of scripts and orthographic rules - /// required to represent a language as text. - /// </summary> - public class StringInfo - { - private string _str = null!; // initialized in helper called by ctors - - private int[]? _indexes; - - public StringInfo() : this(string.Empty) - { - } - - public StringInfo(string value) - { - this.String = value; - } - - public override bool Equals(object? value) - { - return value is StringInfo otherStringInfo - && _str.Equals(otherStringInfo._str); - } - - public override int GetHashCode() => _str.GetHashCode(); - - /// <summary> - /// Our zero-based array of index values into the string. Initialize if - /// our private array is not yet, in fact, initialized. - /// </summary> - private int[]? Indexes - { - get - { - if (_indexes == null && String.Length > 0) - { - _indexes = StringInfo.ParseCombiningCharacters(String); - } - - return _indexes; - } - } - - public string String - { - get => _str; - set - { - _str = value ?? throw new ArgumentNullException(nameof(value)); - _indexes = null; - } - } - - public int LengthInTextElements => Indexes?.Length ?? 0; - - public string SubstringByTextElements(int startingTextElement) - { - // If the string is empty, no sense going further. - if (Indexes == null) - { - if (startingTextElement < 0) - { - throw new ArgumentOutOfRangeException(nameof(startingTextElement), startingTextElement, SR.ArgumentOutOfRange_NeedPosNum); - } - else - { - throw new ArgumentOutOfRangeException(nameof(startingTextElement), startingTextElement, SR.Arg_ArgumentOutOfRangeException); - } - } - - return SubstringByTextElements(startingTextElement, Indexes.Length - startingTextElement); - } - - public string SubstringByTextElements(int startingTextElement, int lengthInTextElements) - { - if (startingTextElement < 0) - { - throw new ArgumentOutOfRangeException(nameof(startingTextElement), startingTextElement, SR.ArgumentOutOfRange_NeedPosNum); - } - if (String.Length == 0 || startingTextElement >= Indexes!.Length) - { - throw new ArgumentOutOfRangeException(nameof(startingTextElement), startingTextElement, SR.Arg_ArgumentOutOfRangeException); - } - if (lengthInTextElements < 0) - { - throw new ArgumentOutOfRangeException(nameof(lengthInTextElements), lengthInTextElements, SR.ArgumentOutOfRange_NeedPosNum); - } - if (startingTextElement > Indexes.Length - lengthInTextElements) - { - throw new ArgumentOutOfRangeException(nameof(lengthInTextElements), lengthInTextElements, SR.Arg_ArgumentOutOfRangeException); - } - - int start = Indexes[startingTextElement]; - - if (startingTextElement + lengthInTextElements == Indexes.Length) - { - // We are at the last text element in the string and because of that - // must handle the call differently. - return String.Substring(start); - } - else - { - return String[start..Indexes[lengthInTextElements + startingTextElement]]; - } - } - - public static string GetNextTextElement(string str) => GetNextTextElement(str, 0); - - /// <summary> - /// Get the code point count of the current text element. - /// - /// A combining class is defined as: - /// A character/surrogate that has the following Unicode category: - /// * NonSpacingMark (e.g. U+0300 COMBINING GRAVE ACCENT) - /// * SpacingCombiningMark (e.g. U+ 0903 DEVANGARI SIGN VISARGA) - /// * EnclosingMark (e.g. U+20DD COMBINING ENCLOSING CIRCLE) - /// - /// In the context of GetNextTextElement() and ParseCombiningCharacters(), a text element is defined as: - /// 1. If a character/surrogate is in the following category, it is a text element. - /// It can NOT further combine with characters in the combinging class to form a text element. - /// * one of the Unicode category in the combinging class - /// * UnicodeCategory.Format - /// * UnicodeCateogry.Control - /// * UnicodeCategory.OtherNotAssigned - /// 2. Otherwise, the character/surrogate can be combined with characters in the combinging class to form a text element. - /// </summary> - /// <returns>The length of the current text element</returns> - internal static int GetCurrentTextElementLen(string str, int index, int len, ref UnicodeCategory ucCurrent, ref int currentCharCount) - { - Debug.Assert(index >= 0 && len >= 0, "StringInfo.GetCurrentTextElementLen() : index = " + index + ", len = " + len); - Debug.Assert(index < len, "StringInfo.GetCurrentTextElementLen() : index = " + index + ", len = " + len); - if (index + currentCharCount == len) - { - // This is the last character/surrogate in the string. - return currentCharCount; - } - - // Call an internal GetUnicodeCategory, which will tell us both the unicode category, and also tell us if it is a surrogate pair or not. - int nextCharCount; - UnicodeCategory ucNext = CharUnicodeInfo.InternalGetUnicodeCategory(str, index + currentCharCount, out nextCharCount); - if (CharUnicodeInfo.IsCombiningCategory(ucNext)) - { - // The next element is a combining class. - // Check if the current text element to see if it is a valid base category (i.e. it should not be a combining category, - // not a format character, and not a control character). - if (CharUnicodeInfo.IsCombiningCategory(ucCurrent) - || (ucCurrent == UnicodeCategory.Format) - || (ucCurrent == UnicodeCategory.Control) - || (ucCurrent == UnicodeCategory.OtherNotAssigned) - || (ucCurrent == UnicodeCategory.Surrogate)) // An unpair high surrogate or low surrogate - { - // Will fall thru and return the currentCharCount - } - else - { - // Remember the current index. - int startIndex = index; - - // We have a valid base characters, and we have a character (or surrogate) that is combining. - // Check if there are more combining characters to follow. - // Check if the next character is a nonspacing character. - index += currentCharCount + nextCharCount; - - while (index < len) - { - ucNext = CharUnicodeInfo.InternalGetUnicodeCategory(str, index, out nextCharCount); - if (!CharUnicodeInfo.IsCombiningCategory(ucNext)) - { - ucCurrent = ucNext; - currentCharCount = nextCharCount; - break; - } - index += nextCharCount; - } - - return index - startIndex; - } - } - - // The return value will be the currentCharCount. - int ret = currentCharCount; - ucCurrent = ucNext; - // Update currentCharCount. - currentCharCount = nextCharCount; - return ret; - } - - /// <summary> - /// Returns the str containing the next text element in str starting at - /// index index. If index is not supplied, then it will start at the beginning - /// of str. It recognizes a base character plus one or more combining - /// characters or a properly formed surrogate pair as a text element. - /// See also the ParseCombiningCharacters() and the ParseSurrogates() methods. - /// </summary> - public static string GetNextTextElement(string str, int index) - { - if (str == null) - { - throw new ArgumentNullException(nameof(str)); - } - - int len = str.Length; - if (index < 0 || index >= len) - { - if (index == len) - { - return string.Empty; - } - - throw new ArgumentOutOfRangeException(nameof(index), index, SR.ArgumentOutOfRange_Index); - } - - int charLen; - UnicodeCategory uc = CharUnicodeInfo.InternalGetUnicodeCategory(str, index, out charLen); - return str.Substring(index, GetCurrentTextElementLen(str, index, len, ref uc, ref charLen)); - } - - public static TextElementEnumerator GetTextElementEnumerator(string str) - { - return GetTextElementEnumerator(str, 0); - } - - public static TextElementEnumerator GetTextElementEnumerator(string str, int index) - { - if (str == null) - { - throw new ArgumentNullException(nameof(str)); - } - - int len = str.Length; - if (index < 0 || index > len) - { - throw new ArgumentOutOfRangeException(nameof(index), index, SR.ArgumentOutOfRange_Index); - } - - return new TextElementEnumerator(str, index, len); - } - - /// <summary> - /// Returns the indices of each base character or properly formed surrogate - /// pair within the str. It recognizes a base character plus one or more - /// combining characters or a properly formed surrogate pair as a text - /// element and returns the index of the base character or high surrogate. - /// Each index is the beginning of a text element within a str. The length - /// of each element is easily computed as the difference between successive - /// indices. The length of the array will always be less than or equal to - /// the length of the str. For example, given the str - /// \u4f00\u302a\ud800\udc00\u4f01, this method would return the indices: - /// 0, 2, 4. - /// </summary> - public static int[] ParseCombiningCharacters(string str) - { - if (str == null) - { - throw new ArgumentNullException(nameof(str)); - } - - int len = str.Length; - int[] result = new int[len]; - if (len == 0) - { - return result; - } - - int resultCount = 0; - - int i = 0; - int currentCharLen; - UnicodeCategory currentCategory = CharUnicodeInfo.InternalGetUnicodeCategory(str, 0, out currentCharLen); - - while (i < len) - { - result[resultCount++] = i; - i += GetCurrentTextElementLen(str, i, len, ref currentCategory, ref currentCharLen); - } - - if (resultCount < len) - { - int[] returnArray = new int[resultCount]; - Array.Copy(result, returnArray, resultCount); - return returnArray; - } - return result; - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/TaiwanCalendar.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/TaiwanCalendar.cs deleted file mode 100644 index 03003826dfa..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/TaiwanCalendar.cs +++ /dev/null @@ -1,198 +0,0 @@ -// 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 -{ - /// <summary> - /// Taiwan calendar is based on the Gregorian calendar. And the year is an offset to Gregorian calendar. - /// That is, - /// Taiwan year = Gregorian year - 1911. So 1912/01/01 A.D. is Taiwan 1/01/01 - /// </summary> - /// <remarks> - /// Calendar support range: - /// Calendar Minimum Maximum - /// ========== ========== ========== - /// Gregorian 1912/01/01 9999/12/31 - /// Taiwan 01/01/01 8088/12/31 - /// </remarks> - public class TaiwanCalendar : Calendar - { - // Since - // Gregorian Year = Era Year + yearOffset - // When Gregorian Year 1912 is year 1, so that - // 1912 = 1 + yearOffset - // So yearOffset = 1911 - private static readonly EraInfo[] s_taiwanEraInfo = new EraInfo[] - { - new EraInfo(1, 1912, 1, 1, 1911, 1, GregorianCalendar.MaxYear - 1911) // era #, start year/month/day, yearOffset, minEraYear - }; - - private static volatile Calendar? s_defaultInstance; - - private readonly GregorianCalendarHelper _helper; - - internal static Calendar GetDefaultInstance() => s_defaultInstance ??= new TaiwanCalendar(); - - private static readonly DateTime s_calendarMinValue = new DateTime(1912, 1, 1); - - public override DateTime MinSupportedDateTime => s_calendarMinValue; - - public override DateTime MaxSupportedDateTime => DateTime.MaxValue; - - public override CalendarAlgorithmType AlgorithmType => CalendarAlgorithmType.SolarCalendar; - - public TaiwanCalendar() - { - try - { - new CultureInfo("zh-TW"); - } - catch (ArgumentException e) - { - throw new TypeInitializationException(GetType().ToString(), e); - } - - _helper = new GregorianCalendarHelper(this, s_taiwanEraInfo); - } - - internal override CalendarId ID => CalendarId.TAIWAN; - - public override DateTime AddMonths(DateTime time, int months) - { - return _helper.AddMonths(time, months); - } - - public override DateTime AddYears(DateTime time, int years) - { - return _helper.AddYears(time, years); - } - - public override int GetDaysInMonth(int year, int month, int era) - { - return _helper.GetDaysInMonth(year, month, era); - } - - public override int GetDaysInYear(int year, int era) - { - return _helper.GetDaysInYear(year, era); - } - - public override int GetDayOfMonth(DateTime time) - { - return _helper.GetDayOfMonth(time); - } - - public override DayOfWeek GetDayOfWeek(DateTime time) - { - return _helper.GetDayOfWeek(time); - } - - public override int GetDayOfYear(DateTime time) - { - return _helper.GetDayOfYear(time); - } - - public override int GetMonthsInYear(int year, int era) - { - return _helper.GetMonthsInYear(year, era); - } - - public override int GetWeekOfYear(DateTime time, CalendarWeekRule rule, DayOfWeek firstDayOfWeek) - { - return _helper.GetWeekOfYear(time, rule, firstDayOfWeek); - } - - public override int GetEra(DateTime time) - { - return _helper.GetEra(time); - } - - public override int GetMonth(DateTime time) - { - return _helper.GetMonth(time); - } - - public override int GetYear(DateTime time) - { - return _helper.GetYear(time); - } - - public override bool IsLeapDay(int year, int month, int day, int era) - { - return _helper.IsLeapDay(year, month, day, era); - } - - public override bool IsLeapYear(int year, int era) - { - return _helper.IsLeapYear(year, era); - } - - public override int GetLeapMonth(int year, int era) - { - return _helper.GetLeapMonth(year, era); - } - - public override bool IsLeapMonth(int year, int month, int era) - { - return _helper.IsLeapMonth(year, month, era); - } - - public override DateTime ToDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int era) - { - return _helper.ToDateTime(year, month, day, hour, minute, second, millisecond, era); - } - - public override int[] Eras => _helper.Eras; - - private const int DefaultTwoDigitYearMax = 99; - - public override int TwoDigitYearMax - { - get - { - if (_twoDigitYearMax == -1) - { - _twoDigitYearMax = GetSystemTwoDigitYearSetting(ID, DefaultTwoDigitYearMax); - } - - return _twoDigitYearMax; - } - set - { - VerifyWritable(); - if (value < 99 || value > _helper.MaxYear) - { - throw new ArgumentOutOfRangeException( - nameof(value), - value, - SR.Format(SR.ArgumentOutOfRange_Range, 99, _helper.MaxYear)); - } - - _twoDigitYearMax = value; - } - } - - /// <summary> - /// For Taiwan calendar, four digit year is not used. - /// Therefore, for any two digit number, we just return the original number. - /// </summary> - - public override int ToFourDigitYear(int year) - { - if (year <= 0) - { - throw new ArgumentOutOfRangeException(nameof(year), year, SR.ArgumentOutOfRange_NeedPosNum); - } - if (year > _helper.MaxYear) - { - throw new ArgumentOutOfRangeException( - nameof(year), - year, - SR.Format(SR.ArgumentOutOfRange_Range, 1, _helper.MaxYear)); - } - - return year; - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/TaiwanLunisolarCalendar.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/TaiwanLunisolarCalendar.cs deleted file mode 100644 index cecbf6a7ed4..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/TaiwanLunisolarCalendar.cs +++ /dev/null @@ -1,234 +0,0 @@ -// 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 -{ - /// <remarks> - /// Calendar support range: - /// Calendar Minimum Maximum - /// ========== ========== ========== - /// Gregorian 1912/02/18 2051/02/10 - /// TaiwanLunisolar 1912/01/01 2050/13/29 - /// </remarks> - public class TaiwanLunisolarCalendar : EastAsianLunisolarCalendar - { - // Since - // Gregorian Year = Era Year + yearOffset - // When Gregorian Year 1912 is year 1, so that - // 1912 = 1 + yearOffset - // So yearOffset = 1911 - private static readonly EraInfo[] s_taiwanLunisolarEraInfo = new EraInfo[] - { - new EraInfo(1, 1912, 1, 1, 1911, 1, GregorianCalendar.MaxYear - 1911) // era #, start year/month/day, yearOffset, minEraYear - }; - - private readonly GregorianCalendarHelper _helper; - - private const int MinLunisolarYear = 1912; - private const int MaxLunisolarYear = 2050; - - private static readonly DateTime s_minDate = new DateTime(1912, 2, 18); - private static readonly DateTime s_maxDate = new DateTime((new DateTime(2051, 2, 10, 23, 59, 59, 999)).Ticks + 9999); - - public override DateTime MinSupportedDateTime => s_minDate; - - public override DateTime MaxSupportedDateTime => s_maxDate; - - protected override int DaysInYearBeforeMinSupportedYear => - // 1911 from ChineseLunisolarCalendar - 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 - 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 - */ }; - - - internal override int MinCalendarYear => MinLunisolarYear; - - internal override int MaxCalendarYear => MaxLunisolarYear; - - internal override DateTime MinDate => s_minDate; - - internal override DateTime MaxDate => s_maxDate; - - internal override EraInfo[]? CalEraInfo => s_taiwanLunisolarEraInfo; - - internal override int GetYearInfo(int lunarYear, int index) - { - if ((lunarYear < MinLunisolarYear) || (lunarYear > MaxLunisolarYear)) - { - throw new ArgumentOutOfRangeException( - "year", - lunarYear, - SR.Format(SR.ArgumentOutOfRange_Range, MinLunisolarYear, MaxLunisolarYear)); - } - - return s_yinfo[lunarYear - MinLunisolarYear, index]; - } - - internal override int GetYear(int year, DateTime time) - { - return _helper.GetYear(year, time); - } - - internal override int GetGregorianYear(int year, int era) - { - return _helper.GetGregorianYear(year, era); - } - - public TaiwanLunisolarCalendar() - { - _helper = new GregorianCalendarHelper(this, s_taiwanLunisolarEraInfo); - } - - public override int GetEra(DateTime time) => _helper.GetEra(time); - - internal override CalendarId BaseCalendarID => CalendarId.TAIWAN; - - internal override CalendarId ID => CalendarId.TAIWANLUNISOLAR; - - public override int[] Eras => _helper.Eras; - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/TextElementEnumerator.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/TextElementEnumerator.cs deleted file mode 100644 index 7ee564a9347..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/TextElementEnumerator.cs +++ /dev/null @@ -1,92 +0,0 @@ -// 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; -using System.Diagnostics; - -namespace System.Globalization -{ - public class TextElementEnumerator : IEnumerator - { - private readonly string _str; - private int _index; - private readonly int _startIndex; - - // This is the length of the total string, counting from the beginning of string. - private readonly int _strLen; - - // The current text element lenght after MoveNext() is called. - private int _currTextElementLen; - - private UnicodeCategory _uc; - - // The next abstract char to look at after MoveNext() is called. - // It could be 1 or 2, depending on if it is a surrogate or not. - private int _charLen; - - internal TextElementEnumerator(string str, int startIndex, int strLen) - { - Debug.Assert(str != null, "TextElementEnumerator(): str != null"); - Debug.Assert(startIndex >= 0 && strLen >= 0, "TextElementEnumerator(): startIndex >= 0 && strLen >= 0"); - Debug.Assert(strLen >= startIndex, "TextElementEnumerator(): strLen >= startIndex"); - _str = str; - _startIndex = startIndex; - _strLen = strLen; - Reset(); - } - - public bool MoveNext() - { - if (_index >= _strLen) - { - // Make the _index to be greater than _strLen so that we can throw exception if GetTextElement() is called. - _index = _strLen + 1; - return false; - } - - _currTextElementLen = StringInfo.GetCurrentTextElementLen(_str, _index, _strLen, ref _uc, ref _charLen); - _index += _currTextElementLen; - return true; - } - - public object Current => GetTextElement(); - - public string GetTextElement() - { - if (_index == _startIndex) - { - throw new InvalidOperationException(SR.InvalidOperation_EnumNotStarted); - } - if (_index > _strLen) - { - throw new InvalidOperationException(SR.InvalidOperation_EnumEnded); - } - - return _str.Substring(_index - _currTextElementLen, _currTextElementLen); - } - - public int ElementIndex - { - get - { - if (_index == _startIndex) - { - throw new InvalidOperationException(SR.InvalidOperation_EnumNotStarted); - } - - return _index - _currTextElementLen; - } - } - - public void Reset() - { - _index = _startIndex; - if (_index < _strLen) - { - // If we have more than 1 character, get the category of the current char. - _uc = CharUnicodeInfo.InternalGetUnicodeCategory(_str, _index, out _charLen); - } - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/TextInfo.Unix.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/TextInfo.Unix.cs deleted file mode 100644 index 02e7c5f50b9..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/TextInfo.Unix.cs +++ /dev/null @@ -1,57 +0,0 @@ -// 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; -using System.Runtime.InteropServices; -using System.Security; -using System.Text; - -namespace System.Globalization -{ - public partial class TextInfo - { - private Tristate _needsTurkishCasing = Tristate.NotInitialized; - - private void FinishInitialization() { } - - // ----------------------------- - // ---- PAL layer ends here ---- - // ----------------------------- - - private static bool NeedsTurkishCasing(string localeName) - { - Debug.Assert(localeName != null); - - return CultureInfo.GetCultureInfo(localeName).CompareInfo.Compare("\u0131", "I", CompareOptions.IgnoreCase) == 0; - } - - private bool IsInvariant { get { return _cultureName.Length == 0; } } - - internal unsafe void ChangeCase(char* src, int srcLen, char* dstBuffer, int dstBufferCapacity, bool bToUpper) - { - Debug.Assert(!GlobalizationMode.Invariant); - - if (IsInvariant) - { - Interop.Globalization.ChangeCaseInvariant(src, srcLen, dstBuffer, dstBufferCapacity, bToUpper); - } - else - { - if (_needsTurkishCasing == Tristate.NotInitialized) - { - _needsTurkishCasing = NeedsTurkishCasing(_textInfoName) ? Tristate.True : Tristate.False; - } - if (_needsTurkishCasing == Tristate.True) - { - Interop.Globalization.ChangeCaseTurkish(src, srcLen, dstBuffer, dstBufferCapacity, bToUpper); - } - else - { - Interop.Globalization.ChangeCase(src, srcLen, dstBuffer, dstBufferCapacity, bToUpper); - } - } - } - - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/TextInfo.Windows.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/TextInfo.Windows.cs deleted file mode 100644 index 948644769da..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/TextInfo.Windows.cs +++ /dev/null @@ -1,55 +0,0 @@ -// 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; - -namespace System.Globalization -{ - public partial class TextInfo - { - private unsafe void FinishInitialization() - { - _sortHandle = CompareInfo.GetSortHandle(_textInfoName); - } - - private unsafe void ChangeCase(char* pSource, int pSourceLen, char* pResult, int pResultLen, bool toUpper) - { - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert(pSource != null); - Debug.Assert(pResult != null); - Debug.Assert(pSourceLen >= 0); - Debug.Assert(pResultLen >= 0); - Debug.Assert(pSourceLen <= pResultLen); - - // Check for Invariant to avoid A/V in LCMapStringEx - uint linguisticCasing = IsInvariantLocale(_textInfoName) ? 0 : LCMAP_LINGUISTIC_CASING; - - int ret = Interop.Kernel32.LCMapStringEx(_sortHandle != IntPtr.Zero ? null : _textInfoName, - linguisticCasing | (toUpper ? LCMAP_UPPERCASE : LCMAP_LOWERCASE), - pSource, - pSourceLen, - pResult, - pSourceLen, - null, - null, - _sortHandle); - if (ret == 0) - { - throw new InvalidOperationException(SR.InvalidOperation_ReadOnly); - } - - Debug.Assert(ret == pSourceLen, "Expected getting the same length of the original string"); - } - - // PAL Ends here - - private IntPtr _sortHandle; - - private const uint LCMAP_LINGUISTIC_CASING = 0x01000000; - private const uint LCMAP_LOWERCASE = 0x00000100; - private const uint LCMAP_UPPERCASE = 0x00000200; - - private static bool IsInvariantLocale(string localeName) => localeName == ""; - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/TextInfo.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/TextInfo.cs deleted file mode 100644 index d1f6b8d343b..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/TextInfo.cs +++ /dev/null @@ -1,870 +0,0 @@ -// 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; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Runtime.Serialization; -using System.Text; -using System.Text.Unicode; -using Internal.Runtime.CompilerServices; - -#pragma warning disable SA1121 // explicitly using type aliases instead of built-in types -#if BIT64 -using nuint = System.UInt64; -#else // BIT64 -using nuint = System.UInt32; -#endif // BIT64 - -namespace System.Globalization -{ - /// <summary> - /// This Class defines behaviors specific to a writing system. - /// A writing system is the collection of scripts and orthographic rules - /// required to represent a language as text. - /// </summary> - public partial class TextInfo : ICloneable, IDeserializationCallback - { - private enum Tristate : byte - { - NotInitialized = 0, - False = 1, - True = 2 - } - - private string? _listSeparator; - private bool _isReadOnly = false; - - private readonly string _cultureName; - private readonly CultureData _cultureData; - - // // Name of the text info we're using (ie: _cultureData.TextInfoName) - private readonly string _textInfoName; - - private Tristate _isAsciiCasingSameAsInvariant = Tristate.NotInitialized; - - // Invariant text info - internal static TextInfo Invariant => s_invariant ??= new TextInfo(CultureData.Invariant); - - private static volatile TextInfo? s_invariant; - - internal TextInfo(CultureData cultureData) - { - // This is our primary data source, we don't need most of the rest of this - _cultureData = cultureData; - _cultureName = _cultureData.CultureName; - _textInfoName = _cultureData.TextInfoName; - - FinishInitialization(); - } - - void IDeserializationCallback.OnDeserialization(object? sender) - { - throw new PlatformNotSupportedException(); - } - - public virtual int ANSICodePage => _cultureData.ANSICodePage; - - public virtual int OEMCodePage => _cultureData.OEMCodePage; - - public virtual int MacCodePage => _cultureData.MacCodePage; - - public virtual int EBCDICCodePage => _cultureData.EBCDICCodePage; - - // Just use the LCID from our text info name - public int LCID => CultureInfo.GetCultureInfo(_textInfoName).LCID; - - public string CultureName => _textInfoName; - - public bool IsReadOnly => _isReadOnly; - - public virtual object Clone() - { - object o = MemberwiseClone(); - ((TextInfo)o).SetReadOnlyState(false); - return o; - } - - /// <summary> - /// Create a cloned readonly instance or return the input one if it is - /// readonly. - /// </summary> - public static TextInfo ReadOnly(TextInfo textInfo) - { - if (textInfo == null) - { - throw new ArgumentNullException(nameof(textInfo)); - } - - if (textInfo.IsReadOnly) - { - return textInfo; - } - - TextInfo clonedTextInfo = (TextInfo)(textInfo.MemberwiseClone()); - clonedTextInfo.SetReadOnlyState(true); - return clonedTextInfo; - } - - private void VerifyWritable() - { - if (_isReadOnly) - { - throw new InvalidOperationException(SR.InvalidOperation_ReadOnly); - } - } - - internal void SetReadOnlyState(bool readOnly) - { - _isReadOnly = readOnly; - } - - /// <summary> - /// Returns the string used to separate items in a list. - /// </summary> - public virtual string ListSeparator - { - get => _listSeparator ??= _cultureData.ListSeparator; - set - { - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - - VerifyWritable(); - _listSeparator = value; - } - } - - /// <summary> - /// Converts the character or string to lower case. Certain locales - /// have different casing semantics from the file systems in Win32. - /// </summary> - public virtual char ToLower(char c) - { - if (GlobalizationMode.Invariant || (IsAscii(c) && IsAsciiCasingSameAsInvariant)) - { - return ToLowerAsciiInvariant(c); - } - - return ChangeCase(c, toUpper: false); - } - - public virtual string ToLower(string str) - { - if (str == null) - { - throw new ArgumentNullException(nameof(str)); - } - - if (GlobalizationMode.Invariant) - { - return ToLowerAsciiInvariant(str); - } - - return ChangeCaseCommon<ToLowerConversion>(str); - } - - private unsafe char ChangeCase(char c, bool toUpper) - { - Debug.Assert(!GlobalizationMode.Invariant); - - char dst = default; - ChangeCase(&c, 1, &dst, 1, toUpper); - return dst; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void ChangeCaseToLower(ReadOnlySpan<char> source, Span<char> destination) - { - Debug.Assert(destination.Length >= source.Length); - ChangeCaseCommon<ToLowerConversion>(ref MemoryMarshal.GetReference(source), ref MemoryMarshal.GetReference(destination), source.Length); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void ChangeCaseToUpper(ReadOnlySpan<char> source, Span<char> destination) - { - Debug.Assert(destination.Length >= source.Length); - ChangeCaseCommon<ToUpperConversion>(ref MemoryMarshal.GetReference(source), ref MemoryMarshal.GetReference(destination), source.Length); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void ChangeCaseCommon<TConversion>(ReadOnlySpan<char> source, Span<char> destination) where TConversion : struct - { - Debug.Assert(destination.Length >= source.Length); - ChangeCaseCommon<TConversion>(ref MemoryMarshal.GetReference(source), ref MemoryMarshal.GetReference(destination), source.Length); - } - - private unsafe void ChangeCaseCommon<TConversion>(ref char source, ref char destination, int charCount) where TConversion : struct - { - Debug.Assert(typeof(TConversion) == typeof(ToUpperConversion) || typeof(TConversion) == typeof(ToLowerConversion)); - bool toUpper = typeof(TConversion) == typeof(ToUpperConversion); // JIT will treat this as a constant in release builds - - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert(charCount >= 0); - - if (charCount == 0) - { - goto Return; - } - - fixed (char* pSource = &source) - fixed (char* pDestination = &destination) - { - nuint currIdx = 0; // in chars - - if (IsAsciiCasingSameAsInvariant) - { - // Read 4 chars (two 32-bit integers) at a time - - if (charCount >= 4) - { - nuint lastIndexWhereCanReadFourChars = (uint)charCount - 4; - do - { - // This is a mostly branchless case change routine. Generally speaking, we assume that the majority - // of input is ASCII, so the 'if' checks below should normally evaluate to false. However, within - // the ASCII data, we expect that characters of either case might be about equally distributed, so - // we want the case change operation itself to be branchless. This gives optimal performance in the - // common case. We also expect that developers aren't passing very long (16+ character) strings into - // this method, so we won't bother vectorizing until data shows us that it's worthwhile to do so. - - uint tempValue = Unsafe.ReadUnaligned<uint>(pSource + currIdx); - if (!Utf16Utility.AllCharsInUInt32AreAscii(tempValue)) - { - goto NonAscii; - } - tempValue = (toUpper) ? Utf16Utility.ConvertAllAsciiCharsInUInt32ToUppercase(tempValue) : Utf16Utility.ConvertAllAsciiCharsInUInt32ToLowercase(tempValue); - Unsafe.WriteUnaligned<uint>(pDestination + currIdx, tempValue); - - tempValue = Unsafe.ReadUnaligned<uint>(pSource + currIdx + 2); - if (!Utf16Utility.AllCharsInUInt32AreAscii(tempValue)) - { - goto NonAsciiSkipTwoChars; - } - tempValue = (toUpper) ? Utf16Utility.ConvertAllAsciiCharsInUInt32ToUppercase(tempValue) : Utf16Utility.ConvertAllAsciiCharsInUInt32ToLowercase(tempValue); - Unsafe.WriteUnaligned<uint>(pDestination + currIdx + 2, tempValue); - currIdx += 4; - } while (currIdx <= lastIndexWhereCanReadFourChars); - - // At this point, there are fewer than 4 characters remaining to convert. - Debug.Assert((uint)charCount - currIdx < 4); - } - - // If there are 2 or 3 characters left to convert, we'll convert 2 of them now. - if ((charCount & 2) != 0) - { - uint tempValue = Unsafe.ReadUnaligned<uint>(pSource + currIdx); - if (!Utf16Utility.AllCharsInUInt32AreAscii(tempValue)) - { - goto NonAscii; - } - tempValue = (toUpper) ? Utf16Utility.ConvertAllAsciiCharsInUInt32ToUppercase(tempValue) : Utf16Utility.ConvertAllAsciiCharsInUInt32ToLowercase(tempValue); - Unsafe.WriteUnaligned<uint>(pDestination + currIdx, tempValue); - currIdx += 2; - } - - // If there's a single character left to convert, do it now. - if ((charCount & 1) != 0) - { - uint tempValue = pSource[currIdx]; - if (tempValue > 0x7Fu) - { - goto NonAscii; - } - tempValue = (toUpper) ? Utf16Utility.ConvertAllAsciiCharsInUInt32ToUppercase(tempValue) : Utf16Utility.ConvertAllAsciiCharsInUInt32ToLowercase(tempValue); - pDestination[currIdx] = (char)tempValue; - } - - // And we're finished! - - goto Return; - - // If we reached this point, we found non-ASCII data. - // Fall back down the p/invoke code path. - - NonAsciiSkipTwoChars: - currIdx += 2; - - NonAscii: - Debug.Assert(currIdx < (uint)charCount, "We somehow read past the end of the buffer."); - charCount -= (int)currIdx; - } - - // We encountered non-ASCII data and therefore can't perform invariant case conversion; or the requested culture - // has a case conversion that's different from the invariant culture, even for ASCII data (e.g., tr-TR converts - // 'i' (U+0069) to Latin Capital Letter I With Dot Above (U+0130)). - - ChangeCase(pSource + currIdx, charCount, pDestination + currIdx, charCount, toUpper); - } - - Return: - return; - } - - private unsafe string ChangeCaseCommon<TConversion>(string source) where TConversion : struct - { - Debug.Assert(typeof(TConversion) == typeof(ToUpperConversion) || typeof(TConversion) == typeof(ToLowerConversion)); - bool toUpper = typeof(TConversion) == typeof(ToUpperConversion); // JIT will treat this as a constant in release builds - - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert(source != null); - - // If the string is empty, we're done. - if (source.Length == 0) - { - return string.Empty; - } - - fixed (char* pSource = source) - { - nuint currIdx = 0; // in chars - - // If this culture's casing for ASCII is the same as invariant, try to take - // a fast path that'll work in managed code and ASCII rather than calling out - // to the OS for culture-aware casing. - if (IsAsciiCasingSameAsInvariant) - { - // Read 2 chars (one 32-bit integer) at a time - - if (source.Length >= 2) - { - nuint lastIndexWhereCanReadTwoChars = (uint)source.Length - 2; - do - { - // See the comments in ChangeCaseCommon<TConversion>(ROS<char>, Span<char>) for a full explanation of the below code. - - uint tempValue = Unsafe.ReadUnaligned<uint>(pSource + currIdx); - if (!Utf16Utility.AllCharsInUInt32AreAscii(tempValue)) - { - goto NotAscii; - } - if ((toUpper) ? Utf16Utility.UInt32ContainsAnyLowercaseAsciiChar(tempValue) : Utf16Utility.UInt32ContainsAnyUppercaseAsciiChar(tempValue)) - { - goto AsciiMustChangeCase; - } - - currIdx += 2; - } while (currIdx <= lastIndexWhereCanReadTwoChars); - } - - // If there's a single character left to convert, do it now. - if ((source.Length & 1) != 0) - { - uint tempValue = pSource[currIdx]; - if (tempValue > 0x7Fu) - { - goto NotAscii; - } - if ((toUpper) ? ((tempValue - 'a') <= (uint)('z' - 'a')) : ((tempValue - 'A') <= (uint)('Z' - 'A'))) - { - goto AsciiMustChangeCase; - } - } - - // We got through all characters without finding anything that needed to change - done! - return source; - - AsciiMustChangeCase: - { - // We reached ASCII data that requires a case change. - // This will necessarily allocate a new string, but let's try to stay within the managed (non-localization tables) - // conversion code path if we can. - - string result = string.FastAllocateString(source.Length); // changing case uses simple folding: doesn't change UTF-16 code unit count - - // copy existing known-good data into the result - Span<char> resultSpan = new Span<char>(ref result.GetRawStringData(), result.Length); - source.AsSpan(0, (int)currIdx).CopyTo(resultSpan); - - // and re-run the fast span-based logic over the remainder of the data - ChangeCaseCommon<TConversion>(source.AsSpan((int)currIdx), resultSpan.Slice((int)currIdx)); - return result; - } - } - - NotAscii: - { - // We reached non-ASCII data *or* the requested culture doesn't map ASCII data the same way as the invariant culture. - // In either case we need to fall back to the localization tables. - - string result = string.FastAllocateString(source.Length); // changing case uses simple folding: doesn't change UTF-16 code unit count - - if (currIdx > 0) - { - // copy existing known-good data into the result - Span<char> resultSpan = new Span<char>(ref result.GetRawStringData(), result.Length); - source.AsSpan(0, (int)currIdx).CopyTo(resultSpan); - } - - // and run the culture-aware logic over the remainder of the data - fixed (char* pResult = result) - { - ChangeCase(pSource + currIdx, source.Length - (int)currIdx, pResult + currIdx, result.Length - (int)currIdx, toUpper); - } - return result; - } - } - } - - internal static unsafe string ToLowerAsciiInvariant(string s) - { - if (s.Length == 0) - { - return string.Empty; - } - - fixed (char* pSource = s) - { - int i = 0; - while (i < s.Length) - { - if ((uint)(pSource[i] - 'A') <= (uint)('Z' - 'A')) - { - break; - } - i++; - } - - if (i >= s.Length) - { - return s; - } - - string result = string.FastAllocateString(s.Length); - fixed (char* pResult = result) - { - for (int j = 0; j < i; j++) - { - pResult[j] = pSource[j]; - } - - pResult[i] = (char)(pSource[i] | 0x20); - i++; - - while (i < s.Length) - { - pResult[i] = ToLowerAsciiInvariant(pSource[i]); - i++; - } - } - - return result; - } - } - - internal static void ToLowerAsciiInvariant(ReadOnlySpan<char> source, Span<char> destination) - { - Debug.Assert(destination.Length >= source.Length); - - for (int i = 0; i < source.Length; i++) - { - destination[i] = ToLowerAsciiInvariant(source[i]); - } - } - - private static unsafe string ToUpperAsciiInvariant(string s) - { - if (s.Length == 0) - { - return string.Empty; - } - - fixed (char* pSource = s) - { - int i = 0; - while (i < s.Length) - { - if ((uint)(pSource[i] - 'a') <= (uint)('z' - 'a')) - { - break; - } - i++; - } - - if (i >= s.Length) - { - return s; - } - - string result = string.FastAllocateString(s.Length); - fixed (char* pResult = result) - { - for (int j = 0; j < i; j++) - { - pResult[j] = pSource[j]; - } - - pResult[i] = (char)(pSource[i] & ~0x20); - i++; - - while (i < s.Length) - { - pResult[i] = ToUpperAsciiInvariant(pSource[i]); - i++; - } - } - - return result; - } - } - - internal static void ToUpperAsciiInvariant(ReadOnlySpan<char> source, Span<char> destination) - { - Debug.Assert(destination.Length >= source.Length); - - for (int i = 0; i < source.Length; i++) - { - destination[i] = ToUpperAsciiInvariant(source[i]); - } - } - - private static char ToLowerAsciiInvariant(char c) - { - if ((uint)(c - 'A') <= (uint)('Z' - 'A')) - { - c = (char)(c | 0x20); - } - return c; - } - - /// <summary> - /// Converts the character or string to upper case. Certain locales - /// have different casing semantics from the file systems in Win32. - /// </summary> - public virtual char ToUpper(char c) - { - if (GlobalizationMode.Invariant || (IsAscii(c) && IsAsciiCasingSameAsInvariant)) - { - return ToUpperAsciiInvariant(c); - } - - return ChangeCase(c, toUpper: true); - } - - public virtual string ToUpper(string str) - { - if (str == null) - { - throw new ArgumentNullException(nameof(str)); - } - - if (GlobalizationMode.Invariant) - { - return ToUpperAsciiInvariant(str); - } - - return ChangeCaseCommon<ToUpperConversion>(str); - } - - internal static char ToUpperAsciiInvariant(char c) - { - if ((uint)(c - 'a') <= (uint)('z' - 'a')) - { - c = (char)(c & ~0x20); - } - return c; - } - - private static bool IsAscii(char c) => c < 0x80; - - private bool IsAsciiCasingSameAsInvariant - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - if (_isAsciiCasingSameAsInvariant == Tristate.NotInitialized) - { - PopulateIsAsciiCasingSameAsInvariant(); - } - - Debug.Assert(_isAsciiCasingSameAsInvariant == Tristate.True || _isAsciiCasingSameAsInvariant == Tristate.False); - return _isAsciiCasingSameAsInvariant == Tristate.True; - } - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private void PopulateIsAsciiCasingSameAsInvariant() - { - bool compareResult = CultureInfo.GetCultureInfo(_textInfoName).CompareInfo.Compare("abcdefghijklmnopqrstuvwxyz", "ABCDEFGHIJKLMNOPQRSTUVWXYZ", CompareOptions.IgnoreCase) == 0; - _isAsciiCasingSameAsInvariant = (compareResult) ? Tristate.True : Tristate.False; - } - - /// <summary> - /// Returns true if the dominant direction of text and UI such as the - /// relative position of buttons and scroll bars - /// </summary> - public bool IsRightToLeft => _cultureData.IsRightToLeft; - - public override bool Equals(object? obj) - { - return obj is TextInfo otherTextInfo - && CultureName.Equals(otherTextInfo.CultureName); - } - - public override int GetHashCode() => CultureName.GetHashCode(); - - public override string ToString() - { - return "TextInfo - " + _cultureData.CultureName; - } - - /// <summary> - /// Titlecasing refers to a casing practice wherein the first letter of a word is an uppercase letter - /// and the rest of the letters are lowercase. The choice of which words to titlecase in headings - /// and titles is dependent on language and local conventions. For example, "The Merry Wives of Windor" - /// is the appropriate titlecasing of that play's name in English, with the word "of" not titlecased. - /// In German, however, the title is "Die lustigen Weiber von Windsor," and both "lustigen" and "von" - /// are not titlecased. In French even fewer words are titlecased: "Les joyeuses commeres de Windsor." - /// - /// Moreover, the determination of what actually constitutes a word is language dependent, and this can - /// influence which letter or letters of a "word" are uppercased when titlecasing strings. For example - /// "l'arbre" is considered two words in French, whereas "can't" is considered one word in English. - /// </summary> - public unsafe string ToTitleCase(string str) - { - if (str == null) - { - throw new ArgumentNullException(nameof(str)); - } - - if (str.Length == 0) - { - return str; - } - - StringBuilder result = new StringBuilder(); - string? lowercaseData = null; - // Store if the current culture is Dutch (special case) - bool isDutchCulture = CultureName.StartsWith("nl-", StringComparison.OrdinalIgnoreCase); - - for (int i = 0; i < str.Length; i++) - { - int charLen; - UnicodeCategory charType = CharUnicodeInfo.InternalGetUnicodeCategory(str, i, out charLen); - if (char.CheckLetter(charType)) - { - // Special case to check for Dutch specific titlecasing with "IJ" characters - // at the beginning of a word - if (isDutchCulture && i < str.Length - 1 && (str[i] == 'i' || str[i] == 'I') && (str[i + 1] == 'j' || str[i + 1] == 'J')) - { - result.Append("IJ"); - i += 2; - } - else - { - // Do the titlecasing for the first character of the word. - i = AddTitlecaseLetter(ref result, ref str, i, charLen) + 1; - } - - // Convert the characters until the end of the this word - // to lowercase. - int lowercaseStart = i; - - // Use hasLowerCase flag to prevent from lowercasing acronyms (like "URT", "USA", etc) - // This is in line with Word 2000 behavior of titlecasing. - bool hasLowerCase = (charType == UnicodeCategory.LowercaseLetter); - - // Use a loop to find all of the other letters following this letter. - while (i < str.Length) - { - charType = CharUnicodeInfo.InternalGetUnicodeCategory(str, i, out charLen); - if (IsLetterCategory(charType)) - { - if (charType == UnicodeCategory.LowercaseLetter) - { - hasLowerCase = true; - } - i += charLen; - } - else if (str[i] == '\'') - { - i++; - if (hasLowerCase) - { - if (lowercaseData == null) - { - lowercaseData = ToLower(str); - } - result.Append(lowercaseData, lowercaseStart, i - lowercaseStart); - } - else - { - result.Append(str, lowercaseStart, i - lowercaseStart); - } - lowercaseStart = i; - hasLowerCase = true; - } - else if (!IsWordSeparator(charType)) - { - // This category is considered to be part of the word. - // This is any category that is marked as false in wordSeprator array. - i += charLen; - } - else - { - // A word separator. Break out of the loop. - break; - } - } - - int count = i - lowercaseStart; - - if (count > 0) - { - if (hasLowerCase) - { - if (lowercaseData == null) - { - lowercaseData = ToLower(str); - } - result.Append(lowercaseData, lowercaseStart, count); - } - else - { - result.Append(str, lowercaseStart, count); - } - } - - if (i < str.Length) - { - // not a letter, just append it - i = AddNonLetter(ref result, ref str, i, charLen); - } - } - else - { - // not a letter, just append it - i = AddNonLetter(ref result, ref str, i, charLen); - } - } - return result.ToString(); - } - - private static int AddNonLetter(ref StringBuilder result, ref string input, int inputIndex, int charLen) - { - Debug.Assert(charLen == 1 || charLen == 2, "[TextInfo.AddNonLetter] CharUnicodeInfo.InternalGetUnicodeCategory returned an unexpected charLen!"); - if (charLen == 2) - { - // Surrogate pair - result.Append(input[inputIndex++]); - result.Append(input[inputIndex]); - } - else - { - result.Append(input[inputIndex]); - } - return inputIndex; - } - - private int AddTitlecaseLetter(ref StringBuilder result, ref string input, int inputIndex, int charLen) - { - Debug.Assert(charLen == 1 || charLen == 2, "[TextInfo.AddTitlecaseLetter] CharUnicodeInfo.InternalGetUnicodeCategory returned an unexpected charLen!"); - - if (charLen == 2) - { - // for surrogate pairs do a ToUpper operation on the substring - ReadOnlySpan<char> src = input.AsSpan(inputIndex, 2); - if (GlobalizationMode.Invariant) - { - result.Append(src); // surrogate pair in invariant mode, so changing case is a nop - } - else - { - Span<char> dst = stackalloc char[2]; - ChangeCaseToUpper(src, dst); - result.Append(dst); - } - inputIndex++; - } - else - { - switch (input[inputIndex]) - { - // For AppCompat, the Titlecase Case Mapping data from NDP 2.0 is used below. - case (char)0x01C4: // DZ with Caron -> Dz with Caron - case (char)0x01C5: // Dz with Caron -> Dz with Caron - case (char)0x01C6: // dz with Caron -> Dz with Caron - result.Append((char)0x01C5); - break; - case (char)0x01C7: // LJ -> Lj - case (char)0x01C8: // Lj -> Lj - case (char)0x01C9: // lj -> Lj - result.Append((char)0x01C8); - break; - case (char)0x01CA: // NJ -> Nj - case (char)0x01CB: // Nj -> Nj - case (char)0x01CC: // nj -> Nj - result.Append((char)0x01CB); - break; - case (char)0x01F1: // DZ -> Dz - case (char)0x01F2: // Dz -> Dz - case (char)0x01F3: // dz -> Dz - result.Append((char)0x01F2); - break; - default: - result.Append(ToUpper(input[inputIndex])); - break; - } - } - return inputIndex; - } - - // Used in ToTitleCase(): - // When we find a starting letter, the following array decides if a category should be - // considered as word seprator or not. - private const int c_wordSeparatorMask = - /* false */ (0 << 0) | // UppercaseLetter = 0, - /* false */ (0 << 1) | // LowercaseLetter = 1, - /* false */ (0 << 2) | // TitlecaseLetter = 2, - /* false */ (0 << 3) | // ModifierLetter = 3, - /* false */ (0 << 4) | // OtherLetter = 4, - /* false */ (0 << 5) | // NonSpacingMark = 5, - /* false */ (0 << 6) | // SpacingCombiningMark = 6, - /* false */ (0 << 7) | // EnclosingMark = 7, - /* false */ (0 << 8) | // DecimalDigitNumber = 8, - /* false */ (0 << 9) | // LetterNumber = 9, - /* false */ (0 << 10) | // OtherNumber = 10, - /* true */ (1 << 11) | // SpaceSeparator = 11, - /* true */ (1 << 12) | // LineSeparator = 12, - /* true */ (1 << 13) | // ParagraphSeparator = 13, - /* true */ (1 << 14) | // Control = 14, - /* true */ (1 << 15) | // Format = 15, - /* false */ (0 << 16) | // Surrogate = 16, - /* false */ (0 << 17) | // PrivateUse = 17, - /* true */ (1 << 18) | // ConnectorPunctuation = 18, - /* true */ (1 << 19) | // DashPunctuation = 19, - /* true */ (1 << 20) | // OpenPunctuation = 20, - /* true */ (1 << 21) | // ClosePunctuation = 21, - /* true */ (1 << 22) | // InitialQuotePunctuation = 22, - /* true */ (1 << 23) | // FinalQuotePunctuation = 23, - /* true */ (1 << 24) | // OtherPunctuation = 24, - /* true */ (1 << 25) | // MathSymbol = 25, - /* true */ (1 << 26) | // CurrencySymbol = 26, - /* true */ (1 << 27) | // ModifierSymbol = 27, - /* true */ (1 << 28) | // OtherSymbol = 28, - /* false */ (0 << 29); // OtherNotAssigned = 29; - - private static bool IsWordSeparator(UnicodeCategory category) - { - return (c_wordSeparatorMask & (1 << (int)category)) != 0; - } - - private static bool IsLetterCategory(UnicodeCategory uc) - { - return uc == UnicodeCategory.UppercaseLetter - || uc == UnicodeCategory.LowercaseLetter - || uc == UnicodeCategory.TitlecaseLetter - || uc == UnicodeCategory.ModifierLetter - || uc == UnicodeCategory.OtherLetter; - } - - // A dummy struct that is used for 'ToUpper' in generic parameters - private readonly struct ToUpperConversion { } - - // A dummy struct that is used for 'ToLower' in generic parameters - private readonly struct ToLowerConversion { } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/ThaiBuddhistCalendar.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/ThaiBuddhistCalendar.cs deleted file mode 100644 index 96ecea765de..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/ThaiBuddhistCalendar.cs +++ /dev/null @@ -1,168 +0,0 @@ -// 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 -{ - /// <summary> - /// ThaiBuddhistCalendar is based on Gregorian calendar. - /// Its year value has an offset to the Gregorain calendar. - /// </summary> - /// <remarks> - /// Calendar support range: - /// Calendar Minimum Maximum - /// ========== ========== ========== - /// Gregorian 0001/01/01 9999/12/31 - /// Thai 0544/01/01 10542/12/31 - /// </remarks> - public class ThaiBuddhistCalendar : Calendar - { - private static readonly EraInfo[] s_thaiBuddhistEraInfo = new EraInfo[] - { - new EraInfo(1, 1, 1, 1, -543, 544, GregorianCalendar.MaxYear + 543) // era #, start year/month/day, yearOffset, minEraYear - }; - - public const int ThaiBuddhistEra = 1; - - private readonly GregorianCalendarHelper _helper; - - public override DateTime MinSupportedDateTime => DateTime.MinValue; - - public override DateTime MaxSupportedDateTime => DateTime.MaxValue; - - public override CalendarAlgorithmType AlgorithmType => CalendarAlgorithmType.SolarCalendar; - - public ThaiBuddhistCalendar() - { - _helper = new GregorianCalendarHelper(this, s_thaiBuddhistEraInfo); - } - - internal override CalendarId ID => CalendarId.THAI; - - public override DateTime AddMonths(DateTime time, int months) - { - return _helper.AddMonths(time, months); - } - - public override DateTime AddYears(DateTime time, int years) - { - return _helper.AddYears(time, years); - } - - public override int GetDaysInMonth(int year, int month, int era) - { - return _helper.GetDaysInMonth(year, month, era); - } - - public override int GetDaysInYear(int year, int era) - { - return _helper.GetDaysInYear(year, era); - } - - public override int GetDayOfMonth(DateTime time) - { - return _helper.GetDayOfMonth(time); - } - - public override DayOfWeek GetDayOfWeek(DateTime time) - { - return _helper.GetDayOfWeek(time); - } - - public override int GetDayOfYear(DateTime time) - { - return _helper.GetDayOfYear(time); - } - - public override int GetMonthsInYear(int year, int era) - { - return _helper.GetMonthsInYear(year, era); - } - - public override int GetWeekOfYear(DateTime time, CalendarWeekRule rule, DayOfWeek firstDayOfWeek) - { - return _helper.GetWeekOfYear(time, rule, firstDayOfWeek); - } - - public override int GetEra(DateTime time) - { - return _helper.GetEra(time); - } - - public override int GetMonth(DateTime time) - { - return _helper.GetMonth(time); - } - - public override int GetYear(DateTime time) - { - return _helper.GetYear(time); - } - - public override bool IsLeapDay(int year, int month, int day, int era) - { - return _helper.IsLeapDay(year, month, day, era); - } - - public override bool IsLeapYear(int year, int era) - { - return _helper.IsLeapYear(year, era); - } - - public override int GetLeapMonth(int year, int era) - { - return _helper.GetLeapMonth(year, era); - } - - public override bool IsLeapMonth(int year, int month, int era) - { - return _helper.IsLeapMonth(year, month, era); - } - - public override DateTime ToDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int era) - { - return _helper.ToDateTime(year, month, day, hour, minute, second, millisecond, era); - } - - public override int[] Eras => _helper.Eras; - - private const int DefaultTwoDigitYearMax = 2572; - - - public override int TwoDigitYearMax - { - get - { - if (_twoDigitYearMax == -1) - { - _twoDigitYearMax = GetSystemTwoDigitYearSetting(ID, DefaultTwoDigitYearMax); - } - - return _twoDigitYearMax; - } - set - { - VerifyWritable(); - if (value < 99 || value > _helper.MaxYear) - { - throw new ArgumentOutOfRangeException( - nameof(value), - value, - SR.Format(SR.ArgumentOutOfRange_Range, 99, _helper.MaxYear)); - } - - _twoDigitYearMax = value; - } - } - - public override int ToFourDigitYear(int year) - { - if (year < 0) - { - throw new ArgumentOutOfRangeException(nameof(year), year, SR.ArgumentOutOfRange_NeedNonNegNum); - } - - return _helper.ToFourDigitYear(year, TwoDigitYearMax); - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/TimeSpanFormat.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/TimeSpanFormat.cs deleted file mode 100644 index 08ffc3269aa..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/TimeSpanFormat.cs +++ /dev/null @@ -1,658 +0,0 @@ -// 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.Buffers.Text; -using System.Diagnostics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Text; - -namespace System.Globalization -{ - internal static class TimeSpanFormat - { - internal static readonly FormatLiterals PositiveInvariantFormatLiterals = TimeSpanFormat.FormatLiterals.InitInvariant(isNegative: false); - internal static readonly FormatLiterals NegativeInvariantFormatLiterals = TimeSpanFormat.FormatLiterals.InitInvariant(isNegative: true); - - /// <summary>Main method called from TimeSpan.ToString.</summary> - internal static string Format(TimeSpan value, string? format, IFormatProvider? formatProvider) - { - if (string.IsNullOrEmpty(format)) - { - return FormatC(value); // formatProvider ignored, as "c" is invariant - } - - if (format.Length == 1) - { - char c = format[0]; - - if (c == 'c' || (c | 0x20) == 't') // special-case to optimize the default TimeSpan format - { - return FormatC(value); // formatProvider ignored, as "c" is invariant - } - - if ((c | 0x20) == 'g') // special-case to optimize the remaining 'g'/'G' standard formats - { - return FormatG(value, DateTimeFormatInfo.GetInstance(formatProvider), c == 'G' ? StandardFormat.G : StandardFormat.g); - } - - throw new FormatException(SR.Format_InvalidString); - } - - return StringBuilderCache.GetStringAndRelease(FormatCustomized(value, format, DateTimeFormatInfo.GetInstance(formatProvider), result: null)); - } - - /// <summary>Main method called from TimeSpan.TryFormat.</summary> - internal static bool TryFormat(TimeSpan value, Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider? formatProvider) - { - if (format.Length == 0) - { - return TryFormatStandard(value, StandardFormat.C, null, destination, out charsWritten); - } - - if (format.Length == 1) - { - char c = format[0]; - if (c == 'c' || ((c | 0x20) == 't')) - { - return TryFormatStandard(value, StandardFormat.C, null, destination, out charsWritten); - } - else - { - StandardFormat sf = - c == 'g' ? StandardFormat.g : - c == 'G' ? StandardFormat.G : - throw new FormatException(SR.Format_InvalidString); - return TryFormatStandard(value, sf, DateTimeFormatInfo.GetInstance(formatProvider).DecimalSeparator, destination, out charsWritten); - } - } - - StringBuilder sb = FormatCustomized(value, format, DateTimeFormatInfo.GetInstance(formatProvider), result: null); - - if (sb.Length <= destination.Length) - { - sb.CopyTo(0, destination, sb.Length); - charsWritten = sb.Length; - StringBuilderCache.Release(sb); - return true; - } - - charsWritten = 0; - StringBuilderCache.Release(sb); - return false; - } - - internal static string FormatC(TimeSpan value) - { - Span<char> destination = stackalloc char[26]; // large enough for any "c" TimeSpan - TryFormatStandard(value, StandardFormat.C, null, destination, out int charsWritten); - return new string(destination.Slice(0, charsWritten)); - } - - private static string FormatG(TimeSpan value, DateTimeFormatInfo dtfi, StandardFormat format) - { - string decimalSeparator = dtfi.DecimalSeparator; - int maxLength = 25 + decimalSeparator.Length; // large enough for any "g"/"G" TimeSpan - Span<char> destination = maxLength < 128 ? - stackalloc char[maxLength] : - new char[maxLength]; // the chances of needing this case are almost 0, as DecimalSeparator.Length will basically always == 1 - TryFormatStandard(value, format, decimalSeparator, destination, out int charsWritten); - return new string(destination.Slice(0, charsWritten)); - } - - private enum StandardFormat { C, G, g } - - private static bool TryFormatStandard(TimeSpan value, StandardFormat format, string? decimalSeparator, Span<char> destination, out int charsWritten) - { - Debug.Assert(format == StandardFormat.C || format == StandardFormat.G || format == StandardFormat.g); - - // First, calculate how large an output buffer is needed to hold the entire output. - int requiredOutputLength = 8; // start with "hh:mm:ss" and adjust as necessary - - uint fraction; - ulong totalSecondsRemaining; - { - // Turn this into a non-negative TimeSpan if possible. - long ticks = value.Ticks; - if (ticks < 0) - { - requiredOutputLength = 9; // requiredOutputLength + 1 for the leading '-' sign - ticks = -ticks; - if (ticks < 0) - { - Debug.Assert(ticks == long.MinValue /* -9223372036854775808 */); - - // We computed these ahead of time; they're straight from the decimal representation of Int64.MinValue. - fraction = 4775808; - totalSecondsRemaining = 922337203685; - goto AfterComputeFraction; - } - } - - totalSecondsRemaining = Math.DivRem((ulong)ticks, TimeSpan.TicksPerSecond, out ulong fraction64); - fraction = (uint)fraction64; - } - - AfterComputeFraction: - // Only write out the fraction if it's non-zero, and in that - // case write out the entire fraction (all digits). - Debug.Assert(fraction < 10_000_000); - int fractionDigits = 0; - switch (format) - { - case StandardFormat.C: - // "c": Write out a fraction only if it's non-zero, and write out all 7 digits of it. - if (fraction != 0) - { - fractionDigits = DateTimeFormat.MaxSecondsFractionDigits; - requiredOutputLength += fractionDigits + 1; // digits plus leading decimal separator - } - break; - - case StandardFormat.G: - // "G": Write out a fraction regardless of whether it's 0, and write out all 7 digits of it. - fractionDigits = DateTimeFormat.MaxSecondsFractionDigits; - requiredOutputLength += fractionDigits + 1; // digits plus leading decimal separator - break; - - default: - // "g": Write out a fraction only if it's non-zero, and write out only the most significant digits. - Debug.Assert(format == StandardFormat.g); - if (fraction != 0) - { - fractionDigits = DateTimeFormat.MaxSecondsFractionDigits - FormattingHelpers.CountDecimalTrailingZeros(fraction, out fraction); - requiredOutputLength += fractionDigits + 1; // digits plus leading decimal separator - } - break; - } - - ulong totalMinutesRemaining = 0, seconds = 0; - if (totalSecondsRemaining > 0) - { - // Only compute minutes if the TimeSpan has an absolute value of >= 1 minute. - totalMinutesRemaining = Math.DivRem(totalSecondsRemaining, 60 /* seconds per minute */, out seconds); - Debug.Assert(seconds < 60); - } - - ulong totalHoursRemaining = 0, minutes = 0; - if (totalMinutesRemaining > 0) - { - // Only compute hours if the TimeSpan has an absolute value of >= 1 hour. - totalHoursRemaining = Math.DivRem(totalMinutesRemaining, 60 /* minutes per hour */, out minutes); - Debug.Assert(minutes < 60); - } - - // At this point, we can switch over to 32-bit DivRem since the data has shrunk far enough. - Debug.Assert(totalHoursRemaining <= uint.MaxValue); - - uint days = 0, hours = 0; - if (totalHoursRemaining > 0) - { - // Only compute days if the TimeSpan has an absolute value of >= 1 day. - days = Math.DivRem((uint)totalHoursRemaining, 24 /* hours per day */, out hours); - Debug.Assert(hours < 24); - } - - int hourDigits = 2; - if (format == StandardFormat.g && hours < 10) - { - // "g": Only writing a one-digit hour, rather than expected two-digit hour - hourDigits = 1; - requiredOutputLength--; - } - - int dayDigits = 0; - if (days > 0) - { - dayDigits = FormattingHelpers.CountDigits(days); - Debug.Assert(dayDigits <= 8); - requiredOutputLength += dayDigits + 1; // for the leading "d." - } - else if (format == StandardFormat.G) - { - // "G": has a leading "0:" if days is 0 - requiredOutputLength += 2; - dayDigits = 1; - } - - if (destination.Length < requiredOutputLength) - { - charsWritten = 0; - return false; - } - - // Write leading '-' if necessary - int idx = 0; - if (value.Ticks < 0) - { - destination[idx++] = '-'; - } - - // Write day and separator, if necessary - if (dayDigits != 0) - { - WriteDigits(days, destination.Slice(idx, dayDigits)); - idx += dayDigits; - destination[idx++] = format == StandardFormat.C ? '.' : ':'; - } - - // Write "[h]h:mm:ss - Debug.Assert(hourDigits == 1 || hourDigits == 2); - if (hourDigits == 2) - { - WriteTwoDigits(hours, destination.Slice(idx)); - idx += 2; - } - else - { - destination[idx++] = (char)('0' + hours); - } - destination[idx++] = ':'; - WriteTwoDigits((uint)minutes, destination.Slice(idx)); - idx += 2; - destination[idx++] = ':'; - WriteTwoDigits((uint)seconds, destination.Slice(idx)); - idx += 2; - - // Write fraction and separator, if necessary - if (fractionDigits != 0) - { - Debug.Assert(format == StandardFormat.C || decimalSeparator != null); - if (format == StandardFormat.C) - { - destination[idx++] = '.'; - } - else if (decimalSeparator!.Length == 1) - { - destination[idx++] = decimalSeparator[0]; - } - else - { - decimalSeparator.AsSpan().CopyTo(destination); - idx += decimalSeparator.Length; - } - WriteDigits(fraction, destination.Slice(idx, fractionDigits)); - idx += fractionDigits; - } - - Debug.Assert(idx == requiredOutputLength); - charsWritten = requiredOutputLength; - return true; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void WriteTwoDigits(uint value, Span<char> buffer) - { - Debug.Assert(buffer.Length >= 2); - uint temp = '0' + value; - value /= 10; - buffer[1] = (char)(temp - (value * 10)); - buffer[0] = (char)('0' + value); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void WriteDigits(uint value, Span<char> buffer) - { - Debug.Assert(buffer.Length > 0); - - for (int i = buffer.Length - 1; i >= 1; i--) - { - uint temp = '0' + value; - value /= 10; - buffer[i] = (char)(temp - (value * 10)); - } - - Debug.Assert(value < 10); - buffer[0] = (char)('0' + value); - } - - /// <summary>Format the TimeSpan instance using the specified format.</summary> - private static StringBuilder FormatCustomized(TimeSpan value, ReadOnlySpan<char> format, DateTimeFormatInfo dtfi, StringBuilder? result = null) - { - Debug.Assert(dtfi != null); - - bool resultBuilderIsPooled = false; - if (result == null) - { - result = StringBuilderCache.Acquire(InternalGlobalizationHelper.StringBuilderDefaultCapacity); - resultBuilderIsPooled = true; - } - - int day = (int)(value.Ticks / TimeSpan.TicksPerDay); - long time = value.Ticks % TimeSpan.TicksPerDay; - - if (value.Ticks < 0) - { - day = -day; - time = -time; - } - int hours = (int)(time / TimeSpan.TicksPerHour % 24); - int minutes = (int)(time / TimeSpan.TicksPerMinute % 60); - int seconds = (int)(time / TimeSpan.TicksPerSecond % 60); - int fraction = (int)(time % TimeSpan.TicksPerSecond); - - long tmp = 0; - int i = 0; - int tokenLen; - - while (i < format.Length) - { - char ch = format[i]; - int nextChar; - switch (ch) - { - case 'h': - tokenLen = DateTimeFormat.ParseRepeatPattern(format, i, ch); - if (tokenLen > 2) - { - goto default; // to release the builder and throw - } - DateTimeFormat.FormatDigits(result, hours, tokenLen); - break; - case 'm': - tokenLen = DateTimeFormat.ParseRepeatPattern(format, i, ch); - if (tokenLen > 2) - { - goto default; // to release the builder and throw - } - DateTimeFormat.FormatDigits(result, minutes, tokenLen); - break; - case 's': - tokenLen = DateTimeFormat.ParseRepeatPattern(format, i, ch); - if (tokenLen > 2) - { - goto default; // to release the builder and throw - } - DateTimeFormat.FormatDigits(result, seconds, tokenLen); - break; - case 'f': - // - // The fraction of a second in single-digit precision. The remaining digits are truncated. - // - tokenLen = DateTimeFormat.ParseRepeatPattern(format, i, ch); - if (tokenLen > DateTimeFormat.MaxSecondsFractionDigits) - { - goto default; // to release the builder and throw - } - - tmp = fraction; - tmp /= TimeSpanParse.Pow10(DateTimeFormat.MaxSecondsFractionDigits - tokenLen); - result.AppendSpanFormattable(tmp, DateTimeFormat.fixedNumberFormats[tokenLen - 1], CultureInfo.InvariantCulture); - break; - case 'F': - // - // Displays the most significant digit of the seconds fraction. Nothing is displayed if the digit is zero. - // - tokenLen = DateTimeFormat.ParseRepeatPattern(format, i, ch); - if (tokenLen > DateTimeFormat.MaxSecondsFractionDigits) - { - goto default; // to release the builder and throw - } - - tmp = fraction; - tmp /= TimeSpanParse.Pow10(DateTimeFormat.MaxSecondsFractionDigits - tokenLen); - int effectiveDigits = tokenLen; - while (effectiveDigits > 0) - { - if (tmp % 10 == 0) - { - tmp /= 10; - effectiveDigits--; - } - else - { - break; - } - } - if (effectiveDigits > 0) - { - result.AppendSpanFormattable(tmp, DateTimeFormat.fixedNumberFormats[effectiveDigits - 1], CultureInfo.InvariantCulture); - } - break; - case 'd': - // - // tokenLen == 1 : Day as digits with no leading zero. - // tokenLen == 2+: Day as digits with leading zero for single-digit days. - // - tokenLen = DateTimeFormat.ParseRepeatPattern(format, i, ch); - if (tokenLen > 8) - { - goto default; // to release the builder and throw - } - - DateTimeFormat.FormatDigits(result, day, tokenLen, true); - break; - case '\'': - case '\"': - tokenLen = DateTimeFormat.ParseQuoteString(format, i, result); - break; - case '%': - // Optional format character. - // For example, format string "%d" will print day - // Most of the cases, "%" can be ignored. - nextChar = DateTimeFormat.ParseNextChar(format, i); - // nextChar will be -1 if we already reach the end of the format string. - // Besides, we will not allow "%%" appear in the pattern. - if (nextChar >= 0 && nextChar != (int)'%') - { - char nextCharChar = (char)nextChar; - StringBuilder origStringBuilder = FormatCustomized(value, MemoryMarshal.CreateReadOnlySpan<char>(ref nextCharChar, 1), dtfi, result); - Debug.Assert(ReferenceEquals(origStringBuilder, result)); - tokenLen = 2; - } - else - { - // - // This means that '%' is at the end of the format string or - // "%%" appears in the format string. - // - goto default; // to release the builder and throw - } - break; - case '\\': - // Escaped character. Can be used to insert character into the format string. - // For example, "\d" will insert the character 'd' into the string. - // - nextChar = DateTimeFormat.ParseNextChar(format, i); - if (nextChar >= 0) - { - result.Append((char)nextChar); - tokenLen = 2; - } - else - { - // - // This means that '\' is at the end of the formatting string. - // - goto default; // to release the builder and throw - } - break; - default: - // Invalid format string - if (resultBuilderIsPooled) - { - StringBuilderCache.Release(result); - } - throw new FormatException(SR.Format_InvalidString); - } - i += tokenLen; - } - return result; - } - - internal struct FormatLiterals - { - internal string AppCompatLiteral; - internal int dd; - internal int hh; - internal int mm; - internal int ss; - internal int ff; - - private string[] _literals; - - internal string Start => _literals[0]; - internal string DayHourSep => _literals[1]; - internal string HourMinuteSep => _literals[2]; - internal string MinuteSecondSep => _literals[3]; - internal string SecondFractionSep => _literals[4]; - internal string End => _literals[5]; - - /* factory method for static invariant FormatLiterals */ - internal static FormatLiterals InitInvariant(bool isNegative) - { - FormatLiterals x = default; - x._literals = new string[6]; - x._literals[0] = isNegative ? "-" : string.Empty; - x._literals[1] = "."; - x._literals[2] = ":"; - x._literals[3] = ":"; - x._literals[4] = "."; - x._literals[5] = string.Empty; - x.AppCompatLiteral = ":."; // MinuteSecondSep+SecondFractionSep; - x.dd = 2; - x.hh = 2; - x.mm = 2; - x.ss = 2; - x.ff = DateTimeFormat.MaxSecondsFractionDigits; - return x; - } - - // For the "v1" TimeSpan localized patterns, the data is simply literal field separators with - // the constants guaranteed to include DHMSF ordered greatest to least significant. - // Once the data becomes more complex than this we will need to write a proper tokenizer for - // parsing and formatting - internal void Init(ReadOnlySpan<char> format, bool useInvariantFieldLengths) - { - dd = hh = mm = ss = ff = 0; - _literals = new string[6]; - for (int i = 0; i < _literals.Length; i++) - { - _literals[i] = string.Empty; - } - - StringBuilder sb = StringBuilderCache.Acquire(InternalGlobalizationHelper.StringBuilderDefaultCapacity); - bool inQuote = false; - char quote = '\''; - int field = 0; - - for (int i = 0; i < format.Length; i++) - { - switch (format[i]) - { - case '\'': - case '\"': - if (inQuote && (quote == format[i])) - { - /* we were in a quote and found a matching exit quote, so we are outside a quote now */ - if (field >= 0 && field <= 5) - { - _literals[field] = sb.ToString(); - sb.Length = 0; - inQuote = false; - } - else - { - Debug.Fail($"Unexpected field value: {field}"); - return; // how did we get here? - } - } - else if (!inQuote) - { - /* we are at the start of a new quote block */ - quote = format[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 '%': - Debug.Fail("Unexpected special token '%', Bug in DateTimeFormatInfo.FullTimeSpan[Positive|Negative]Pattern"); - goto default; - case '\\': - if (!inQuote) - { - i++; /* skip next character that is escaped by this backslash or percent sign */ - break; - } - goto default; - case 'd': - if (!inQuote) - { - Debug.Assert((field == 0 && sb.Length == 0) || field == 1, "field == 0 || field == 1, Bug in DateTimeFormatInfo.FullTimeSpan[Positive|Negative]Pattern"); - field = 1; // DayHourSep - dd++; - } - break; - case 'h': - if (!inQuote) - { - Debug.Assert((field == 1 && sb.Length == 0) || field == 2, "field == 1 || field == 2, Bug in DateTimeFormatInfo.FullTimeSpan[Positive|Negative]Pattern"); - field = 2; // HourMinuteSep - hh++; - } - break; - case 'm': - if (!inQuote) - { - Debug.Assert((field == 2 && sb.Length == 0) || field == 3, "field == 2 || field == 3, Bug in DateTimeFormatInfo.FullTimeSpan[Positive|Negative]Pattern"); - field = 3; // MinuteSecondSep - mm++; - } - break; - case 's': - if (!inQuote) - { - Debug.Assert((field == 3 && sb.Length == 0) || field == 4, "field == 3 || field == 4, Bug in DateTimeFormatInfo.FullTimeSpan[Positive|Negative]Pattern"); - field = 4; // SecondFractionSep - ss++; - } - break; - case 'f': - case 'F': - if (!inQuote) - { - Debug.Assert((field == 4 && sb.Length == 0) || field == 5, "field == 4 || field == 5, Bug in DateTimeFormatInfo.FullTimeSpan[Positive|Negative]Pattern"); - field = 5; // End - ff++; - } - break; - default: - sb.Append(format[i]); - break; - } - } - - Debug.Assert(field == 5); - AppCompatLiteral = MinuteSecondSep + SecondFractionSep; - - Debug.Assert(0 < dd && dd < 3, "0 < dd && dd < 3, Bug in System.Globalization.DateTimeFormatInfo.FullTimeSpan[Positive|Negative]Pattern"); - Debug.Assert(0 < hh && hh < 3, "0 < hh && hh < 3, Bug in System.Globalization.DateTimeFormatInfo.FullTimeSpan[Positive|Negative]Pattern"); - Debug.Assert(0 < mm && mm < 3, "0 < mm && mm < 3, Bug in System.Globalization.DateTimeFormatInfo.FullTimeSpan[Positive|Negative]Pattern"); - Debug.Assert(0 < ss && ss < 3, "0 < ss && ss < 3, Bug in System.Globalization.DateTimeFormatInfo.FullTimeSpan[Positive|Negative]Pattern"); - Debug.Assert(0 < ff && ff < 8, "0 < ff && ff < 8, Bug in System.Globalization.DateTimeFormatInfo.FullTimeSpan[Positive|Negative]Pattern"); - - if (useInvariantFieldLengths) - { - dd = 2; - hh = 2; - mm = 2; - ss = 2; - ff = DateTimeFormat.MaxSecondsFractionDigits; - } - else - { - if (dd < 1 || dd > 2) dd = 2; // The DTFI property has a problem. let's try to make the best of the situation. - if (hh < 1 || hh > 2) hh = 2; - if (mm < 1 || mm > 2) mm = 2; - if (ss < 1 || ss > 2) ss = 2; - if (ff < 1 || ff > 7) ff = 7; - } - StringBuilderCache.Release(sb); - } - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/TimeSpanParse.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/TimeSpanParse.cs deleted file mode 100644 index 0a2df773409..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/TimeSpanParse.cs +++ /dev/null @@ -1,1705 +0,0 @@ -// 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: Used by TimeSpan to parse a time interval string. -// -// Standard Format: -// -=-=-=-=-=-=-=- -// "c": Constant format. [-][d'.']hh':'mm':'ss['.'fffffff] -// Not culture sensitive. Default format (and null/empty format string) map to this format. -// -// "g": General format, short: [-][d':']h':'mm':'ss'.'FFFFFFF -// Only print what's needed. Localized (if you want Invariant, pass in Invariant). -// The fractional seconds separator is localized, equal to the culture's DecimalSeparator. -// -// "G": General format, long: [-]d':'hh':'mm':'ss'.'fffffff -// Always print days and 7 fractional digits. Localized (if you want Invariant, pass in Invariant). -// The fractional seconds separator is localized, equal to the culture's DecimalSeparator. -// -// * "TryParseTimeSpan" is the main method for Parse/TryParse -// -// - TimeSpanTokenizer.GetNextToken() is used to split the input string into number and literal tokens. -// - TimeSpanRawInfo.ProcessToken() adds the next token into the parsing intermediary state structure -// - ProcessTerminalState() uses the fully initialized TimeSpanRawInfo to find a legal parse match. -// The terminal states are attempted as follows: -// foreach (+InvariantPattern, -InvariantPattern, +LocalizedPattern, -LocalizedPattern) try -// 1 number => d -// 2 numbers => h:m -// 3 numbers => h:m:s | d.h:m | h:m:.f -// 4 numbers => h:m:s.f | d.h:m:s | d.h:m:.f -// 5 numbers => d.h:m:s.f -// -// Custom Format: -// -=-=-=-=-=-=-= -// -// * "TryParseExactTimeSpan" is the main method for ParseExact/TryParseExact methods -// * "TryParseExactMultipleTimeSpan" is the main method for ParseExact/TryparseExact -// methods that take a string[] of formats -// -// - For single-letter formats "TryParseTimeSpan" is called (see above) -// - For multi-letter formats "TryParseByFormat" is called -// - TryParseByFormat uses helper methods (ParseExactLiteral, ParseExactDigits, etc) -// which drive the underlying TimeSpanTokenizer. However, unlike standard formatting which -// operates on whole-tokens, ParseExact operates at the character-level. As such, -// TimeSpanTokenizer.NextChar and TimeSpanTokenizer.BackOne() are called directly. -// -//////////////////////////////////////////////////////////////////////////// - -using System.Diagnostics; -using System.Text; - -namespace System.Globalization -{ - internal static class TimeSpanParse - { - private const int MaxFractionDigits = 7; - private const int MaxDays = 10675199; - private const int MaxHours = 23; - private const int MaxMinutes = 59; - private const int MaxSeconds = 59; - private const int MaxFraction = 9999999; - - [Flags] - private enum TimeSpanStandardStyles : byte - { - // Standard Format Styles - None = 0x00000000, - Invariant = 0x00000001, // Allow Invariant Culture - Localized = 0x00000002, // Allow Localized Culture - RequireFull = 0x00000004, // Require the input to be in DHMSF format - Any = Invariant | Localized, - } - - // TimeSpan Token Types - private enum TTT : byte - { - None = 0, // None of the TimeSpanToken fields are set - End = 1, // '\0' - Num = 2, // Number - Sep = 3, // literal - NumOverflow = 4, // Number that overflowed - } - - private ref struct TimeSpanToken - { - internal TTT _ttt; - internal int _num; // Store the number that we are parsing (if any) - internal int _zeroes; // Store the number of leading zeroes (if any) - internal ReadOnlySpan<char> _sep; // Store the literal that we are parsing (if any) - - public TimeSpanToken(TTT type) : this(type, 0, 0, default) { } - - public TimeSpanToken(int number) : this(TTT.Num, number, 0, default) { } - - public TimeSpanToken(int number, int leadingZeroes) : this(TTT.Num, number, leadingZeroes, default) { } - - public TimeSpanToken(TTT type, int number, int leadingZeroes, ReadOnlySpan<char> separator) - { - _ttt = type; - _num = number; - _zeroes = leadingZeroes; - _sep = separator; - } - - public bool NormalizeAndValidateFraction() - { - Debug.Assert(_ttt == TTT.Num); - Debug.Assert(_num > -1); - - if (_num == 0) - return true; - - if (_zeroes == 0 && _num > MaxFraction) - return false; - - int totalDigitsCount = ((int)Math.Floor(Math.Log10(_num))) + 1 + _zeroes; - - if (totalDigitsCount == MaxFractionDigits) - { - // Already normalized. no more action needed - // .9999999 normalize to 9,999,999 ticks - // .0000001 normalize to 1 ticks - return true; - } - - if (totalDigitsCount < MaxFractionDigits) - { - // normalize the fraction to the 7-digits - // .999999 normalize to 9,999,990 ticks - // .99999 normalize to 9,999,900 ticks - // .000001 normalize to 10 ticks - // .1 normalize to 1,000,000 ticks - - _num *= (int)Pow10(MaxFractionDigits - totalDigitsCount); - return true; - } - - // totalDigitsCount is greater then MaxFractionDigits, we'll need to do the rounding to 7-digits length - // .00000001 normalized to 0 ticks - // .00000005 normalized to 1 ticks - // .09999999 normalize to 1,000,000 ticks - // .099999999 normalize to 1,000,000 ticks - - Debug.Assert(_zeroes > 0); // Already validated that in the condition _zeroes == 0 && _num > MaxFraction - _num = (int)Math.Round((double)_num / Pow10(totalDigitsCount - MaxFractionDigits), MidpointRounding.AwayFromZero); - Debug.Assert(_num < MaxFraction); - - return true; - } - } - - private ref struct TimeSpanTokenizer - { - private readonly ReadOnlySpan<char> _value; - private int _pos; - - internal TimeSpanTokenizer(ReadOnlySpan<char> input) : this(input, 0) { } - - internal TimeSpanTokenizer(ReadOnlySpan<char> input, int startPosition) - { - _value = input; - _pos = startPosition; - } - - /// <summary>Returns the next token in the input string</summary> - /// <remarks>Used by the parsing routines that operate on standard-formats.</remarks> - internal TimeSpanToken GetNextToken() - { - // Get the position of the next character to be processed. If there is no - // next character, we're at the end. - int pos = _pos; - Debug.Assert(pos > -1); - if (pos >= _value.Length) - { - return new TimeSpanToken(TTT.End); - } - - // Now retrieve that character. If it's a digit, we're processing a number. - int num = _value[pos] - '0'; - if ((uint)num <= 9) - { - int zeroes = 0; - if (num == 0) - { - // Read all leading zeroes. - zeroes = 1; - while (true) - { - int digit; - if (++_pos >= _value.Length || (uint)(digit = _value[_pos] - '0') > 9) - { - return new TimeSpanToken(TTT.Num, 0, zeroes, default); - } - - if (digit == 0) - { - zeroes++; - continue; - } - - num = digit; - break; - } - } - - // Continue to read as long as we're reading digits. - while (++_pos < _value.Length) - { - int digit = _value[_pos] - '0'; - if ((uint)digit > 9) - { - break; - } - - num = num * 10 + digit; - if ((num & 0xF0000000) != 0) // Max limit we can support 268435455 which is FFFFFFF - { - return new TimeSpanToken(TTT.NumOverflow); - } - } - - return new TimeSpanToken(TTT.Num, num, zeroes, default); - } - - // Otherwise, we're processing a separator, and we've already processed the first - // character of it. Continue processing characters as long as they're not digits. - int length = 1; - while (true) - { - if (++_pos >= _value.Length || (uint)(_value[_pos] - '0') <= 9) - { - break; - } - length++; - } - - // Return the separator. - return new TimeSpanToken(TTT.Sep, 0, 0, _value.Slice(pos, length)); - } - - internal bool EOL => _pos >= (_value.Length - 1); - - internal void BackOne() - { - if (_pos > 0) --_pos; - } - - internal char NextChar - { - get - { - int pos = ++_pos; - return (uint)pos < (uint)_value.Length ? - _value[pos] : - (char)0; - } - } - } - - /// <summary>Stores intermediary parsing state for the standard formats.</summary> - private ref struct TimeSpanRawInfo - { - internal TimeSpanFormat.FormatLiterals PositiveLocalized - { - get - { - if (!_posLocInit) - { - _posLoc = default; - _posLoc.Init(_fullPosPattern, false); - _posLocInit = true; - } - return _posLoc; - } - } - - internal TimeSpanFormat.FormatLiterals NegativeLocalized - { - get - { - if (!_negLocInit) - { - _negLoc = default; - _negLoc.Init(_fullNegPattern, false); - _negLocInit = true; - } - return _negLoc; - } - } - - internal bool FullAppCompatMatch(TimeSpanFormat.FormatLiterals pattern) => - _sepCount == 5 - && _numCount == 4 - && _literals0.EqualsOrdinal(pattern.Start) - && _literals1.EqualsOrdinal(pattern.DayHourSep) - && _literals2.EqualsOrdinal(pattern.HourMinuteSep) - && _literals3.EqualsOrdinal(pattern.AppCompatLiteral) - && _literals4.EqualsOrdinal(pattern.End); - - internal bool PartialAppCompatMatch(TimeSpanFormat.FormatLiterals pattern) => - _sepCount == 4 - && _numCount == 3 - && _literals0.EqualsOrdinal(pattern.Start) - && _literals1.EqualsOrdinal(pattern.HourMinuteSep) - && _literals2.EqualsOrdinal(pattern.AppCompatLiteral) - && _literals3.EqualsOrdinal(pattern.End); - - /// <summary>DHMSF (all values matched)</summary> - internal bool FullMatch(TimeSpanFormat.FormatLiterals pattern) => - _sepCount == MaxLiteralTokens - && _numCount == MaxNumericTokens - && _literals0.EqualsOrdinal(pattern.Start) - && _literals1.EqualsOrdinal(pattern.DayHourSep) - && _literals2.EqualsOrdinal(pattern.HourMinuteSep) - && _literals3.EqualsOrdinal(pattern.MinuteSecondSep) - && _literals4.EqualsOrdinal(pattern.SecondFractionSep) - && _literals5.EqualsOrdinal(pattern.End); - - /// <summary>D (no hours, minutes, seconds, or fractions)</summary> - internal bool FullDMatch(TimeSpanFormat.FormatLiterals pattern) => - _sepCount == 2 - && _numCount == 1 - && _literals0.EqualsOrdinal(pattern.Start) - && _literals1.EqualsOrdinal(pattern.End); - - /// <summary>HM (no days, seconds, or fractions)</summary> - internal bool FullHMMatch(TimeSpanFormat.FormatLiterals pattern) => - _sepCount == 3 - && _numCount == 2 - && _literals0.EqualsOrdinal(pattern.Start) - && _literals1.EqualsOrdinal(pattern.HourMinuteSep) - && _literals2.EqualsOrdinal(pattern.End); - - /// <summary>DHM (no seconds or fraction)</summary> - internal bool FullDHMMatch(TimeSpanFormat.FormatLiterals pattern) => - _sepCount == 4 - && _numCount == 3 - && _literals0.EqualsOrdinal(pattern.Start) - && _literals1.EqualsOrdinal(pattern.DayHourSep) - && _literals2.EqualsOrdinal(pattern.HourMinuteSep) - && _literals3.EqualsOrdinal(pattern.End); - - /// <summary>HMS (no days or fraction)</summary> - internal bool FullHMSMatch(TimeSpanFormat.FormatLiterals pattern) => - _sepCount == 4 - && _numCount == 3 - && _literals0.EqualsOrdinal(pattern.Start) - && _literals1.EqualsOrdinal(pattern.HourMinuteSep) - && _literals2.EqualsOrdinal(pattern.MinuteSecondSep) - && _literals3.EqualsOrdinal(pattern.End); - - /// <summary>DHMS (no fraction)</summary> - internal bool FullDHMSMatch(TimeSpanFormat.FormatLiterals pattern) => - _sepCount == 5 - && _numCount == 4 - && _literals0.EqualsOrdinal(pattern.Start) - && _literals1.EqualsOrdinal(pattern.DayHourSep) - && _literals2.EqualsOrdinal(pattern.HourMinuteSep) - && _literals3.EqualsOrdinal(pattern.MinuteSecondSep) - && _literals4.EqualsOrdinal(pattern.End); - - /// <summary>HMSF (no days)</summary> - internal bool FullHMSFMatch(TimeSpanFormat.FormatLiterals pattern) => - _sepCount == 5 - && _numCount == 4 - && _literals0.EqualsOrdinal(pattern.Start) - && _literals1.EqualsOrdinal(pattern.HourMinuteSep) - && _literals2.EqualsOrdinal(pattern.MinuteSecondSep) - && _literals3.EqualsOrdinal(pattern.SecondFractionSep) - && _literals4.EqualsOrdinal(pattern.End); - - internal TTT _lastSeenTTT; - internal int _tokenCount; - internal int _sepCount; - internal int _numCount; - - private TimeSpanFormat.FormatLiterals _posLoc; - private TimeSpanFormat.FormatLiterals _negLoc; - private bool _posLocInit; - private bool _negLocInit; - private string _fullPosPattern; - private string _fullNegPattern; - - private const int MaxTokens = 11; - private const int MaxLiteralTokens = 6; - private const int MaxNumericTokens = 5; - - internal TimeSpanToken _numbers0, _numbers1, _numbers2, _numbers3, _numbers4; // MaxNumbericTokens = 5 - internal ReadOnlySpan<char> _literals0, _literals1, _literals2, _literals3, _literals4, _literals5; // MaxLiteralTokens=6 - - internal void Init(DateTimeFormatInfo dtfi) - { - Debug.Assert(dtfi != null); - - _lastSeenTTT = TTT.None; - _tokenCount = 0; - _sepCount = 0; - _numCount = 0; - - _fullPosPattern = dtfi.FullTimeSpanPositivePattern; - _fullNegPattern = dtfi.FullTimeSpanNegativePattern; - _posLocInit = false; - _negLocInit = false; - } - - internal bool ProcessToken(ref TimeSpanToken tok, ref TimeSpanResult result) - { - switch (tok._ttt) - { - case TTT.Num: - if ((_tokenCount == 0 && !AddSep(default, ref result)) || !AddNum(tok, ref result)) - { - return false; - } - break; - - case TTT.Sep: - if (!AddSep(tok._sep, ref result)) - { - return false; - } - break; - - case TTT.NumOverflow: - return result.SetOverflowFailure(); - - default: - // Some unknown token or a repeat token type in the input - return result.SetBadTimeSpanFailure(); - } - - _lastSeenTTT = tok._ttt; - Debug.Assert(_tokenCount == (_sepCount + _numCount), "tokenCount == (SepCount + NumCount)"); - return true; - } - - private bool AddSep(ReadOnlySpan<char> sep, ref TimeSpanResult result) - { - if (_sepCount >= MaxLiteralTokens || _tokenCount >= MaxTokens) - { - return result.SetBadTimeSpanFailure(); - } - - switch (_sepCount++) - { - case 0: _literals0 = sep; break; - case 1: _literals1 = sep; break; - case 2: _literals2 = sep; break; - case 3: _literals3 = sep; break; - case 4: _literals4 = sep; break; - default: _literals5 = sep; break; - } - - _tokenCount++; - return true; - } - private bool AddNum(TimeSpanToken num, ref TimeSpanResult result) - { - if (_numCount >= MaxNumericTokens || _tokenCount >= MaxTokens) - { - return result.SetBadTimeSpanFailure(); - } - - switch (_numCount++) - { - case 0: _numbers0 = num; break; - case 1: _numbers1 = num; break; - case 2: _numbers2 = num; break; - case 3: _numbers3 = num; break; - default: _numbers4 = num; break; - } - - _tokenCount++; - return true; - } - } - - /// <summary>Store the result of the parsing.</summary> - private ref struct TimeSpanResult - { - internal TimeSpan parsedTimeSpan; - private readonly bool _throwOnFailure; - private readonly ReadOnlySpan<char> _originalTimeSpanString; - - internal TimeSpanResult(bool throwOnFailure, ReadOnlySpan<char> originalTimeSpanString) - { - parsedTimeSpan = default; - _throwOnFailure = throwOnFailure; - _originalTimeSpanString = originalTimeSpanString; - } - - internal bool SetNoFormatSpecifierFailure() - { - if (!_throwOnFailure) - { - return false; - } - - throw new FormatException(SR.Format_NoFormatSpecifier); - } - - internal bool SetBadQuoteFailure(char failingCharacter) - { - if (!_throwOnFailure) - { - return false; - } - - throw new FormatException(SR.Format(SR.Format_BadQuote, failingCharacter)); - } - - internal bool SetInvalidStringFailure() - { - if (!_throwOnFailure) - { - return false; - } - - throw new FormatException(SR.Format_InvalidString); - } - - internal bool SetArgumentNullFailure(string argumentName) - { - if (!_throwOnFailure) - { - return false; - } - - Debug.Assert(argumentName != null); - throw new ArgumentNullException(argumentName, SR.ArgumentNull_String); - } - - internal bool SetOverflowFailure() - { - if (!_throwOnFailure) - { - return false; - } - - throw new OverflowException(SR.Format(SR.Overflow_TimeSpanElementTooLarge, new string(_originalTimeSpanString))); - } - - internal bool SetBadTimeSpanFailure() - { - if (!_throwOnFailure) - { - return false; - } - - throw new FormatException(SR.Format(SR.Format_BadTimeSpan, new string(_originalTimeSpanString))); - } - - internal bool SetBadFormatSpecifierFailure(char? formatSpecifierCharacter = null) - { - if (!_throwOnFailure) - { - return false; - } - - throw new FormatException(SR.Format(SR.Format_BadFormatSpecifier, formatSpecifierCharacter)); - } - } - - internal static long Pow10(int pow) - { - return pow switch - { - 0 => 1, - 1 => 10, - 2 => 100, - 3 => 1000, - 4 => 10000, - 5 => 100000, - 6 => 1000000, - 7 => 10000000, - _ => (long)Math.Pow(10, pow), - }; - } - - private static bool TryTimeToTicks(bool positive, TimeSpanToken days, TimeSpanToken hours, TimeSpanToken minutes, TimeSpanToken seconds, TimeSpanToken fraction, out long result) - { - if (days._num > MaxDays || - hours._num > MaxHours || - minutes._num > MaxMinutes || - seconds._num > MaxSeconds || - !fraction.NormalizeAndValidateFraction()) - { - result = 0; - return false; - } - - long ticks = ((long)days._num * 3600 * 24 + (long)hours._num * 3600 + (long)minutes._num * 60 + seconds._num) * 1000; - if (ticks > InternalGlobalizationHelper.MaxMilliSeconds || ticks < InternalGlobalizationHelper.MinMilliSeconds) - { - result = 0; - return false; - } - - result = ticks * TimeSpan.TicksPerMillisecond + fraction._num; - if (positive && result < 0) - { - result = 0; - return false; - } - - return true; - } - - internal static TimeSpan Parse(ReadOnlySpan<char> input, IFormatProvider? formatProvider) - { - var parseResult = new TimeSpanResult(throwOnFailure: true, originalTimeSpanString: input); - bool success = TryParseTimeSpan(input, TimeSpanStandardStyles.Any, formatProvider, ref parseResult); - Debug.Assert(success, "Should have thrown on failure"); - return parseResult.parsedTimeSpan; - } - - internal static bool TryParse(ReadOnlySpan<char> input, IFormatProvider? formatProvider, out TimeSpan result) - { - var parseResult = new TimeSpanResult(throwOnFailure: false, originalTimeSpanString: input); - - if (TryParseTimeSpan(input, TimeSpanStandardStyles.Any, formatProvider, ref parseResult)) - { - result = parseResult.parsedTimeSpan; - return true; - } - - result = default; - return false; - } - - internal static TimeSpan ParseExact(ReadOnlySpan<char> input, ReadOnlySpan<char> format, IFormatProvider? formatProvider, TimeSpanStyles styles) - { - var parseResult = new TimeSpanResult(throwOnFailure: true, originalTimeSpanString: input); - bool success = TryParseExactTimeSpan(input, format, formatProvider, styles, ref parseResult); - Debug.Assert(success, "Should have thrown on failure"); - return parseResult.parsedTimeSpan; - } - - internal static bool TryParseExact(ReadOnlySpan<char> input, ReadOnlySpan<char> format, IFormatProvider? formatProvider, TimeSpanStyles styles, out TimeSpan result) - { - var parseResult = new TimeSpanResult(throwOnFailure: false, originalTimeSpanString: input); - - if (TryParseExactTimeSpan(input, format, formatProvider, styles, ref parseResult)) - { - result = parseResult.parsedTimeSpan; - return true; - } - - result = default; - return false; - } - - internal static TimeSpan ParseExactMultiple(ReadOnlySpan<char> input, string[] formats, IFormatProvider? formatProvider, TimeSpanStyles styles) - { - var parseResult = new TimeSpanResult(throwOnFailure: true, originalTimeSpanString: input); - bool success = TryParseExactMultipleTimeSpan(input, formats, formatProvider, styles, ref parseResult); - Debug.Assert(success, "Should have thrown on failure"); - return parseResult.parsedTimeSpan; - } - - internal static bool TryParseExactMultiple(ReadOnlySpan<char> input, string[] formats, IFormatProvider? formatProvider, TimeSpanStyles styles, out TimeSpan result) - { - var parseResult = new TimeSpanResult(throwOnFailure: false, originalTimeSpanString: input); - - if (TryParseExactMultipleTimeSpan(input, formats, formatProvider, styles, ref parseResult)) - { - result = parseResult.parsedTimeSpan; - return true; - } - - result = default; - return false; - } - - /// <summary>Common private Parse method called by both Parse and TryParse.</summary> - private static bool TryParseTimeSpan(ReadOnlySpan<char> input, TimeSpanStandardStyles style, IFormatProvider? formatProvider, ref TimeSpanResult result) - { - input = input.Trim(); - if (input.IsEmpty) - { - return result.SetBadTimeSpanFailure(); - } - - var tokenizer = new TimeSpanTokenizer(input); - - TimeSpanRawInfo raw = default; - raw.Init(DateTimeFormatInfo.GetInstance(formatProvider)); - - TimeSpanToken tok = tokenizer.GetNextToken(); - - // The following loop will break out when we reach the end of the str or - // when we can determine that the input is invalid. - while (tok._ttt != TTT.End) - { - if (!raw.ProcessToken(ref tok, ref result)) - { - return result.SetBadTimeSpanFailure(); - } - tok = tokenizer.GetNextToken(); - } - Debug.Assert(tokenizer.EOL); - - if (!ProcessTerminalState(ref raw, style, ref result)) - { - return result.SetBadTimeSpanFailure(); - } - - return true; - } - - /// <summary> - /// Validate the terminal state of a standard format parse. - /// Sets result.parsedTimeSpan on success. - /// Calculates the resultant TimeSpan from the TimeSpanRawInfo. - /// </summary> - /// <remarks> - /// try => +InvariantPattern, -InvariantPattern, +LocalizedPattern, -LocalizedPattern - /// 1) Verify Start matches - /// 2) Verify End matches - /// 3) 1 number => d - /// 2 numbers => h:m - /// 3 numbers => h:m:s | d.h:m | h:m:.f - /// 4 numbers => h:m:s.f | d.h:m:s | d.h:m:.f - /// 5 numbers => d.h:m:s.f - /// </remarks> - private static bool ProcessTerminalState(ref TimeSpanRawInfo raw, TimeSpanStandardStyles style, ref TimeSpanResult result) - { - if (raw._lastSeenTTT == TTT.Num) - { - TimeSpanToken tok = default; - tok._ttt = TTT.Sep; - if (!raw.ProcessToken(ref tok, ref result)) - { - return result.SetBadTimeSpanFailure(); - } - } - - return raw._numCount switch - { - 1 => ProcessTerminal_D(ref raw, style, ref result), - 2 => ProcessTerminal_HM(ref raw, style, ref result), - 3 => ProcessTerminal_HM_S_D(ref raw, style, ref result), - 4 => ProcessTerminal_HMS_F_D(ref raw, style, ref result), - 5 => ProcessTerminal_DHMSF(ref raw, style, ref result), - _ => result.SetBadTimeSpanFailure(), - }; - } - - /// <summary>Validate the 5-number "Days.Hours:Minutes:Seconds.Fraction" terminal case.</summary> - private static bool ProcessTerminal_DHMSF(ref TimeSpanRawInfo raw, TimeSpanStandardStyles style, ref TimeSpanResult result) - { - if (raw._sepCount != 6) - { - return result.SetBadTimeSpanFailure(); - } - Debug.Assert(raw._numCount == 5); - - bool inv = (style & TimeSpanStandardStyles.Invariant) != 0; - bool loc = (style & TimeSpanStandardStyles.Localized) != 0; - bool positive = false; - bool match = false; - - if (inv) - { - if (raw.FullMatch(TimeSpanFormat.PositiveInvariantFormatLiterals)) - { - match = true; - positive = true; - } - if (!match && raw.FullMatch(TimeSpanFormat.NegativeInvariantFormatLiterals)) - { - match = true; - positive = false; - } - } - - if (loc) - { - if (!match && raw.FullMatch(raw.PositiveLocalized)) - { - match = true; - positive = true; - } - if (!match && raw.FullMatch(raw.NegativeLocalized)) - { - match = true; - positive = false; - } - } - - if (match) - { - long ticks; - - if (!TryTimeToTicks(positive, raw._numbers0, raw._numbers1, raw._numbers2, raw._numbers3, raw._numbers4, out ticks)) - { - return result.SetOverflowFailure(); - } - - if (!positive) - { - ticks = -ticks; - if (ticks > 0) - { - return result.SetOverflowFailure(); - } - } - - result.parsedTimeSpan = new TimeSpan(ticks); - return true; - } - - return result.SetBadTimeSpanFailure(); - } - - - /// <summary> - /// Validate the ambiguous 4-number "Hours:Minutes:Seconds.Fraction", "Days.Hours:Minutes:Seconds", - /// or "Days.Hours:Minutes:.Fraction" terminal case. - /// </summary> - private static bool ProcessTerminal_HMS_F_D(ref TimeSpanRawInfo raw, TimeSpanStandardStyles style, ref TimeSpanResult result) - { - if (raw._sepCount != 5 || (style & TimeSpanStandardStyles.RequireFull) != 0) - { - return result.SetBadTimeSpanFailure(); - } - Debug.Assert(raw._numCount == 4); - - bool inv = ((style & TimeSpanStandardStyles.Invariant) != 0); - bool loc = ((style & TimeSpanStandardStyles.Localized) != 0); - - long ticks = 0; - bool positive = false, match = false, overflow = false; - var zero = new TimeSpanToken(0); - - if (inv) - { - if (raw.FullHMSFMatch(TimeSpanFormat.PositiveInvariantFormatLiterals)) - { - positive = true; - match = TryTimeToTicks(positive, zero, raw._numbers0, raw._numbers1, raw._numbers2, raw._numbers3, out ticks); - overflow = overflow || !match; - } - - if (!match && raw.FullDHMSMatch(TimeSpanFormat.PositiveInvariantFormatLiterals)) - { - positive = true; - match = TryTimeToTicks(positive, raw._numbers0, raw._numbers1, raw._numbers2, raw._numbers3, zero, out ticks); - overflow = overflow || !match; - } - - if (!match && raw.FullAppCompatMatch(TimeSpanFormat.PositiveInvariantFormatLiterals)) - { - positive = true; - match = TryTimeToTicks(positive, raw._numbers0, raw._numbers1, raw._numbers2, zero, raw._numbers3, out ticks); - overflow = overflow || !match; - } - - if (!match && raw.FullHMSFMatch(TimeSpanFormat.NegativeInvariantFormatLiterals)) - { - positive = false; - match = TryTimeToTicks(positive, zero, raw._numbers0, raw._numbers1, raw._numbers2, raw._numbers3, out ticks); - overflow = overflow || !match; - } - - if (!match && raw.FullDHMSMatch(TimeSpanFormat.NegativeInvariantFormatLiterals)) - { - positive = false; - match = TryTimeToTicks(positive, raw._numbers0, raw._numbers1, raw._numbers2, raw._numbers3, zero, out ticks); - overflow = overflow || !match; - } - - if (!match && raw.FullAppCompatMatch(TimeSpanFormat.NegativeInvariantFormatLiterals)) - { - positive = false; - match = TryTimeToTicks(positive, raw._numbers0, raw._numbers1, raw._numbers2, zero, raw._numbers3, out ticks); - overflow = overflow || !match; - } - } - - if (loc) - { - if (!match && raw.FullHMSFMatch(raw.PositiveLocalized)) - { - positive = true; - match = TryTimeToTicks(positive, zero, raw._numbers0, raw._numbers1, raw._numbers2, raw._numbers3, out ticks); - overflow = overflow || !match; - } - - if (!match && raw.FullDHMSMatch(raw.PositiveLocalized)) - { - positive = true; - match = TryTimeToTicks(positive, raw._numbers0, raw._numbers1, raw._numbers2, raw._numbers3, zero, out ticks); - overflow = overflow || !match; - } - - if (!match && raw.FullAppCompatMatch(raw.PositiveLocalized)) - { - positive = true; - match = TryTimeToTicks(positive, raw._numbers0, raw._numbers1, raw._numbers2, zero, raw._numbers3, out ticks); - overflow = overflow || !match; - } - - if (!match && raw.FullHMSFMatch(raw.NegativeLocalized)) - { - positive = false; - match = TryTimeToTicks(positive, zero, raw._numbers0, raw._numbers1, raw._numbers2, raw._numbers3, out ticks); - overflow = overflow || !match; - } - - if (!match && raw.FullDHMSMatch(raw.NegativeLocalized)) - { - positive = false; - match = TryTimeToTicks(positive, raw._numbers0, raw._numbers1, raw._numbers2, raw._numbers3, zero, out ticks); - overflow = overflow || !match; - } - - if (!match && raw.FullAppCompatMatch(raw.NegativeLocalized)) - { - positive = false; - match = TryTimeToTicks(positive, raw._numbers0, raw._numbers1, raw._numbers2, zero, raw._numbers3, out ticks); - overflow = overflow || !match; - } - } - - if (match) - { - if (!positive) - { - ticks = -ticks; - if (ticks > 0) - { - return result.SetOverflowFailure(); - } - } - - result.parsedTimeSpan = new TimeSpan(ticks); - return true; - } - - return overflow ? - result.SetOverflowFailure() : // we found at least one literal pattern match but the numbers just didn't fit - result.SetBadTimeSpanFailure(); // we couldn't find a thing - } - - /// <summary>Validate the ambiguous 3-number "Hours:Minutes:Seconds", "Days.Hours:Minutes", or "Hours:Minutes:.Fraction" terminal case.</summary> - private static bool ProcessTerminal_HM_S_D(ref TimeSpanRawInfo raw, TimeSpanStandardStyles style, ref TimeSpanResult result) - { - if (raw._sepCount != 4 || (style & TimeSpanStandardStyles.RequireFull) != 0) - { - return result.SetBadTimeSpanFailure(); - } - Debug.Assert(raw._numCount == 3); - - bool inv = ((style & TimeSpanStandardStyles.Invariant) != 0); - bool loc = ((style & TimeSpanStandardStyles.Localized) != 0); - - bool positive = false, match = false, overflow = false; - var zero = new TimeSpanToken(0); - long ticks = 0; - - if (inv) - { - if (raw.FullHMSMatch(TimeSpanFormat.PositiveInvariantFormatLiterals)) - { - positive = true; - match = TryTimeToTicks(positive, zero, raw._numbers0, raw._numbers1, raw._numbers2, zero, out ticks); - overflow = overflow || !match; - } - - if (!match && raw.FullDHMMatch(TimeSpanFormat.PositiveInvariantFormatLiterals)) - { - positive = true; - match = TryTimeToTicks(positive, raw._numbers0, raw._numbers1, raw._numbers2, zero, zero, out ticks); - overflow = overflow || !match; - } - - if (!match && raw.PartialAppCompatMatch(TimeSpanFormat.PositiveInvariantFormatLiterals)) - { - positive = true; - match = TryTimeToTicks(positive, zero, raw._numbers0, raw._numbers1, zero, raw._numbers2, out ticks); - overflow = overflow || !match; - } - - if (!match && raw.FullHMSMatch(TimeSpanFormat.NegativeInvariantFormatLiterals)) - { - positive = false; - match = TryTimeToTicks(positive, zero, raw._numbers0, raw._numbers1, raw._numbers2, zero, out ticks); - overflow = overflow || !match; - } - - if (!match && raw.FullDHMMatch(TimeSpanFormat.NegativeInvariantFormatLiterals)) - { - positive = false; - match = TryTimeToTicks(positive, raw._numbers0, raw._numbers1, raw._numbers2, zero, zero, out ticks); - overflow = overflow || !match; - } - - if (!match && raw.PartialAppCompatMatch(TimeSpanFormat.NegativeInvariantFormatLiterals)) - { - positive = false; - match = TryTimeToTicks(positive, zero, raw._numbers0, raw._numbers1, zero, raw._numbers2, out ticks); - overflow = overflow || !match; - } - } - - if (loc) - { - if (!match && raw.FullHMSMatch(raw.PositiveLocalized)) - { - positive = true; - match = TryTimeToTicks(positive, zero, raw._numbers0, raw._numbers1, raw._numbers2, zero, out ticks); - overflow = overflow || !match; - } - - if (!match && raw.FullDHMMatch(raw.PositiveLocalized)) - { - positive = true; - match = TryTimeToTicks(positive, raw._numbers0, raw._numbers1, raw._numbers2, zero, zero, out ticks); - overflow = overflow || !match; - } - - if (!match && raw.PartialAppCompatMatch(raw.PositiveLocalized)) - { - positive = true; - match = TryTimeToTicks(positive, zero, raw._numbers0, raw._numbers1, zero, raw._numbers2, out ticks); - overflow = overflow || !match; - } - - if (!match && raw.FullHMSMatch(raw.NegativeLocalized)) - { - positive = false; - match = TryTimeToTicks(positive, zero, raw._numbers0, raw._numbers1, raw._numbers2, zero, out ticks); - overflow = overflow || !match; - } - - if (!match && raw.FullDHMMatch(raw.NegativeLocalized)) - { - positive = false; - match = TryTimeToTicks(positive, raw._numbers0, raw._numbers1, raw._numbers2, zero, zero, out ticks); - overflow = overflow || !match; - } - - if (!match && raw.PartialAppCompatMatch(raw.NegativeLocalized)) - { - positive = false; - match = TryTimeToTicks(positive, zero, raw._numbers0, raw._numbers1, zero, raw._numbers2, out ticks); - overflow = overflow || !match; - } - } - - if (match) - { - if (!positive) - { - ticks = -ticks; - if (ticks > 0) - { - return result.SetOverflowFailure(); - } - } - - result.parsedTimeSpan = new TimeSpan(ticks); - return true; - } - - return overflow ? - result.SetOverflowFailure() : // we found at least one literal pattern match but the numbers just didn't fit - result.SetBadTimeSpanFailure(); // we couldn't find a thing - } - - /// <summary>Validate the 2-number "Hours:Minutes" terminal case.</summary> - private static bool ProcessTerminal_HM(ref TimeSpanRawInfo raw, TimeSpanStandardStyles style, ref TimeSpanResult result) - { - if (raw._sepCount != 3 || (style & TimeSpanStandardStyles.RequireFull) != 0) - { - return result.SetBadTimeSpanFailure(); - } - Debug.Assert(raw._numCount == 2); - - bool inv = ((style & TimeSpanStandardStyles.Invariant) != 0); - bool loc = ((style & TimeSpanStandardStyles.Localized) != 0); - - bool positive = false, match = false; - - if (inv) - { - if (raw.FullHMMatch(TimeSpanFormat.PositiveInvariantFormatLiterals)) - { - match = true; - positive = true; - } - - if (!match && raw.FullHMMatch(TimeSpanFormat.NegativeInvariantFormatLiterals)) - { - match = true; - positive = false; - } - } - - if (loc) - { - if (!match && raw.FullHMMatch(raw.PositiveLocalized)) - { - match = true; - positive = true; - } - - if (!match && raw.FullHMMatch(raw.NegativeLocalized)) - { - match = true; - positive = false; - } - } - - if (match) - { - long ticks; - var zero = new TimeSpanToken(0); - - if (!TryTimeToTicks(positive, zero, raw._numbers0, raw._numbers1, zero, zero, out ticks)) - { - return result.SetOverflowFailure(); - } - - if (!positive) - { - ticks = -ticks; - if (ticks > 0) - { - return result.SetOverflowFailure(); - } - } - - result.parsedTimeSpan = new TimeSpan(ticks); - return true; - } - - return result.SetBadTimeSpanFailure(); - } - - /// <summary>Validate the 1-number "Days" terminal case.</summary> - private static bool ProcessTerminal_D(ref TimeSpanRawInfo raw, TimeSpanStandardStyles style, ref TimeSpanResult result) - { - if (raw._sepCount != 2 || (style & TimeSpanStandardStyles.RequireFull) != 0) - { - return result.SetBadTimeSpanFailure(); - } - Debug.Assert(raw._numCount == 1); - - bool inv = ((style & TimeSpanStandardStyles.Invariant) != 0); - bool loc = ((style & TimeSpanStandardStyles.Localized) != 0); - - bool positive = false, match = false; - - if (inv) - { - if (raw.FullDMatch(TimeSpanFormat.PositiveInvariantFormatLiterals)) - { - match = true; - positive = true; - } - - if (!match && raw.FullDMatch(TimeSpanFormat.NegativeInvariantFormatLiterals)) - { - match = true; - positive = false; - } - } - - if (loc) - { - if (!match && raw.FullDMatch(raw.PositiveLocalized)) - { - match = true; - positive = true; - } - - if (!match && raw.FullDMatch(raw.NegativeLocalized)) - { - match = true; - positive = false; - } - } - - if (match) - { - long ticks; - var zero = new TimeSpanToken(0); - - if (!TryTimeToTicks(positive, raw._numbers0, zero, zero, zero, zero, out ticks)) - { - return result.SetOverflowFailure(); - } - - if (!positive) - { - ticks = -ticks; - if (ticks > 0) - { - return result.SetOverflowFailure(); - } - } - - result.parsedTimeSpan = new TimeSpan(ticks); - return true; - } - - return result.SetBadTimeSpanFailure(); - } - - /// <summary>Common private ParseExact method called by both ParseExact and TryParseExact.</summary> - private static bool TryParseExactTimeSpan(ReadOnlySpan<char> input, ReadOnlySpan<char> format, IFormatProvider? formatProvider, TimeSpanStyles styles, ref TimeSpanResult result) - { - if (format.Length == 0) - { - return result.SetBadFormatSpecifierFailure(); - } - - if (format.Length == 1) - { - switch (format[0]) - { - case 'c': - case 't': - case 'T': - return TryParseTimeSpanConstant(input, ref result); // fast path for legacy style TimeSpan formats. - - case 'g': - return TryParseTimeSpan(input, TimeSpanStandardStyles.Localized, formatProvider, ref result); - - case 'G': - return TryParseTimeSpan(input, TimeSpanStandardStyles.Localized | TimeSpanStandardStyles.RequireFull, formatProvider, ref result); - - default: - return result.SetBadFormatSpecifierFailure(format[0]); - } - } - - return TryParseByFormat(input, format, styles, ref result); - } - - /// <summary>Parse the TimeSpan instance using the specified format. Used by TryParseExactTimeSpan.</summary> - private static bool TryParseByFormat(ReadOnlySpan<char> input, ReadOnlySpan<char> format, TimeSpanStyles styles, ref TimeSpanResult result) - { - bool seenDD = false; // already processed days? - bool seenHH = false; // already processed hours? - bool seenMM = false; // already processed minutes? - bool seenSS = false; // already processed seconds? - bool seenFF = false; // already processed fraction? - - int dd = 0; // parsed days - int hh = 0; // parsed hours - int mm = 0; // parsed minutes - int ss = 0; // parsed seconds - int leadingZeroes = 0; // number of leading zeroes in the parsed fraction - int ff = 0; // parsed fraction - int i = 0; // format string position - int tokenLen; // length of current format token, used to update index 'i' - - var tokenizer = new TimeSpanTokenizer(input, -1); - - while (i < format.Length) - { - char ch = format[i]; - int nextFormatChar; - switch (ch) - { - case 'h': - tokenLen = DateTimeFormat.ParseRepeatPattern(format, i, ch); - if (tokenLen > 2 || seenHH || !ParseExactDigits(ref tokenizer, tokenLen, out hh)) - { - return result.SetInvalidStringFailure(); - } - seenHH = true; - break; - - case 'm': - tokenLen = DateTimeFormat.ParseRepeatPattern(format, i, ch); - if (tokenLen > 2 || seenMM || !ParseExactDigits(ref tokenizer, tokenLen, out mm)) - { - return result.SetInvalidStringFailure(); - } - seenMM = true; - break; - - case 's': - tokenLen = DateTimeFormat.ParseRepeatPattern(format, i, ch); - if (tokenLen > 2 || seenSS || !ParseExactDigits(ref tokenizer, tokenLen, out ss)) - { - return result.SetInvalidStringFailure(); - } - seenSS = true; - break; - - case 'f': - tokenLen = DateTimeFormat.ParseRepeatPattern(format, i, ch); - if (tokenLen > DateTimeFormat.MaxSecondsFractionDigits || seenFF || !ParseExactDigits(ref tokenizer, tokenLen, tokenLen, out leadingZeroes, out ff)) - { - return result.SetInvalidStringFailure(); - } - seenFF = true; - break; - - case 'F': - tokenLen = DateTimeFormat.ParseRepeatPattern(format, i, ch); - if (tokenLen > DateTimeFormat.MaxSecondsFractionDigits || seenFF) - { - return result.SetInvalidStringFailure(); - } - ParseExactDigits(ref tokenizer, tokenLen, tokenLen, out leadingZeroes, out ff); - seenFF = true; - break; - - case 'd': - tokenLen = DateTimeFormat.ParseRepeatPattern(format, i, ch); - if (tokenLen > 8 || seenDD || !ParseExactDigits(ref tokenizer, (tokenLen < 2) ? 1 : tokenLen, (tokenLen < 2) ? 8 : tokenLen, out _, out dd)) - { - return result.SetInvalidStringFailure(); - } - seenDD = true; - break; - - case '\'': - case '\"': - StringBuilder enquotedString = StringBuilderCache.Acquire(); - if (!DateTimeParse.TryParseQuoteString(format, i, enquotedString, out tokenLen)) - { - StringBuilderCache.Release(enquotedString); - return result.SetBadQuoteFailure(ch); - } - if (!ParseExactLiteral(ref tokenizer, enquotedString)) - { - StringBuilderCache.Release(enquotedString); - return result.SetInvalidStringFailure(); - } - StringBuilderCache.Release(enquotedString); - break; - - case '%': - // Optional format character. - // For example, format string "%d" will print day - // Most of the cases, "%" can be ignored. - nextFormatChar = DateTimeFormat.ParseNextChar(format, i); - - // nextFormatChar will be -1 if we already reach the end of the format string. - // Besides, we will not allow "%%" appear in the pattern. - if (nextFormatChar >= 0 && nextFormatChar != '%') - { - tokenLen = 1; // skip the '%' and process the format character - break; - } - else - { - // This means that '%' is at the end of the format string or - // "%%" appears in the format string. - return result.SetInvalidStringFailure(); - } - - case '\\': - // Escaped character. Can be used to insert character into the format string. - // For example, "\d" will insert the character 'd' into the string. - // - nextFormatChar = DateTimeFormat.ParseNextChar(format, i); - if (nextFormatChar >= 0 && tokenizer.NextChar == (char)nextFormatChar) - { - tokenLen = 2; - } - else - { - // This means that '\' is at the end of the format string or the literal match failed. - return result.SetInvalidStringFailure(); - } - break; - - default: - return result.SetInvalidStringFailure(); - } - - i += tokenLen; - } - - - if (!tokenizer.EOL) - { - // the custom format didn't consume the entire input - return result.SetBadTimeSpanFailure(); - } - - bool positive = (styles & TimeSpanStyles.AssumeNegative) == 0; - if (TryTimeToTicks(positive, new TimeSpanToken(dd), - new TimeSpanToken(hh), - new TimeSpanToken(mm), - new TimeSpanToken(ss), - new TimeSpanToken(ff, leadingZeroes), - out long ticks)) - { - if (!positive) - { - ticks = -ticks; - } - - result.parsedTimeSpan = new TimeSpan(ticks); - return true; - } - else - { - return result.SetOverflowFailure(); - } - } - - private static bool ParseExactDigits(ref TimeSpanTokenizer tokenizer, int minDigitLength, out int result) - { - int maxDigitLength = (minDigitLength == 1) ? 2 : minDigitLength; - return ParseExactDigits(ref tokenizer, minDigitLength, maxDigitLength, out _, out result); - } - - private static bool ParseExactDigits(ref TimeSpanTokenizer tokenizer, int minDigitLength, int maxDigitLength, out int zeroes, out int result) - { - int tmpResult = 0, tmpZeroes = 0; - - int tokenLength = 0; - while (tokenLength < maxDigitLength) - { - char ch = tokenizer.NextChar; - if (ch < '0' || ch > '9') - { - tokenizer.BackOne(); - break; - } - - tmpResult = tmpResult * 10 + (ch - '0'); - if (tmpResult == 0) tmpZeroes++; - tokenLength++; - } - - zeroes = tmpZeroes; - result = tmpResult; - return tokenLength >= minDigitLength; - } - - private static bool ParseExactLiteral(ref TimeSpanTokenizer tokenizer, StringBuilder enquotedString) - { - for (int i = 0; i < enquotedString.Length; i++) - { - if (enquotedString[i] != tokenizer.NextChar) - { - return false; - } - } - - return true; - } - - /// <summary> - /// Parses the "c" (constant) format. This code is 100% identical to the non-globalized v1.0-v3.5 TimeSpan.Parse() routine - /// and exists for performance/appcompat with legacy callers who cannot move onto the globalized Parse overloads. - /// </summary> - private static bool TryParseTimeSpanConstant(ReadOnlySpan<char> input, ref TimeSpanResult result) => - default(StringParser).TryParse(input, ref result); - - private ref struct StringParser - { - private ReadOnlySpan<char> _str; - private char _ch; - private int _pos; - private int _len; - - internal void NextChar() - { - if (_pos < _len) - { - _pos++; - } - - _ch = _pos < _len ? - _str[_pos] : - (char)0; - } - - internal char NextNonDigit() - { - int i = _pos; - while (i < _len) - { - char ch = _str[i]; - if (ch < '0' || ch > '9') return ch; - i++; - } - - return (char)0; - } - - internal bool TryParse(ReadOnlySpan<char> input, ref TimeSpanResult result) - { - result.parsedTimeSpan = default; - - _str = input; - _len = input.Length; - _pos = -1; - NextChar(); - SkipBlanks(); - - bool negative = false; - if (_ch == '-') - { - negative = true; - NextChar(); - } - - long time; - if (NextNonDigit() == ':') - { - if (!ParseTime(out time, ref result)) - { - return false; - } - } - else - { - int days; - if (!ParseInt((int)(0x7FFFFFFFFFFFFFFFL / TimeSpan.TicksPerDay), out days, ref result)) - { - return false; - } - - time = days * TimeSpan.TicksPerDay; - - if (_ch == '.') - { - NextChar(); - long remainingTime; - if (!ParseTime(out remainingTime, ref result)) - { - return false; - } - time += remainingTime; - } - } - - if (negative) - { - time = -time; - // Allow -0 as well - if (time > 0) - { - return result.SetOverflowFailure(); - } - } - else - { - if (time < 0) - { - return result.SetOverflowFailure(); - } - } - - SkipBlanks(); - - if (_pos < _len) - { - return result.SetBadTimeSpanFailure(); - } - - result.parsedTimeSpan = new TimeSpan(time); - return true; - } - - internal bool ParseInt(int max, out int i, ref TimeSpanResult result) - { - i = 0; - int p = _pos; - while (_ch >= '0' && _ch <= '9') - { - if ((i & 0xF0000000) != 0) - { - return result.SetOverflowFailure(); - } - - i = i * 10 + _ch - '0'; - if (i < 0) - { - return result.SetOverflowFailure(); - } - - NextChar(); - } - - if (p == _pos) - { - return result.SetBadTimeSpanFailure(); - } - - if (i > max) - { - return result.SetOverflowFailure(); - } - - return true; - } - - internal bool ParseTime(out long time, ref TimeSpanResult result) - { - time = 0; - int unit; - - if (!ParseInt(23, out unit, ref result)) - { - return false; - } - - time = unit * TimeSpan.TicksPerHour; - if (_ch != ':') - { - return result.SetBadTimeSpanFailure(); - } - - NextChar(); - - if (!ParseInt(59, out unit, ref result)) - { - return false; - } - - time += unit * TimeSpan.TicksPerMinute; - - if (_ch == ':') - { - NextChar(); - - // allow seconds with the leading zero - if (_ch != '.') - { - if (!ParseInt(59, out unit, ref result)) - { - return false; - } - time += unit * TimeSpan.TicksPerSecond; - } - - if (_ch == '.') - { - NextChar(); - int f = (int)TimeSpan.TicksPerSecond; - while (f > 1 && _ch >= '0' && _ch <= '9') - { - f /= 10; - time += (_ch - '0') * f; - NextChar(); - } - } - } - - return true; - } - - internal void SkipBlanks() - { - while (_ch == ' ' || _ch == '\t') NextChar(); - } - } - - /// <summary>Common private ParseExactMultiple method called by both ParseExactMultiple and TryParseExactMultiple.</summary> - private static bool TryParseExactMultipleTimeSpan(ReadOnlySpan<char> input, string[] formats, IFormatProvider? formatProvider, TimeSpanStyles styles, ref TimeSpanResult result) - { - if (formats == null) - { - return result.SetArgumentNullFailure(nameof(formats)); - } - - if (input.Length == 0) - { - return result.SetBadTimeSpanFailure(); - } - - if (formats.Length == 0) - { - return result.SetNoFormatSpecifierFailure(); - } - - // Do a loop through the provided formats and see if we can parse succesfully in - // one of the formats. - for (int i = 0; i < formats.Length; i++) - { - if (formats[i] == null || formats[i].Length == 0) - { - return result.SetBadFormatSpecifierFailure(); - } - - // Create a new non-throwing result each time to ensure the runs are independent. - TimeSpanResult innerResult = new TimeSpanResult(throwOnFailure: false, originalTimeSpanString: input); - - if (TryParseExactTimeSpan(input, formats[i], formatProvider, styles, ref innerResult)) - { - result.parsedTimeSpan = innerResult.parsedTimeSpan; - return true; - } - } - - return result.SetBadTimeSpanFailure(); - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/TimeSpanStyles.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/TimeSpanStyles.cs deleted file mode 100644 index 68a47bcbe60..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/TimeSpanStyles.cs +++ /dev/null @@ -1,13 +0,0 @@ -// 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 -{ - [Flags] - public enum TimeSpanStyles - { - None = 0x00000000, - AssumeNegative = 0x00000001, - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/UmAlQuraCalendar.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/UmAlQuraCalendar.cs deleted file mode 100644 index ae5820841e4..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/UmAlQuraCalendar.cs +++ /dev/null @@ -1,653 +0,0 @@ -// 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; - -namespace System.Globalization -{ - /// <remarks> - /// Calendar support range: - /// Calendar Minimum Maximum - /// ========== ========== ========== - /// Gregorian 1900/04/30 2077/05/13 - /// UmAlQura 1318/01/01 1500/12/30 - /// </remarks> - public partial class UmAlQuraCalendar : Calendar - { - private const int MinCalendarYear = 1318; - private const int MaxCalendarYear = 1500; - - private struct DateMapping - { - internal DateMapping(int MonthsLengthFlags, int GYear, int GMonth, int GDay) - { - HijriMonthsLengthFlags = MonthsLengthFlags; - GregorianDate = new DateTime(GYear, GMonth, GDay); - } - - internal int HijriMonthsLengthFlags; - internal DateTime GregorianDate; - } - - private static readonly DateMapping[] s_hijriYearInfo = InitDateMapping(); - - private static DateMapping[] InitDateMapping() - { - short[] rawData = new short[] - { - // These data are taken from Tables/Excel/UmAlQura.xls please make sure that the two places are in sync - /* DaysPerM GY GM GD D1 D2 D3 D4 D5 D6 D7 D8 D9 D10 D11 D12 - 1318*/0x02EA, 1900, 4, 30, /* 0 1 0 1 0 1 1 1 0 1 0 0 4/30/1900 - 1319*/0x06E9, 1901, 4, 19, /* 1 0 0 1 0 1 1 1 0 1 1 0 4/19/1901 - 1320*/0x0ED2, 1902, 4, 9, /* 0 1 0 0 1 0 1 1 0 1 1 1 4/9/1902 - 1321*/0x0EA4, 1903, 3, 30, /* 0 0 1 0 0 1 0 1 0 1 1 1 3/30/1903 - 1322*/0x0D4A, 1904, 3, 18, /* 0 1 0 1 0 0 1 0 1 0 1 1 3/18/1904 - 1323*/0x0A96, 1905, 3, 7, /* 0 1 1 0 1 0 0 1 0 1 0 1 3/7/1905 - 1324*/0x0536, 1906, 2, 24, /* 0 1 1 0 1 1 0 0 1 0 1 0 2/24/1906 - 1325*/0x0AB5, 1907, 2, 13, /* 1 0 1 0 1 1 0 1 0 1 0 1 2/13/1907 - 1326*/0x0DAA, 1908, 2, 3, /* 0 1 0 1 0 1 0 1 1 0 1 1 2/3/1908 - 1327*/0x0BA4, 1909, 1, 23, /* 0 0 1 0 0 1 0 1 1 1 0 1 1/23/1909 - 1328*/0x0B49, 1910, 1, 12, /* 1 0 0 1 0 0 1 0 1 1 0 1 1/12/1910 - 1329*/0x0A93, 1911, 1, 1, /* 1 1 0 0 1 0 0 1 0 1 0 1 1/1/1911 - 1330*/0x052B, 1911, 12, 21, /* 1 1 0 1 0 1 0 0 1 0 1 0 12/21/1911 - 1331*/0x0A57, 1912, 12, 9, /* 1 1 1 0 1 0 1 0 0 1 0 1 12/9/1912 - 1332*/0x04B6, 1913, 11, 29, /* 0 1 1 0 1 1 0 1 0 0 1 0 11/29/1913 - 1333*/0x0AB5, 1914, 11, 18, /* 1 0 1 0 1 1 0 1 0 1 0 1 11/18/1914 - 1334*/0x05AA, 1915, 11, 8, /* 0 1 0 1 0 1 0 1 1 0 1 0 11/8/1915 - 1335*/0x0D55, 1916, 10, 27, /* 1 0 1 0 1 0 1 0 1 0 1 1 10/27/1916 - 1336*/0x0D2A, 1917, 10, 17, /* 0 1 0 1 0 1 0 0 1 0 1 1 10/17/1917 - 1337*/0x0A56, 1918, 10, 6, /* 0 1 1 0 1 0 1 0 0 1 0 1 10/6/1918 - 1338*/0x04AE, 1919, 9, 25, /* 0 1 1 1 0 1 0 1 0 0 1 0 9/25/1919 - 1339*/0x095D, 1920, 9, 13, /* 1 0 1 1 1 0 1 0 1 0 0 1 9/13/1920 - 1340*/0x02EC, 1921, 9, 3, /* 0 0 1 1 0 1 1 1 0 1 0 0 9/3/1921 - 1341*/0x06D5, 1922, 8, 23, /* 1 0 1 0 1 0 1 1 0 1 1 0 8/23/1922 - 1342*/0x06AA, 1923, 8, 13, /* 0 1 0 1 0 1 0 1 0 1 1 0 8/13/1923 - 1343*/0x0555, 1924, 8, 1, /* 1 0 1 0 1 0 1 0 1 0 1 0 8/1/1924 - 1344*/0x04AB, 1925, 7, 21, /* 1 1 0 1 0 1 0 1 0 0 1 0 7/21/1925 - 1345*/0x095B, 1926, 7, 10, /* 1 1 0 1 1 0 1 0 1 0 0 1 7/10/1926 - 1346*/0x02BA, 1927, 6, 30, /* 0 1 0 1 1 1 0 1 0 1 0 0 6/30/1927 - 1347*/0x0575, 1928, 6, 18, /* 1 0 1 0 1 1 1 0 1 0 1 0 6/18/1928 - 1348*/0x0BB2, 1929, 6, 8, /* 0 1 0 0 1 1 0 1 1 1 0 1 6/8/1929 - 1349*/0x0764, 1930, 5, 29, /* 0 0 1 0 0 1 1 0 1 1 1 0 5/29/1930 - 1350*/0x0749, 1931, 5, 18, /* 1 0 0 1 0 0 1 0 1 1 1 0 5/18/1931 - 1351*/0x0655, 1932, 5, 6, /* 1 0 1 0 1 0 1 0 0 1 1 0 5/6/1932 - 1352*/0x02AB, 1933, 4, 25, /* 1 1 0 1 0 1 0 1 0 1 0 0 4/25/1933 - 1353*/0x055B, 1934, 4, 14, /* 1 1 0 1 1 0 1 0 1 0 1 0 4/14/1934 - 1354*/0x0ADA, 1935, 4, 4, /* 0 1 0 1 1 0 1 1 0 1 0 1 4/4/1935 - 1355*/0x06D4, 1936, 3, 24, /* 0 0 1 0 1 0 1 1 0 1 1 0 3/24/1936 - 1356*/0x0EC9, 1937, 3, 13, /* 1 0 0 1 0 0 1 1 0 1 1 1 3/13/1937 - 1357*/0x0D92, 1938, 3, 3, /* 0 1 0 0 1 0 0 1 1 0 1 1 3/3/1938 - 1358*/0x0D25, 1939, 2, 20, /* 1 0 1 0 0 1 0 0 1 0 1 1 2/20/1939 - 1359*/0x0A4D, 1940, 2, 9, /* 1 0 1 1 0 0 1 0 0 1 0 1 2/9/1940 - 1360*/0x02AD, 1941, 1, 28, /* 1 0 1 1 0 1 0 1 0 1 0 0 1/28/1941 - 1361*/0x056D, 1942, 1, 17, /* 1 0 1 1 0 1 1 0 1 0 1 0 1/17/1942 - 1362*/0x0B6A, 1943, 1, 7, /* 0 1 0 1 0 1 1 0 1 1 0 1 1/7/1943 - 1363*/0x0B52, 1943, 12, 28, /* 0 1 0 0 1 0 1 0 1 1 0 1 12/28/1943 - 1364*/0x0AA5, 1944, 12, 16, /* 1 0 1 0 0 1 0 1 0 1 0 1 12/16/1944 - 1365*/0x0A4B, 1945, 12, 5, /* 1 1 0 1 0 0 1 0 0 1 0 1 12/5/1945 - 1366*/0x0497, 1946, 11, 24, /* 1 1 1 0 1 0 0 1 0 0 1 0 11/24/1946 - 1367*/0x0937, 1947, 11, 13, /* 1 1 1 0 1 1 0 0 1 0 0 1 11/13/1947 - 1368*/0x02B6, 1948, 11, 2, /* 0 1 1 0 1 1 0 1 0 1 0 0 11/2/1948 - 1369*/0x0575, 1949, 10, 22, /* 1 0 1 0 1 1 1 0 1 0 1 0 10/22/1949 - 1370*/0x0D6A, 1950, 10, 12, /* 0 1 0 1 0 1 1 0 1 0 1 1 10/12/1950 - 1371*/0x0D52, 1951, 10, 2, /* 0 1 0 0 1 0 1 0 1 0 1 1 10/2/1951 - 1372*/0x0A96, 1952, 9, 20, /* 0 1 1 0 1 0 0 1 0 1 0 1 9/20/1952 - 1373*/0x092D, 1953, 9, 9, /* 1 0 1 1 0 1 0 0 1 0 0 1 9/9/1953 - 1374*/0x025D, 1954, 8, 29, /* 1 0 1 1 1 0 1 0 0 1 0 0 8/29/1954 - 1375*/0x04DD, 1955, 8, 18, /* 1 0 1 1 1 0 1 1 0 0 1 0 8/18/1955 - 1376*/0x0ADA, 1956, 8, 7, /* 0 1 0 1 1 0 1 1 0 1 0 1 8/7/1956 - 1377*/0x05D4, 1957, 7, 28, /* 0 0 1 0 1 0 1 1 1 0 1 0 7/28/1957 - 1378*/0x0DA9, 1958, 7, 17, /* 1 0 0 1 0 1 0 1 1 0 1 1 7/17/1958 - 1379*/0x0D52, 1959, 7, 7, /* 0 1 0 0 1 0 1 0 1 0 1 1 7/7/1959 - 1380*/0x0AAA, 1960, 6, 25, /* 0 1 0 1 0 1 0 1 0 1 0 1 6/25/1960 - 1381*/0x04D6, 1961, 6, 14, /* 0 1 1 0 1 0 1 1 0 0 1 0 6/14/1961 - 1382*/0x09B6, 1962, 6, 3, /* 0 1 1 0 1 1 0 1 1 0 0 1 6/3/1962 - 1383*/0x0374, 1963, 5, 24, /* 0 0 1 0 1 1 1 0 1 1 0 0 5/24/1963 - 1384*/0x0769, 1964, 5, 12, /* 1 0 0 1 0 1 1 0 1 1 1 0 5/12/1964 - 1385*/0x0752, 1965, 5, 2, /* 0 1 0 0 1 0 1 0 1 1 1 0 5/2/1965 - 1386*/0x06A5, 1966, 4, 21, /* 1 0 1 0 0 1 0 1 0 1 1 0 4/21/1966 - 1387*/0x054B, 1967, 4, 10, /* 1 1 0 1 0 0 1 0 1 0 1 0 4/10/1967 - 1388*/0x0AAB, 1968, 3, 29, /* 1 1 0 1 0 1 0 1 0 1 0 1 3/29/1968 - 1389*/0x055A, 1969, 3, 19, /* 0 1 0 1 1 0 1 0 1 0 1 0 3/19/1969 - 1390*/0x0AD5, 1970, 3, 8, /* 1 0 1 0 1 0 1 1 0 1 0 1 3/8/1970 - 1391*/0x0DD2, 1971, 2, 26, /* 0 1 0 0 1 0 1 1 1 0 1 1 2/26/1971 - 1392*/0x0DA4, 1972, 2, 16, /* 0 0 1 0 0 1 0 1 1 0 1 1 2/16/1972 - 1393*/0x0D49, 1973, 2, 4, /* 1 0 0 1 0 0 1 0 1 0 1 1 2/4/1973 - 1394*/0x0A95, 1974, 1, 24, /* 1 0 1 0 1 0 0 1 0 1 0 1 1/24/1974 - 1395*/0x052D, 1975, 1, 13, /* 1 0 1 1 0 1 0 0 1 0 1 0 1/13/1975 - 1396*/0x0A5D, 1976, 1, 2, /* 1 0 1 1 1 0 1 0 0 1 0 1 1/2/1976 - 1397*/0x055A, 1976, 12, 22, /* 0 1 0 1 1 0 1 0 1 0 1 0 12/22/1976 - 1398*/0x0AD5, 1977, 12, 11, /* 1 0 1 0 1 0 1 1 0 1 0 1 12/11/1977 - 1399*/0x06AA, 1978, 12, 1, /* 0 1 0 1 0 1 0 1 0 1 1 0 12/1/1978 - 1400*/0x0695, 1979, 11, 20, /* 1 0 1 0 1 0 0 1 0 1 1 0 11/20/1979 - 1401*/0x052B, 1980, 11, 8, /* 1 1 0 1 0 1 0 0 1 0 1 0 11/8/1980 - 1402*/0x0A57, 1981, 10, 28, /* 1 1 1 0 1 0 1 0 0 1 0 1 10/28/1981 - 1403*/0x04AE, 1982, 10, 18, /* 0 1 1 1 0 1 0 1 0 0 1 0 10/18/1982 - 1404*/0x0976, 1983, 10, 7, /* 0 1 1 0 1 1 1 0 1 0 0 1 10/7/1983 - 1405*/0x056C, 1984, 9, 26, /* 0 0 1 1 0 1 1 0 1 0 1 0 9/26/1984 - 1406*/0x0B55, 1985, 9, 15, /* 1 0 1 0 1 0 1 0 1 1 0 1 9/15/1985 - 1407*/0x0AAA, 1986, 9, 5, /* 0 1 0 1 0 1 0 1 0 1 0 1 9/5/1986 - 1408*/0x0A55, 1987, 8, 25, /* 1 0 1 0 1 0 1 0 0 1 0 1 8/25/1987 - 1409*/0x04AD, 1988, 8, 13, /* 1 0 1 1 0 1 0 1 0 0 1 0 8/13/1988 - 1410*/0x095D, 1989, 8, 2, /* 1 0 1 1 1 0 1 0 1 0 0 1 8/2/1989 - 1411*/0x02DA, 1990, 7, 23, /* 0 1 0 1 1 0 1 1 0 1 0 0 7/23/1990 - 1412*/0x05D9, 1991, 7, 12, /* 1 0 0 1 1 0 1 1 1 0 1 0 7/12/1991 - 1413*/0x0DB2, 1992, 7, 1, /* 0 1 0 0 1 1 0 1 1 0 1 1 7/1/1992 - 1414*/0x0BA4, 1993, 6, 21, /* 0 0 1 0 0 1 0 1 1 1 0 1 6/21/1993 - 1415*/0x0B4A, 1994, 6, 10, /* 0 1 0 1 0 0 1 0 1 1 0 1 6/10/1994 - 1416*/0x0A55, 1995, 5, 30, /* 1 0 1 0 1 0 1 0 0 1 0 1 5/30/1995 - 1417*/0x02B5, 1996, 5, 18, /* 1 0 1 0 1 1 0 1 0 1 0 0 5/18/1996 - 1418*/0x0575, 1997, 5, 7, /* 1 0 1 0 1 1 1 0 1 0 1 0 5/7/1997 - 1419*/0x0B6A, 1998, 4, 27, /* 0 1 0 1 0 1 1 0 1 1 0 1 4/27/1998 - 1420*/0x0BD2, 1999, 4, 17, /* 0 1 0 0 1 0 1 1 1 1 0 1 4/17/1999 - 1421*/0x0BC4, 2000, 4, 6, /* 0 0 1 0 0 0 1 1 1 1 0 1 4/6/2000 - 1422*/0x0B89, 2001, 3, 26, /* 1 0 0 1 0 0 0 1 1 1 0 1 3/26/2001 - 1423*/0x0A95, 2002, 3, 15, /* 1 0 1 0 1 0 0 1 0 1 0 1 3/15/2002 - 1424*/0x052D, 2003, 3, 4, /* 1 0 1 1 0 1 0 0 1 0 1 0 3/4/2003 - 1425*/0x05AD, 2004, 2, 21, /* 1 0 1 1 0 1 0 1 1 0 1 0 2/21/2004 - 1426*/0x0B6A, 2005, 2, 10, /* 0 1 0 1 0 1 1 0 1 1 0 1 2/10/2005 - 1427*/0x06D4, 2006, 1, 31, /* 0 0 1 0 1 0 1 1 0 1 1 0 1/31/2006 - 1428*/0x0DC9, 2007, 1, 20, /* 1 0 0 1 0 0 1 1 1 0 1 1 1/20/2007 - 1429*/0x0D92, 2008, 1, 10, /* 0 1 0 0 1 0 0 1 1 0 1 1 1/10/2008 - 1430*/0x0AA6, 2008, 12, 29, /* 0 1 1 0 0 1 0 1 0 1 0 1 12/29/2008 - 1431*/0x0956, 2009, 12, 18, /* 0 1 1 0 1 0 1 0 1 0 0 1 12/18/2009 - 1432*/0x02AE, 2010, 12, 7, /* 0 1 1 1 0 1 0 1 0 1 0 0 12/7/2010 - 1433*/0x056D, 2011, 11, 26, /* 1 0 1 1 0 1 1 0 1 0 1 0 11/26/2011 - 1434*/0x036A, 2012, 11, 15, /* 0 1 0 1 0 1 1 0 1 1 0 0 11/15/2012 - 1435*/0x0B55, 2013, 11, 4, /* 1 0 1 0 1 0 1 0 1 1 0 1 11/4/2013 - 1436*/0x0AAA, 2014, 10, 25, /* 0 1 0 1 0 1 0 1 0 1 0 1 10/25/2014 - 1437*/0x094D, 2015, 10, 14, /* 1 0 1 1 0 0 1 0 1 0 0 1 10/14/2015 - 1438*/0x049D, 2016, 10, 2, /* 1 0 1 1 1 0 0 1 0 0 1 0 10/2/2016 - 1439*/0x095D, 2017, 9, 21, /* 1 0 1 1 1 0 1 0 1 0 0 1 9/21/2017 - 1440*/0x02BA, 2018, 9, 11, /* 0 1 0 1 1 1 0 1 0 1 0 0 9/11/2018 - 1441*/0x05B5, 2019, 8, 31, /* 1 0 1 0 1 1 0 1 1 0 1 0 8/31/2019 - 1442*/0x05AA, 2020, 8, 20, /* 0 1 0 1 0 1 0 1 1 0 1 0 8/20/2020 - 1443*/0x0D55, 2021, 8, 9, /* 1 0 1 0 1 0 1 0 1 0 1 1 8/9/2021 - 1444*/0x0A9A, 2022, 7, 30, /* 0 1 0 1 1 0 0 1 0 1 0 1 7/30/2022 - 1445*/0x092E, 2023, 7, 19, /* 0 1 1 1 0 1 0 0 1 0 0 1 7/19/2023 - 1446*/0x026E, 2024, 7, 7, /* 0 1 1 1 0 1 1 0 0 1 0 0 7/7/2024 - 1447*/0x055D, 2025, 6, 26, /* 1 0 1 1 1 0 1 0 1 0 1 0 6/26/2025 - 1448*/0x0ADA, 2026, 6, 16, /* 0 1 0 1 1 0 1 1 0 1 0 1 6/16/2026 - 1449*/0x06D4, 2027, 6, 6, /* 0 0 1 0 1 0 1 1 0 1 1 0 6/6/2027 - 1450*/0x06A5, 2028, 5, 25, /* 1 0 1 0 0 1 0 1 0 1 1 0 5/25/2028 - 1451*/0x054B, 2029, 5, 14, /* 1 1 0 1 0 0 1 0 1 0 1 0 5/14/2029 - 1452*/0x0A97, 2030, 5, 3, /* 1 1 1 0 1 0 0 1 0 1 0 1 5/3/2030 - 1453*/0x054E, 2031, 4, 23, /* 0 1 1 1 0 0 1 0 1 0 1 0 4/23/2031 - 1454*/0x0AAE, 2032, 4, 11, /* 0 1 1 1 0 1 0 1 0 1 0 1 4/11/2032 - 1455*/0x05AC, 2033, 4, 1, /* 0 0 1 1 0 1 0 1 1 0 1 0 4/1/2033 - 1456*/0x0BA9, 2034, 3, 21, /* 1 0 0 1 0 1 0 1 1 1 0 1 3/21/2034 - 1457*/0x0D92, 2035, 3, 11, /* 0 1 0 0 1 0 0 1 1 0 1 1 3/11/2035 - 1458*/0x0B25, 2036, 2, 28, /* 1 0 1 0 0 1 0 0 1 1 0 1 2/28/2036 - 1459*/0x064B, 2037, 2, 16, /* 1 1 0 1 0 0 1 0 0 1 1 0 2/16/2037 - 1460*/0x0CAB, 2038, 2, 5, /* 1 1 0 1 0 1 0 1 0 0 1 1 2/5/2038 - 1461*/0x055A, 2039, 1, 26, /* 0 1 0 1 1 0 1 0 1 0 1 0 1/26/2039 - 1462*/0x0B55, 2040, 1, 15, /* 1 0 1 0 1 0 1 0 1 1 0 1 1/15/2040 - 1463*/0x06D2, 2041, 1, 4, /* 0 1 0 0 1 0 1 1 0 1 1 0 1/4/2041 - 1464*/0x0EA5, 2041, 12, 24, /* 1 0 1 0 0 1 0 1 0 1 1 1 12/24/2041 - 1465*/0x0E4A, 2042, 12, 14, /* 0 1 0 1 0 0 1 0 0 1 1 1 12/14/2042 - 1466*/0x0A95, 2043, 12, 3, /* 1 0 1 0 1 0 0 1 0 1 0 1 12/3/2043 - 1467*/0x052D, 2044, 11, 21, /* 1 0 1 1 0 1 0 0 1 0 1 0 11/21/2044 - 1468*/0x0AAD, 2045, 11, 10, /* 1 0 1 1 0 1 0 1 0 1 0 1 11/10/2045 - 1469*/0x036C, 2046, 10, 31, /* 0 0 1 1 0 1 1 0 1 1 0 0 10/31/2046 - 1470*/0x0759, 2047, 10, 20, /* 1 0 0 1 1 0 1 0 1 1 1 0 10/20/2047 - 1471*/0x06D2, 2048, 10, 9, /* 0 1 0 0 1 0 1 1 0 1 1 0 10/9/2048 - 1472*/0x0695, 2049, 9, 28, /* 1 0 1 0 1 0 0 1 0 1 1 0 9/28/2049 - 1473*/0x052D, 2050, 9, 17, /* 1 0 1 1 0 1 0 0 1 0 1 0 9/17/2050 - 1474*/0x0A5B, 2051, 9, 6, /* 1 1 0 1 1 0 1 0 0 1 0 1 9/6/2051 - 1475*/0x04BA, 2052, 8, 26, /* 0 1 0 1 1 1 0 1 0 0 1 0 8/26/2052 - 1476*/0x09BA, 2053, 8, 15, /* 0 1 0 1 1 1 0 1 1 0 0 1 8/15/2053 - 1477*/0x03B4, 2054, 8, 5, /* 0 0 1 0 1 1 0 1 1 1 0 0 8/5/2054 - 1478*/0x0B69, 2055, 7, 25, /* 1 0 0 1 0 1 1 0 1 1 0 1 7/25/2055 - 1479*/0x0B52, 2056, 7, 14, /* 0 1 0 0 1 0 1 0 1 1 0 1 7/14/2056 - 1480*/0x0AA6, 2057, 7, 3, /* 0 1 1 0 0 1 0 1 0 1 0 1 7/3/2057 - 1481*/0x04B6, 2058, 6, 22, /* 0 1 1 0 1 1 0 1 0 0 1 0 6/22/2058 - 1482*/0x096D, 2059, 6, 11, /* 1 0 1 1 0 1 1 0 1 0 0 1 6/11/2059 - 1483*/0x02EC, 2060, 5, 31, /* 0 0 1 1 0 1 1 1 0 1 0 0 5/31/2060 - 1484*/0x06D9, 2061, 5, 20, /* 1 0 0 1 1 0 1 1 0 1 1 0 5/20/2061 - 1485*/0x0EB2, 2062, 5, 10, /* 0 1 0 0 1 1 0 1 0 1 1 1 5/10/2062 - 1486*/0x0D54, 2063, 4, 30, /* 0 0 1 0 1 0 1 0 1 0 1 1 4/30/2063 - 1487*/0x0D2A, 2064, 4, 18, /* 0 1 0 1 0 1 0 0 1 0 1 1 4/18/2064 - 1488*/0x0A56, 2065, 4, 7, /* 0 1 1 0 1 0 1 0 0 1 0 1 4/7/2065 - 1489*/0x04AE, 2066, 3, 27, /* 0 1 1 1 0 1 0 1 0 0 1 0 3/27/2066 - 1490*/0x096D, 2067, 3, 16, /* 1 0 1 1 0 1 1 0 1 0 0 1 3/16/2067 - 1491*/0x0D6A, 2068, 3, 5, /* 0 1 0 1 0 1 1 0 1 0 1 1 3/5/2068 - 1492*/0x0B54, 2069, 2, 23, /* 0 0 1 0 1 0 1 0 1 1 0 1 2/23/2069 - 1493*/0x0B29, 2070, 2, 12, /* 1 0 0 1 0 1 0 0 1 1 0 1 2/12/2070 - 1494*/0x0A93, 2071, 2, 1, /* 1 1 0 0 1 0 0 1 0 1 0 1 2/1/2071 - 1495*/0x052B, 2072, 1, 21, /* 1 1 0 1 0 1 0 0 1 0 1 0 1/21/2072 - 1496*/0x0A57, 2073, 1, 9, /* 1 1 1 0 1 0 1 0 0 1 0 1 1/9/2073 - 1497*/0x0536, 2073, 12, 30, /* 0 1 1 0 1 1 0 0 1 0 1 0 12/30/2073 - 1498*/0x0AB5, 2074, 12, 19, /* 1 0 1 0 1 1 0 1 0 1 0 1 12/19/2074 - 1499*/0x06AA, 2075, 12, 9, /* 0 1 0 1 0 1 0 1 0 1 1 0 12/9/2075 - 1500*/0x0E93, 2076, 11, 27, /* 1 1 0 0 1 0 0 1 0 1 1 1 11/27/2076 - 1501*/ 0, 2077, 11, 17, /* 0 0 0 0 0 0 0 0 0 0 0 0 11/17/2077 - */ }; - // Direct inline initialization of DateMapping array would produce a lot of code bloat. - - // We take advantage of C# compiler compiles inline initialization of primitive type array into very compact code. - // So we start with raw data stored in primitive type array, and initialize the DateMapping out of it - - DateMapping[] mapping = new DateMapping[rawData.Length / 4]; - for (int i = 0; i < mapping.Length; i++) - mapping[i] = new DateMapping(rawData[i * 4], rawData[i * 4 + 1], rawData[i * 4 + 2], rawData[i * 4 + 3]); - return mapping; - } - - public const int UmAlQuraEra = 1; - - private const int DatePartYear = 0; - private const int DatePartDayOfYear = 1; - private const int DatePartMonth = 2; - private const int DatePartDay = 3; - - private static readonly DateTime s_minDate = new DateTime(1900, 4, 30); - private static readonly DateTime s_maxDate = new DateTime((new DateTime(2077, 11, 16, 23, 59, 59, 999)).Ticks + 9999); - - public override DateTime MinSupportedDateTime => s_minDate; - - public override DateTime MaxSupportedDateTime => s_maxDate; - - public override CalendarAlgorithmType AlgorithmType => CalendarAlgorithmType.LunarCalendar; - - public UmAlQuraCalendar() - { - } - - internal override CalendarId BaseCalendarID => CalendarId.HIJRI; - - internal override CalendarId ID => CalendarId.UMALQURA; - - protected override int DaysInYearBeforeMinSupportedYear => - // HijriCalendar has same number of days as UmAlQuraCalendar for any given year - // HijriCalendar says year 1317 has 355 days. - 355; - - private static void ConvertHijriToGregorian(int HijriYear, int HijriMonth, int HijriDay, out int yg, out int mg, out int dg) - { - Debug.Assert((HijriYear >= MinCalendarYear) && (HijriYear <= MaxCalendarYear), "Hijri year is out of range."); - Debug.Assert(HijriMonth >= 1, "Hijri month is out of range."); - Debug.Assert(HijriDay >= 1, "Hijri day is out of range."); - int nDays = HijriDay - 1; - - int index = HijriYear - MinCalendarYear; - DateTime dt = s_hijriYearInfo[index].GregorianDate; - int b = s_hijriYearInfo[index].HijriMonthsLengthFlags; - - for (int m = 1; m < HijriMonth; m++) - { - // Add the months lengths before mh - nDays = nDays + 29 + (b & 1); - b >>= 1; - } - - dt = dt.AddDays(nDays); - dt.GetDatePart(out yg, out mg, out dg); - } - - private static long GetAbsoluteDateUmAlQura(int year, int month, int day) - { - ConvertHijriToGregorian(year, month, day, out int yg, out int mg, out int dg); - return GregorianCalendar.GetAbsoluteDate(yg, mg, dg); - } - - internal static void CheckTicksRange(long ticks) - { - if (ticks < s_minDate.Ticks || ticks > s_maxDate.Ticks) - { - throw new ArgumentOutOfRangeException( - "time", - ticks, - SR.Format( - CultureInfo.InvariantCulture, - SR.ArgumentOutOfRange_CalendarRange, - s_minDate, - s_maxDate)); - } - } - - internal static void CheckEraRange(int era) - { - if (era != CurrentEra && era != UmAlQuraEra) - { - throw new ArgumentOutOfRangeException(nameof(era), era, SR.ArgumentOutOfRange_InvalidEraValue); - } - } - - internal static void CheckYearRange(int year, int era) - { - CheckEraRange(era); - if (year < MinCalendarYear || year > MaxCalendarYear) - { - throw new ArgumentOutOfRangeException( - nameof(year), - year, - SR.Format(SR.ArgumentOutOfRange_Range, MinCalendarYear, MaxCalendarYear)); - } - } - - internal static void CheckYearMonthRange(int year, int month, int era) - { - CheckYearRange(year, era); - if (month < 1 || month > 12) - { - throw new ArgumentOutOfRangeException(nameof(month), month, SR.ArgumentOutOfRange_Month); - } - } - - private static void ConvertGregorianToHijri(DateTime time, out int HijriYear, out int HijriMonth, out int HijriDay) - { - Debug.Assert((time.Ticks >= s_minDate.Ticks) && (time.Ticks <= s_maxDate.Ticks), "Gregorian date is out of range."); - - // Find the index where we should start our search by quessing the Hijri year that we will be in HijriYearInfo. - // A Hijri year is 354 or 355 days. Use 355 days so that we will search from a lower index. - - int index = (int)((time.Ticks - s_minDate.Ticks) / Calendar.TicksPerDay) / 355; - do - { - } while (time.CompareTo(s_hijriYearInfo[++index].GregorianDate) > 0); // while greater - - if (time.CompareTo(s_hijriYearInfo[index].GregorianDate) != 0) - { - index--; - } - - TimeSpan ts = time.Subtract(s_hijriYearInfo[index].GregorianDate); - int yh1 = index + MinCalendarYear; - int mh1 = 1; - int dh1 = 1; - double nDays = ts.TotalDays; - int b = s_hijriYearInfo[index].HijriMonthsLengthFlags; - int daysPerThisMonth = 29 + (b & 1); - - while (nDays >= daysPerThisMonth) - { - nDays -= daysPerThisMonth; - b >>= 1; - daysPerThisMonth = 29 + (b & 1); - mh1++; - } - dh1 += (int)nDays; - - HijriDay = dh1; - HijriMonth = mh1; - HijriYear = yh1; - } - - /// <summary> - /// First, we get the absolute date (the number of days from January 1st, 1 A.C) for the given ticks. - /// Use the formula (((AbsoluteDate - 226894) * 33) / (33 * 365 + 8)) + 1, we can a rough value for the UmAlQura year. - /// In order to get the exact UmAlQura year, we compare the exact absolute date for UmAlQuraYear and (UmAlQuraYear + 1). - /// From here, we can get the correct UmAlQura year. - /// </summary> - private int GetDatePart(DateTime time, int part) - { - long ticks = time.Ticks; - CheckTicksRange(ticks); - - ConvertGregorianToHijri(time, out int UmAlQuraYear, out int UmAlQuraMonth, out int UmAlQuraDay); - - if (part == DatePartYear) - { - return UmAlQuraYear; - } - if (part == DatePartMonth) - { - return UmAlQuraMonth; - } - if (part == DatePartDay) - { - return UmAlQuraDay; - } - if (part == DatePartDayOfYear) - { - return (int)(GetAbsoluteDateUmAlQura(UmAlQuraYear, UmAlQuraMonth, UmAlQuraDay) - GetAbsoluteDateUmAlQura(UmAlQuraYear, 1, 1) + 1); - } - - // Incorrect part value. - throw new InvalidOperationException(SR.InvalidOperation_DateTimeParsing); - } - - public override DateTime AddMonths(DateTime time, int months) - { - if (months < -120000 || months > 120000) - { - throw new ArgumentOutOfRangeException( - nameof(months), - months, - SR.Format(SR.ArgumentOutOfRange_Range, -120000, 120000)); - } - - // Get the date in UmAlQura calendar. - int y = GetDatePart(time, DatePartYear); - int m = GetDatePart(time, DatePartMonth); - int d = GetDatePart(time, DatePartDay); - int i = m - 1 + months; - - if (i >= 0) - { - m = i % 12 + 1; - y += i / 12; - } - else - { - m = 12 + (i + 1) % 12; - y += (i - 11) / 12; - } - - if (d > 29) - { - int days = GetDaysInMonth(y, m); - if (d > days) - { - d = days; - } - } - - CheckYearRange(y, UmAlQuraEra); - DateTime dt = new DateTime(GetAbsoluteDateUmAlQura(y, m, d) * TicksPerDay + time.Ticks % TicksPerDay); - Calendar.CheckAddResult(dt.Ticks, MinSupportedDateTime, MaxSupportedDateTime); - return dt; - } - - public override DateTime AddYears(DateTime time, int years) - { - return AddMonths(time, years * 12); - } - - public override int GetDayOfMonth(DateTime time) - { - return GetDatePart(time, DatePartDay); - } - - public override DayOfWeek GetDayOfWeek(DateTime time) - { - return (DayOfWeek)((int)(time.Ticks / TicksPerDay + 1) % 7); - } - - public override int GetDayOfYear(DateTime time) - { - return GetDatePart(time, DatePartDayOfYear); - } - - public override int GetDaysInMonth(int year, int month, int era) - { - CheckYearMonthRange(year, month, era); - - if ((s_hijriYearInfo[year - MinCalendarYear].HijriMonthsLengthFlags & (1 << month - 1)) == 0) - { - return 29; - } - else - { - return 30; - } - } - - internal static int RealGetDaysInYear(int year) - { - int days = 0; - - Debug.Assert((year >= MinCalendarYear) && (year <= MaxCalendarYear), "Hijri year is out of range."); - - int b = s_hijriYearInfo[year - MinCalendarYear].HijriMonthsLengthFlags; - - for (int m = 1; m <= 12; m++) - { - days = days + 29 + (b & 1); /* Add the months lengths before mh */ - b >>= 1; - } - - Debug.Assert((days == 354) || (days == 355), "Hijri year has to be 354 or 355 days."); - return days; - } - - public override int GetDaysInYear(int year, int era) - { - CheckYearRange(year, era); - return RealGetDaysInYear(year); - } - - public override int GetEra(DateTime time) - { - CheckTicksRange(time.Ticks); - return UmAlQuraEra; - } - - public override int[] Eras => new int[] { UmAlQuraEra }; - - public override int GetMonth(DateTime time) - { - return GetDatePart(time, DatePartMonth); - } - - public override int GetMonthsInYear(int year, int era) - { - CheckYearRange(year, era); - return 12; - } - - public override int GetYear(DateTime time) - { - return GetDatePart(time, DatePartYear); - } - - public override bool IsLeapDay(int year, int month, int day, int era) - { - if (day >= 1 && day <= 29) - { - CheckYearMonthRange(year, month, era); - return false; - } - - // The year/month/era value checking is done in GetDaysInMonth(). - int daysInMonth = GetDaysInMonth(year, month, era); - if (day < 1 || day > daysInMonth) - { - throw new ArgumentOutOfRangeException( - nameof(day), - day, - SR.Format(SR.ArgumentOutOfRange_Day, daysInMonth, month)); - } - return false; - } - - public override int GetLeapMonth(int year, int era) - { - CheckYearRange(year, era); - return 0; - } - - public override bool IsLeapMonth(int year, int month, int era) - { - CheckYearMonthRange(year, month, era); - return false; - } - - public override bool IsLeapYear(int year, int era) - { - CheckYearRange(year, era); - return RealGetDaysInYear(year) == 355; - } - - public override DateTime ToDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int era) - { - if (day >= 1 && day <= 29) - { - CheckYearMonthRange(year, month, era); - goto DayInRang; - } - - // The year/month/era value checking is done in GetDaysInMonth(). - int daysInMonth = GetDaysInMonth(year, month, era); - - if (day < 1 || day > daysInMonth) - { - throw new ArgumentOutOfRangeException( - nameof(day), - day, - SR.Format(SR.ArgumentOutOfRange_Day, daysInMonth, month)); - } - DayInRang: - long lDate = GetAbsoluteDateUmAlQura(year, month, day); - if (lDate < 0) - { - throw new ArgumentOutOfRangeException(null, SR.ArgumentOutOfRange_BadYearMonthDay); - } - - return new DateTime(lDate * GregorianCalendar.TicksPerDay + TimeToTicks(hour, minute, second, millisecond)); - } - - private const int DefaultTwoDigitYearMax = 1451; - - public override int TwoDigitYearMax - { - get - { - if (_twoDigitYearMax == -1) - { - _twoDigitYearMax = GetSystemTwoDigitYearSetting(ID, DefaultTwoDigitYearMax); - } - - return _twoDigitYearMax; - } - set - { - if (value != 99 && (value < MinCalendarYear || value > MaxCalendarYear)) - { - throw new ArgumentOutOfRangeException( - nameof(value), - value, - SR.Format(SR.ArgumentOutOfRange_Range, MinCalendarYear, MaxCalendarYear)); - } - - VerifyWritable(); - // We allow year 99 to be set so that one can make ToFourDigitYearMax a no-op by setting TwoDigitYearMax to 99. - _twoDigitYearMax = value; - } - } - - public override int ToFourDigitYear(int year) - { - if (year < 0) - { - throw new ArgumentOutOfRangeException(nameof(year), year, SR.ArgumentOutOfRange_NeedNonNegNum); - } - - if (year < 100) - { - return base.ToFourDigitYear(year); - } - - if (year < MinCalendarYear || year > MaxCalendarYear) - { - throw new ArgumentOutOfRangeException( - nameof(year), - year, - SR.Format(SR.ArgumentOutOfRange_Range, MinCalendarYear, MaxCalendarYear)); - } - - return year; - } - } -} diff --git a/netcore/System.Private.CoreLib/shared/System/Globalization/UnicodeCategory.cs b/netcore/System.Private.CoreLib/shared/System/Globalization/UnicodeCategory.cs deleted file mode 100644 index f0ae1fdfd9d..00000000000 --- a/netcore/System.Private.CoreLib/shared/System/Globalization/UnicodeCategory.cs +++ /dev/null @@ -1,40 +0,0 @@ -// 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 enum UnicodeCategory - { - UppercaseLetter = 0, - LowercaseLetter = 1, - TitlecaseLetter = 2, - ModifierLetter = 3, - OtherLetter = 4, - NonSpacingMark = 5, - SpacingCombiningMark = 6, - EnclosingMark = 7, - DecimalDigitNumber = 8, - LetterNumber = 9, - OtherNumber = 10, - SpaceSeparator = 11, - LineSeparator = 12, - ParagraphSeparator = 13, - Control = 14, - Format = 15, - Surrogate = 16, - PrivateUse = 17, - ConnectorPunctuation = 18, - DashPunctuation = 19, - OpenPunctuation = 20, - ClosePunctuation = 21, - InitialQuotePunctuation = 22, - FinalQuotePunctuation = 23, - OtherPunctuation = 24, - MathSymbol = 25, - CurrencySymbol = 26, - ModifierSymbol = 27, - OtherSymbol = 28, - OtherNotAssigned = 29, - } -} |