diff options
| author | TSR Berry <20988865+TSRBerry@users.noreply.github.com> | 2023-04-08 01:22:00 +0200 |
|---|---|---|
| committer | Mary <thog@protonmail.com> | 2023-04-27 23:51:14 +0200 |
| commit | cee712105850ac3385cd0091a923438167433f9f (patch) | |
| tree | 4a5274b21d8b7f938c0d0ce18736d3f2993b11b1 /Ryujinx.HLE/HOS/Services/Time/TimeZone | |
| parent | cd124bda587ef09668a971fa1cac1c3f0cfc9f21 (diff) | |
Move solution and projects to src
Diffstat (limited to 'Ryujinx.HLE/HOS/Services/Time/TimeZone')
9 files changed, 0 insertions, 2418 deletions
diff --git a/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZone.cs b/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZone.cs deleted file mode 100644 index f7477e97..00000000 --- a/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZone.cs +++ /dev/null @@ -1,1703 +0,0 @@ -using Ryujinx.Common; -using Ryujinx.Common.Memory; -using Ryujinx.Common.Utilities; -using Ryujinx.HLE.Utilities; -using System; -using System.Buffers.Binary; -using System.IO; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Text; - -using static Ryujinx.HLE.HOS.Services.Time.TimeZone.TimeZoneRule; - -namespace Ryujinx.HLE.HOS.Services.Time.TimeZone -{ - public class TimeZone - { - private const int TimeTypeSize = 8; - private const int EpochYear = 1970; - private const int YearBase = 1900; - private const int EpochWeekDay = 4; - private const int SecondsPerMinute = 60; - private const int MinutesPerHour = 60; - private const int HoursPerDays = 24; - private const int DaysPerWekk = 7; - private const int DaysPerNYear = 365; - private const int DaysPerLYear = 366; - private const int MonthsPerYear = 12; - private const int SecondsPerHour = SecondsPerMinute * MinutesPerHour; - private const int SecondsPerDay = SecondsPerHour * HoursPerDays; - - private const int YearsPerRepeat = 400; - private const long AverageSecondsPerYear = 31556952; - private const long SecondsPerRepeat = YearsPerRepeat * AverageSecondsPerYear; - - private static readonly int[] YearLengths = { DaysPerNYear, DaysPerLYear }; - private static readonly int[][] MonthsLengths = new int[][] - { - new int[] { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, - new int[] { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } - }; - - private static ReadOnlySpan<byte> TimeZoneDefaultRule => ",M4.1.0,M10.5.0"u8; - - [StructLayout(LayoutKind.Sequential, Pack = 0x4, Size = 0x10)] - private struct CalendarTimeInternal - { - // NOTE: On the IPC side this is supposed to be a 16 bits value but internally this need to be a 64 bits value for ToPosixTime. - public long Year; - public sbyte Month; - public sbyte Day; - public sbyte Hour; - public sbyte Minute; - public sbyte Second; - - public int CompareTo(CalendarTimeInternal other) - { - if (Year != other.Year) - { - if (Year < other.Year) - { - return -1; - } - - return 1; - } - - if (Month != other.Month) - { - return Month - other.Month; - } - - if (Day != other.Day) - { - return Day - other.Day; - } - - if (Hour != other.Hour) - { - return Hour - other.Hour; - } - - if (Minute != other.Minute) - { - return Minute - other.Minute; - } - - if (Second != other.Second) - { - return Second - other.Second; - } - - return 0; - } - } - - private enum RuleType - { - JulianDay, - DayOfYear, - MonthNthDayOfWeek - } - - private struct Rule - { - public RuleType Type; - public int Day; - public int Week; - public int Month; - public int TransitionTime; - } - - private static int Detzcode32(ReadOnlySpan<byte> bytes) - { - return BinaryPrimitives.ReadInt32BigEndian(bytes); - } - - private static int Detzcode32(int value) - { - if (BitConverter.IsLittleEndian) - { - return BinaryPrimitives.ReverseEndianness(value); - } - - return value; - } - - private static long Detzcode64(ReadOnlySpan<byte> bytes) - { - return BinaryPrimitives.ReadInt64BigEndian(bytes); - } - - private static bool DifferByRepeat(long t1, long t0) - { - return (t1 - t0) == SecondsPerRepeat; - } - - private static bool TimeTypeEquals(in TimeZoneRule outRules, byte aIndex, byte bIndex) - { - if (aIndex < 0 || aIndex >= outRules.TypeCount || bIndex < 0 || bIndex >= outRules.TypeCount) - { - return false; - } - - TimeTypeInfo a = outRules.Ttis[aIndex]; - TimeTypeInfo b = outRules.Ttis[bIndex]; - - return a.GmtOffset == b.GmtOffset && - a.IsDaySavingTime == b.IsDaySavingTime && - a.IsStandardTimeDaylight == b.IsStandardTimeDaylight && - a.IsGMT == b.IsGMT && - StringUtils.CompareCStr(outRules.Chars[a.AbbreviationListIndex..], outRules.Chars[b.AbbreviationListIndex..]) == 0; - } - - private static int GetQZName(ReadOnlySpan<byte> name, int namePosition, char delimiter) - { - int i = namePosition; - - while (name[i] != '\0' && name[i] != delimiter) - { - i++; - } - - return i; - } - - private static int GetTZName(ReadOnlySpan<byte> name, int namePosition) - { - int i = namePosition; - - char c; - - while ((c = (char)name[i]) != '\0' && !char.IsDigit(c) && c != ',' && c != '-' && c != '+') - { - i++; - } - - return i; - } - - private static bool GetNum(ReadOnlySpan<byte> name, ref int namePosition, out int num, int min, int max) - { - num = 0; - - if (namePosition >= name.Length) - { - return false; - } - - char c = (char)name[namePosition]; - - if (!char.IsDigit(c)) - { - return false; - } - - do - { - num = num * 10 + (c - '0'); - if (num > max) - { - return false; - } - - if (++namePosition >= name.Length) - { - return false; - } - - c = (char)name[namePosition]; - } - while (char.IsDigit(c)); - - if (num < min) - { - return false; - } - - return true; - } - - private static bool GetSeconds(ReadOnlySpan<byte> name, ref int namePosition, out int seconds) - { - seconds = 0; - - - bool isValid = GetNum(name, ref namePosition, out int num, 0, HoursPerDays * DaysPerWekk - 1); - if (!isValid) - { - return false; - } - - seconds = num * SecondsPerHour; - - if (namePosition >= name.Length) - { - return false; - } - - if (name[namePosition] == ':') - { - namePosition++; - isValid = GetNum(name, ref namePosition, out num, 0, MinutesPerHour - 1); - if (!isValid) - { - return false; - } - - seconds += num * SecondsPerMinute; - - if (namePosition >= name.Length) - { - return false; - } - - if (name[namePosition] == ':') - { - namePosition++; - isValid = GetNum(name, ref namePosition, out num, 0, SecondsPerMinute); - if (!isValid) - { - return false; - } - - seconds += num; - } - } - return true; - } - - private static bool GetOffset(ReadOnlySpan<byte> name, ref int namePosition, ref int offset) - { - bool isNegative = false; - - if (namePosition >= name.Length) - { - return false; - } - - if (name[namePosition] == '-') - { - isNegative = true; - namePosition++; - } - else if (name[namePosition] == '+') - { - namePosition++; - } - - if (namePosition >= name.Length) - { - return false; - } - - bool isValid = GetSeconds(name, ref namePosition, out offset); - if (!isValid) - { - return false; - } - - if (isNegative) - { - offset = -offset; - } - - return true; - } - - private static bool GetRule(ReadOnlySpan<byte> name, ref int namePosition, out Rule rule) - { - rule = new Rule(); - - bool isValid = false; - - if (name[namePosition] == 'J') - { - namePosition++; - - rule.Type = RuleType.JulianDay; - isValid = GetNum(name, ref namePosition, out rule.Day, 1, DaysPerNYear); - } - else if (name[namePosition] == 'M') - { - namePosition++; - - rule.Type = RuleType.MonthNthDayOfWeek; - isValid = GetNum(name, ref namePosition, out rule.Month, 1, MonthsPerYear); - - if (!isValid) - { - return false; - } - - if (name[namePosition++] != '.') - { - return false; - } - - isValid = GetNum(name, ref namePosition, out rule.Week, 1, 5); - if (!isValid) - { - return false; - } - - if (name[namePosition++] != '.') - { - return false; - } - - isValid = GetNum(name, ref namePosition, out rule.Day, 0, DaysPerWekk - 1); - } - else if (char.IsDigit((char)name[namePosition])) - { - rule.Type = RuleType.DayOfYear; - isValid = GetNum(name, ref namePosition, out rule.Day, 0, DaysPerLYear - 1); - } - else - { - return false; - } - - if (!isValid) - { - return false; - } - - if (name[namePosition] == '/') - { - namePosition++; - return GetOffset(name, ref namePosition, ref rule.TransitionTime); - } - else - { - rule.TransitionTime = 2 * SecondsPerHour; - } - - return true; - } - - private static int IsLeap(int year) - { - if (((year) % 4) == 0 && (((year) % 100) != 0 || ((year) % 400) == 0)) - { - return 1; - } - - return 0; - } - - private static bool ParsePosixName(ReadOnlySpan<byte> name, ref TimeZoneRule outRules, bool lastDitch) - { - outRules = new TimeZoneRule(); - - int stdLen; - - ReadOnlySpan<byte> stdName = name; - int namePosition = 0; - int stdOffset = 0; - - if (lastDitch) - { - stdLen = 3; - namePosition += stdLen; - } - else - { - if (name[namePosition] == '<') - { - namePosition++; - - stdName = name.Slice(namePosition); - - int stdNamePosition = namePosition; - - namePosition = GetQZName(name, namePosition, '>'); - - if (name[namePosition] != '>') - { - return false; - } - - stdLen = namePosition - stdNamePosition; - namePosition++; - } - else - { - namePosition = GetTZName(name, namePosition); - stdLen = namePosition; - } - - if (stdLen == 0) - { - return false; - } - - bool isValid = GetOffset(name.ToArray(), ref namePosition, ref stdOffset); - - if (!isValid) - { - return false; - } - } - - int charCount = stdLen + 1; - int destLen = 0; - int dstOffset = 0; - - ReadOnlySpan<byte> destName = name.Slice(namePosition); - - if (TzCharsArraySize < charCount) - { - return false; - } - - if (name[namePosition] != '\0') - { - if (name[namePosition] == '<') - { - destName = name.Slice(++namePosition); - int destNamePosition = namePosition; - - namePosition = GetQZName(name.ToArray(), namePosition, '>'); - - if (name[namePosition] != '>') - { - return false; - } - - destLen = namePosition - destNamePosition; - namePosition++; - } - else - { - destName = name.Slice(namePosition); - namePosition = GetTZName(name, namePosition); - destLen = namePosition; - } - - if (destLen == 0) - { - return false; - } - - charCount += destLen + 1; - if (TzCharsArraySize < charCount) - { - return false; - } - - if (name[namePosition] != '\0' && name[namePosition] != ',' && name[namePosition] != ';') - { - bool isValid = GetOffset(name.ToArray(), ref namePosition, ref dstOffset); - - if (!isValid) - { - return false; - } - } - else - { - dstOffset = stdOffset - SecondsPerHour; - } - - if (name[namePosition] == '\0') - { - name = TimeZoneDefaultRule; - namePosition = 0; - } - - if (name[namePosition] == ',' || name[namePosition] == ';') - { - namePosition++; - - bool IsRuleValid = GetRule(name, ref namePosition, out Rule start); - if (!IsRuleValid) - { - return false; - } - - if (name[namePosition++] != ',') - { - return false; - } - - IsRuleValid = GetRule(name, ref namePosition, out Rule end); - if (!IsRuleValid) - { - return false; - } - - if (name[namePosition] != '\0') - { - return false; - } - - outRules.TypeCount = 2; - - outRules.Ttis[0] = new TimeTypeInfo - { - GmtOffset = -dstOffset, - IsDaySavingTime = true, - AbbreviationListIndex = stdLen + 1 - }; - - outRules.Ttis[1] = new TimeTypeInfo - { - GmtOffset = -stdOffset, - IsDaySavingTime = false, - AbbreviationListIndex = 0 - }; - - outRules.DefaultType = 0; - - int timeCount = 0; - long janFirst = 0; - int janOffset = 0; - int yearBegining = EpochYear; - - do - { - int yearSeconds = YearLengths[IsLeap(yearBegining - 1)] * SecondsPerDay; - yearBegining--; - if (IncrementOverflow64(ref janFirst, -yearSeconds)) - { - janOffset = -yearSeconds; - break; - } - } - while (EpochYear - YearsPerRepeat / 2 < yearBegining); - - int yearLimit = yearBegining + YearsPerRepeat + 1; - int year; - for (year = yearBegining; year < yearLimit; year++) - { - int startTime = TransitionTime(year, start, stdOffset); - int endTime = TransitionTime(year, end, dstOffset); - - int yearSeconds = YearLengths[IsLeap(year)] * SecondsPerDay; - - bool isReversed = endTime < startTime; - if (isReversed) - { - int swap = startTime; - - startTime = endTime; - endTime = swap; - } - - if (isReversed || (startTime < endTime && (endTime - startTime < (yearSeconds + (stdOffset - dstOffset))))) - { - if (TzMaxTimes - 2 < timeCount) - { - break; - } - - outRules.Ats[timeCount] = janFirst; - if (!IncrementOverflow64(ref outRules.Ats[timeCount], janOffset + startTime)) - { - outRules.Types[timeCount++] = isReversed ? (byte)1 : (byte)0; - } - else if (janOffset != 0) - { - outRules.DefaultType = isReversed ? 1 : 0; - } - - outRules.Ats[timeCount] = janFirst; - if (!IncrementOverflow64(ref outRules.Ats[timeCount], janOffset + endTime)) - { - outRules.Types[timeCount++] = isReversed ? (byte)0 : (byte)1; - yearLimit = year + YearsPerRepeat + 1; - } - else if (janOffset != 0) - { - outRules.DefaultType = isReversed ? 0 : 1; - } - } - - if (IncrementOverflow64(ref janFirst, janOffset + yearSeconds)) - { - break; - } - - janOffset = 0; - } - - outRules.TimeCount = timeCount; - - // There is no time variation, this is then a perpetual DST rule - if (timeCount == 0) - { - outRules.TypeCount = 1; - } - else if (YearsPerRepeat < year - yearBegining) - { - outRules.GoBack = true; - outRules.GoAhead = true; - } - } - else - { - if (name[namePosition] == '\0') - { - return false; - } - - long theirStdOffset = 0; - for (int i = 0; i < outRules.TimeCount; i++) - { - int j = outRules.Types[i]; - if (outRules.Ttis[j].IsStandardTimeDaylight) - { - theirStdOffset = -outRules.Ttis[j].GmtOffset; - } - } - - long theirDstOffset = 0; - for (int i = 0; i < outRules.TimeCount; i++) - { - int j = outRules.Types[i]; - if (outRules.Ttis[j].IsDaySavingTime) - { - theirDstOffset = -outRules.Ttis[j].GmtOffset; - } - } - - bool isDaySavingTime = false; - long theirOffset = theirStdOffset; - for (int i = 0; i < outRules.TimeCount; i++) - { - int j = outRules.Types[i]; - outRules.Types[i] = outRules.Ttis[j].IsDaySavingTime ? (byte)1 : (byte)0; - if (!outRules.Ttis[j].IsGMT) - { - if (isDaySavingTime && !outRules.Ttis[j].IsStandardTimeDaylight) - { - outRules.Ats[i] += dstOffset - theirStdOffset; - } - else - { - outRules.Ats[i] += stdOffset - theirStdOffset; - } - } - - theirOffset = -outRules.Ttis[j].GmtOffset; - if (outRules.Ttis[j].IsDaySavingTime) - { - theirDstOffset = theirOffset; - } - else - { - theirStdOffset = theirOffset; - } - } - - outRules.Ttis[0] = new TimeTypeInfo - { - GmtOffset = -stdOffset, - IsDaySavingTime = false, - AbbreviationListIndex = 0 - }; - - outRules.Ttis[1] = new TimeTypeInfo - { - GmtOffset = -dstOffset, - IsDaySavingTime = true, - AbbreviationListIndex = stdLen + 1 - }; - - outRules.TypeCount = 2; - outRules.DefaultType = 0; - } - } - else - { - // default is perpetual standard time - outRules.TypeCount = 1; - outRules.TimeCount = 0; - outRules.DefaultType = 0; - outRules.Ttis[0] = new TimeTypeInfo - { - GmtOffset = -stdOffset, - IsDaySavingTime = false, - AbbreviationListIndex = 0 - }; - } - - outRules.CharCount = charCount; - - int charsPosition = 0; - - for (int i = 0; i < stdLen; i++) - { - outRules.Chars[i] = stdName[i]; - } - - charsPosition += stdLen; - outRules.Chars[charsPosition++] = 0; - - if (destLen != 0) - { - for (int i = 0; i < destLen; i++) - { - outRules.Chars[charsPosition + i] = destName[i]; - } - outRules.Chars[charsPosition + destLen] = 0; - } - - return true; - } - - private static int TransitionTime(int year, Rule rule, int offset) - { - int leapYear = IsLeap(year); - - int value; - switch (rule.Type) - { - case RuleType.JulianDay: - value = (rule.Day - 1) * SecondsPerDay; - if (leapYear == 1 && rule.Day >= 60) - { - value += SecondsPerDay; - } - break; - - case RuleType.DayOfYear: - value = rule.Day * SecondsPerDay; - break; - - case RuleType.MonthNthDayOfWeek: - // Here we use Zeller's Congruence to get the day of week of the first month. - - int m1 = (rule.Month + 9) % 12 + 1; - int yy0 = (rule.Month <= 2) ? (year - 1) : year; - int yy1 = yy0 / 100; - int yy2 = yy0 % 100; - - int dayOfWeek = ((26 * m1 - 2) / 10 + 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7; - - if (dayOfWeek < 0) - { - dayOfWeek += DaysPerWekk; - } - - // Get the zero origin - int d = rule.Day - dayOfWeek; - - if (d < 0) - { - d += DaysPerWekk; - } - - for (int i = 1; i < rule.Week; i++) - { - if (d + DaysPerWekk >= MonthsLengths[leapYear][rule.Month - 1]) - { - break; - } - - d += DaysPerWekk; - } - - value = d * SecondsPerDay; - for (int i = 0; i < rule.Month - 1; i++) - { - value += MonthsLengths[leapYear][i] * SecondsPerDay; - } - - break; - default: - throw new NotImplementedException("Unknown time transition!"); - } - - return value + rule.TransitionTime + offset; - } - - private static bool NormalizeOverflow32(ref int ip, ref int unit, int baseValue) - { - int delta; - - if (unit >= 0) - { - delta = unit / baseValue; - } - else - { - delta = -1 - (-1 - unit) / baseValue; - } - - unit -= delta * baseValue; - - return IncrementOverflow32(ref ip, delta); - } - - private static bool NormalizeOverflow64(ref long ip, ref long unit, long baseValue) - { - long delta; - - if (unit >= 0) - { - delta = unit / baseValue; - } - else - { - delta = -1 - (-1 - unit) / baseValue; - } - - unit -= delta * baseValue; - - return IncrementOverflow64(ref ip, delta); - } - - private static bool IncrementOverflow32(ref int time, int j) - { - try - { - time = checked(time + j); - - return false; - } - catch (OverflowException) - { - return true; - } - } - - private static bool IncrementOverflow64(ref long time, long j) - { - try - { - time = checked(time + j); - - return false; - } - catch (OverflowException) - { - return true; - } - } - - internal static bool ParsePosixName(string name, ref TimeZoneRule outRules) - { - return ParsePosixName(Encoding.ASCII.GetBytes(name), ref outRules, false); - } - - internal static bool ParseTimeZoneBinary(ref TimeZoneRule outRules, Stream inputData) - { - outRules = new TimeZoneRule(); - - BinaryReader reader = new BinaryReader(inputData); - - long streamLength = reader.BaseStream.Length; - - if (streamLength < Unsafe.SizeOf<TzifHeader>()) - { - return false; - } - - TzifHeader header = reader.ReadStruct<TzifHeader>(); - - streamLength -= Unsafe.SizeOf<TzifHeader>(); - - int ttisGMTCount = Detzcode32(header.TtisGMTCount); - int ttisSTDCount = Detzcode32(header.TtisSTDCount); - int leapCount = Detzcode32(header.LeapCount); - int timeCount = Detzcode32(header.TimeCount); - int typeCount = Detzcode32(header.TypeCount); - int charCount = Detzcode32(header.CharCount); - - if (!(0 <= leapCount - && leapCount < TzMaxLeaps - && 0 < typeCount - && typeCount < TzMaxTypes - && 0 <= timeCount - && timeCount < TzMaxTimes - && 0 <= charCount - && charCount < TzMaxChars - && (ttisSTDCount == typeCount || ttisSTDCount == 0) - && (ttisGMTCount == typeCount || ttisGMTCount == 0))) - { - return false; - } - - - if (streamLength < (timeCount * TimeTypeSize - + timeCount - + typeCount * 6 - + charCount - + leapCount * (TimeTypeSize + 4) - + ttisSTDCount - + ttisGMTCount)) - { - return false; - } - - outRules.TimeCount = timeCount; - outRules.TypeCount = typeCount; - outRules.CharCount = charCount; - - byte[] workBuffer = StreamUtils.StreamToBytes(inputData); - - timeCount = 0; - - { - Span<byte> p = workBuffer; - for (int i = 0; i < outRules.TimeCount; i++) - { - long at = Detzcode64(p); - outRules.Types[i] = 1; - - if (timeCount != 0 && at <= outRules.Ats[timeCount - 1]) - { - if (at < outRules.Ats[timeCount - 1]) - { - return false; - } - - outRules.Types[i - 1] = 0; - timeCount--; - } - - outRules.Ats[timeCount++] = at; - - p = p[TimeTypeSize..]; - } - - timeCount = 0; - for (int i = 0; i < outRules.TimeCount; i++) - { - byte type = p[0]; - p = p[1..]; - - if (outRules.TypeCount <= type) - { - return false; - } - - if (outRules.Types[i] != 0) - { - outRules.Types[timeCount++] = type; - } - } - - outRules.TimeCount = timeCount; - - for (int i = 0; i < outRules.TypeCount; i++) - { - TimeTypeInfo ttis = outRules.Ttis[i]; - ttis.GmtOffset = Detzcode32(p); - p = p[sizeof(int)..]; - - if (p[0] >= 2) - { - return false; - } - - ttis.IsDaySavingTime = p[0] != 0; - p = p[1..]; - - int abbreviationListIndex = p[0]; - p = p[1..]; - - if (abbreviationListIndex >= outRules.CharCount) - { - return false; - } - - ttis.AbbreviationListIndex = abbreviationListIndex; - - outRules.Ttis[i] = ttis; - } - - p[..outRules.CharCount].CopyTo(outRules.Chars); - - p = p[outRules.CharCount..]; - outRules.Chars[outRules.CharCount] = 0; - - for (int i = 0; i < outRules.TypeCount; i++) - { - if (ttisSTDCount == 0) - { - outRules.Ttis[i].IsStandardTimeDaylight = false; - } - else - { - if (p[0] >= 2) - { - return false; - } - - outRules.Ttis[i].IsStandardTimeDaylight = p[0] != 0; - p = p[1..]; - } - } - - for (int i = 0; i < outRules.TypeCount; i++) - { - if (ttisSTDCount == 0) - { - outRules.Ttis[i].IsGMT = false; - } - else - { - if (p[0] >= 2) - { - return false; - } - - outRules.Ttis[i].IsGMT = p[0] != 0; - p = p[1..]; - } - - } - - long position = (workBuffer.Length - p.Length); - long nRead = streamLength - position; - - if (nRead < 0) - { - return false; - } - - // Nintendo abort in case of a TzIf file with a POSIX TZ Name too long to fit inside a TimeZoneRule. - // As it's impossible in normal usage to achive this, we also force a crash. - if (nRead > (TzNameMax + 1)) - { - throw new InvalidOperationException(); - } - - byte[] tempName = new byte[TzNameMax + 1]; - Array.Copy(workBuffer, position, tempName, 0, nRead); - - if (nRead > 2 && tempName[0] == '\n' && tempName[nRead - 1] == '\n' && outRules.TypeCount + 2 <= TzMaxTypes) - { - tempName[nRead - 1] = 0; - - byte[] name = new byte[TzNameMax]; - Array.Copy(tempName, 1, name, 0, nRead - 1); - - Box<TimeZoneRule> tempRulesBox = new Box<TimeZoneRule>(); - ref TimeZoneRule tempRules = ref tempRulesBox.Data; - - if (ParsePosixName(name, ref tempRulesBox.Data, false)) - { - int abbreviationCount = 0; - charCount = outRules.CharCount; - - Span<byte> chars = outRules.Chars; - - for (int i = 0; i < tempRules.TypeCount; i++) - { - ReadOnlySpan<byte> tempChars = tempRules.Chars; - ReadOnlySpan<byte> tempAbbreviation = tempChars[tempRules.Ttis[i].AbbreviationListIndex..]; - - int j; - - for (j = 0; j < charCount; j++) - { - if (StringUtils.CompareCStr(chars[j..], tempAbbreviation) == 0) - { - tempRules.Ttis[i].AbbreviationListIndex = j; - abbreviationCount++; - break; - } - } - - if (j >= charCount) - { - int abbreviationLength = StringUtils.LengthCstr(tempAbbreviation); - if (j + abbreviationLength < TzMaxChars) - { - for (int x = 0; x < abbreviationLength; x++) - { - chars[j + x] = tempAbbreviation[x]; - } - - charCount = j + abbreviationLength + 1; - - tempRules.Ttis[i].AbbreviationListIndex = j; - abbreviationCount++; - } - } - } - - if (abbreviationCount == tempRules.TypeCount) - { - outRules.CharCount = charCount; - - // Remove trailing - while (1 < outRules.TimeCount && (outRules.Types[outRules.TimeCount - 1] == outRules.Types[outRules.TimeCount - 2])) - { - outRules.TimeCount--; - } - - int i; - - for (i = 0; i < tempRules.TimeCount; i++) - { - if (outRules.TimeCount == 0 || outRules.Ats[outRules.TimeCount - 1] < tempRules.Ats[i]) - { - break; - } - } - - while (i < tempRules.TimeCount && outRules.TimeCount < TzMaxTimes) - { - outRules.Ats[outRules.TimeCount] = tempRules.Ats[i]; - outRules.Types[outRules.TimeCount] = (byte)(outRules.TypeCount + (byte)tempRules.Types[i]); - - outRules.TimeCount++; - i++; - } - - for (i = 0; i < tempRules.TypeCount; i++) - { - outRules.Ttis[outRules.TypeCount++] = tempRules.Ttis[i]; - } - } - } - } - - if (outRules.TypeCount == 0) - { - return false; - } - - if (outRules.TimeCount > 1) - { - for (int i = 1; i < outRules.TimeCount; i++) - { - if (TimeTypeEquals(in outRules, outRules.Types[i], outRules.Types[0]) && DifferByRepeat(outRules.Ats[i], outRules.Ats[0])) - { - outRules.GoBack = true; - break; - } - } - - for (int i = outRules.TimeCount - 2; i >= 0; i--) - { - if (TimeTypeEquals(in outRules, outRules.Types[outRules.TimeCount - 1], outRules.Types[i]) && DifferByRepeat(outRules.Ats[outRules.TimeCount - 1], outRules.Ats[i])) - { - outRules.GoAhead = true; - break; - } - } - } - - int defaultType; - - for (defaultType = 0; defaultType < outRules.TimeCount; defaultType++) - { - if (outRules.Types[defaultType] == 0) - { - break; - } - } - - defaultType = defaultType < outRules.TimeCount ? -1 : 0; - - if (defaultType < 0 && outRules.TimeCount > 0 && outRules.Ttis[outRules.Types[0]].IsDaySavingTime) - { - defaultType = outRules.Types[0]; - while (--defaultType >= 0) - { - if (!outRules.Ttis[defaultType].IsDaySavingTime) - { - break; - } - } - } - - if (defaultType < 0) - { - defaultType = 0; - while (outRules.Ttis[defaultType].IsDaySavingTime) - { - if (++defaultType >= outRules.TypeCount) - { - defaultType = 0; - break; - } - } - } - - outRules.DefaultType = defaultType; - } - - return true; - } - - private static long GetLeapDaysNotNeg(long year) - { - return year / 4 - year / 100 + year / 400; - } - - private static long GetLeapDays(long year) - { - if (year < 0) - { - return -1 - GetLeapDaysNotNeg(-1 - year); - } - else - { - return GetLeapDaysNotNeg(year); - } - } - - private static ResultCode CreateCalendarTime(long time, int gmtOffset, out CalendarTimeInternal calendarTime, out CalendarAdditionalInfo calendarAdditionalInfo) - { - long year = EpochYear; - long timeDays = time / SecondsPerDay; - long remainingSeconds = time % SecondsPerDay; - - calendarTime = new CalendarTimeInternal(); - calendarAdditionalInfo = new CalendarAdditionalInfo(); - - while (timeDays < 0 || timeDays >= YearLengths[IsLeap((int)year)]) - { - long timeDelta = timeDays / DaysPerLYear; - long delta = timeDelta; - - if (delta == 0) - { - delta = timeDays < 0 ? -1 : 1; - } - - long newYear = year; - - if (IncrementOverflow64(ref newYear, delta)) - { - return ResultCode.OutOfRange; - } - - long leapDays = GetLeapDays(newYear - 1) - GetLeapDays(year - 1); - timeDays -= (newYear - year) * DaysPerNYear; - timeDays -= leapDays; - year = newYear; - } - - long dayOfYear = timeDays; - remainingSeconds += gmtOffset; - while (remainingSeconds < 0) - { - remainingSeconds += SecondsPerDay; - dayOfYear -= 1; - } - - while (remainingSeconds >= SecondsPerDay) - { - remainingSeconds -= SecondsPerDay; - dayOfYear += 1; - } - - while (dayOfYear < 0) - { - if (IncrementOverflow64(ref year, -1)) - { - return ResultCode.OutOfRange; - } - - dayOfYear += YearLengths[IsLeap((int)year)]; - } - - while (dayOfYear >= YearLengths[IsLeap((int)year)]) - { - dayOfYear -= YearLengths[IsLeap((int)year)]; - - if (IncrementOverflow64(ref year, 1)) - { - return ResultCode.OutOfRange; - } - } - - calendarTime.Year = year; - calendarAdditionalInfo.DayOfYear = (uint)dayOfYear; - - long dayOfWeek = (EpochWeekDay + ((year - EpochYear) % DaysPerWekk) * (DaysPerNYear % DaysPerWekk) + GetLeapDays(year - 1) - GetLeapDays(EpochYear - 1) + dayOfYear) % DaysPerWekk; - if (dayOfWeek < 0) - { - dayOfWeek += DaysPerWekk; - } - - calendarAdditionalInfo.DayOfWeek = (uint)dayOfWeek; - - calendarTime.Hour = (sbyte)((remainingSeconds / SecondsPerHour) % SecondsPerHour); - remainingSeconds %= SecondsPerHour; - - calendarTime.Minute = (sbyte)(remainingSeconds / SecondsPerMinute); - calendarTime.Second = (sbyte)(remainingSeconds % SecondsPerMinute); - - int[] ip = MonthsLengths[IsLeap((int)year)]; - - for (calendarTime.Month = 0; dayOfYear >= ip[calendarTime.Month]; ++calendarTime.Month) - { - dayOfYear -= ip[calendarTime.Month]; - } - - calendarTime.Day = (sbyte)(dayOfYear + 1); - - calendarAdditionalInfo.IsDaySavingTime = false; - calendarAdditionalInfo.GmtOffset = gmtOffset; - - return 0; - } - - private static ResultCode ToCalendarTimeInternal(in TimeZoneRule rules, long time, out CalendarTimeInternal calendarTime, out CalendarAdditionalInfo calendarAdditionalInfo) - { - calendarTime = new CalendarTimeInternal(); - calendarAdditionalInfo = new CalendarAdditionalInfo(); - - ResultCode result; - - if ((rules.GoAhead && time < rules.Ats[0]) || (rules.GoBack && time > rules.Ats[rules.TimeCount - 1])) - { - long newTime = time; - - long seconds; - long years; - - if (time < rules.Ats[0]) - { - seconds = rules.Ats[0] - time; - } - else - { - seconds = time - rules.Ats[rules.TimeCount - 1]; - } - - seconds -= 1; - - years = (seconds / SecondsPerRepeat + 1) * YearsPerRepeat; - seconds = years * AverageSecondsPerYear; - - if (time < rules.Ats[0]) - { - newTime += seconds; - } - else - { - newTime -= seconds; - } - - if (newTime < rules.Ats[0] && newTime > rules.Ats[rules.TimeCount - 1]) - { - return ResultCode.TimeNotFound; - } - - result = ToCalendarTimeInternal(in rules, newTime, out calendarTime, out calendarAdditionalInfo); - if (result != 0) - { - return result; - } - - if (time < rules.Ats[0]) - { - calendarTime.Year -= years; - } - else - { - calendarTime.Year += years; - } - - return ResultCode.Success; - } - - int ttiIndex; - - if (rules.TimeCount == 0 || time < rules.Ats[0]) - { - ttiIndex = rules.DefaultType; - } - else - { - int low = 1; - int high = rules.TimeCount; - - while (low < high) - { - int mid = (low + high) >> 1; - - if (time < rules.Ats[mid]) - { - high = mid; - } - else - { - low = mid + 1; - } - } - - ttiIndex = rules.Types[low - 1]; - } - - result = CreateCalendarTime(time, rules.Ttis[ttiIndex].GmtOffset, out calendarTime, out calendarAdditionalInfo); - - if (result == 0) - { - calendarAdditionalInfo.IsDaySavingTime = rules.Ttis[ttiIndex].IsDaySavingTime; - - ReadOnlySpan<byte> timeZoneAbbreviation = rules.Chars[rules.Ttis[ttiIndex].AbbreviationListIndex..]; - - int timeZoneSize = Math.Min(StringUtils.LengthCstr(timeZoneAbbreviation), 8); - - timeZoneAbbreviation[..timeZoneSize].CopyTo(calendarAdditionalInfo.TimezoneName.AsSpan()); - } - - return result; - } - - private static ResultCode ToPosixTimeInternal(in TimeZoneRule rules, CalendarTimeInternal calendarTime, out long posixTime) - { - posixTime = 0; - - int hour = calendarTime.Hour; - int minute = calendarTime.Minute; - - if (NormalizeOverflow32(ref hour, ref minute, MinutesPerHour)) - { - return ResultCode.Overflow; - } - - calendarTime.Minute = (sbyte)minute; - - int day = calendarTime.Day; - if (NormalizeOverflow32(ref day, ref hour, HoursPerDays)) - { - return ResultCode.Overflow; - } - - calendarTime.Day = (sbyte)day; - calendarTime.Hour = (sbyte)hour; - - long year = calendarTime.Year; - long month = calendarTime.Month; - - if (NormalizeOverflow64(ref year, ref month, MonthsPerYear)) - { - return ResultCode.Overflow; - } - - calendarTime.Month = (sbyte)month; - - if (IncrementOverflow64(ref year, YearBase)) - { - return ResultCode.Overflow; - } - - while (day <= 0) - { - if (IncrementOverflow64(ref year, -1)) - { - return ResultCode.Overflow; - } - - long li = year; - - if (1 < calendarTime.Month) - { - li++; - } - - day += YearLengths[IsLeap((int)li)]; - } - - while (day > DaysPerLYear) - { - long li = year; - - if (1 < calendarTime.Month) - { - li++; - } - - day -= YearLengths[IsLeap((int)li)]; - - if (IncrementOverflow64(ref year, 1)) - { - return ResultCode.Overflow; - } - } - - while (true) - { - int i = MonthsLengths[IsLeap((int)year)][calendarTime.Month]; - - if (day <= i) - { - break; - } - - day -= i; - calendarTime.Month += 1; - - if (calendarTime.Month >= MonthsPerYear) - { - calendarTime.Month = 0; - if (IncrementOverflow64(ref year, 1)) - { - return ResultCode.Overflow; - } - } - } - - calendarTime.Day = (sbyte)day; - - if (IncrementOverflow64(ref year, -YearBase)) - { - return ResultCode.Overflow; - } - - calendarTime.Year = year; - - int savedSeconds; - - if (calendarTime.Second >= 0 && calendarTime.Second < SecondsPerMinute) - { - savedSeconds = 0; - } - else if (year + YearBase < EpochYear) - { - int second = calendarTime.Second; - if (IncrementOverflow32(ref second, 1 - SecondsPerMinute)) - { - return ResultCode.Overflow; - } - - savedSeconds = second; - calendarTime.Second = 1 - SecondsPerMinute; - } - else - { - savedSeconds = calendarTime.Second; - calendarTime.Second = 0; - } - - long low = long.MinValue; - long high = long.MaxValue; - - while (true) - { - long pivot = low / 2 + high / 2; - - if (pivot < low) - { - pivot = low; - } - else if (pivot > high) - { - pivot = high; - } - - int direction; - - ResultCode result = ToCalendarTimeInternal(in rules, pivot, out CalendarTimeInternal candidateCalendarTime, out _); - if (result != 0) - { - if (pivot > 0) - { - direction = 1; - } - else - { - direction = -1; - } - } - else - { - direction = candidateCalendarTime.CompareTo(calendarTime); - } - - if (direction == 0) - { - long timeResult = pivot + savedSeconds; - - if ((timeResult < pivot) != (savedSeconds < 0)) - { - return ResultCode.Overflow; - } - - posixTime = timeResult; - break; - } - else - { - if (pivot == low) - { - if (pivot == long.MaxValue) - { - return ResultCode.TimeNotFound; - } - - pivot += 1; - low += 1; - } - else if (pivot == high) - { - if (pivot == long.MinValue) - { - return ResultCode.TimeNotFound; - } - - pivot -= 1; - high -= 1; - } - - if (low > high) - { - return ResultCode.TimeNotFound; - } - - if (direction > 0) - { - high = pivot; - } - else - { - low = pivot; - } - } - } - - return ResultCode.Success; - } - - internal static ResultCode ToCalendarTime(in TimeZoneRule rules, long time, out CalendarInfo calendar) - { - ResultCode result = ToCalendarTimeInternal(in rules, time, out CalendarTimeInternal calendarTime, out CalendarAdditionalInfo calendarAdditionalInfo); - - calendar = new CalendarInfo() - { - Time = new CalendarTime() - { - Year = (short)calendarTime.Year, - // NOTE: Nintendo's month range is 1-12, internal range is 0-11. - Month = (sbyte)(calendarTime.Month + 1), - Day = calendarTime.Day, - Hour = calendarTime.Hour, - Minute = calendarTime.Minute, - Second = calendarTime.Second - }, - AdditionalInfo = calendarAdditionalInfo - }; - - return result; - } - - internal static ResultCode ToPosixTime(in TimeZoneRule rules, CalendarTime calendarTime, out long posixTime) - { - CalendarTimeInternal calendarTimeInternal = new CalendarTimeInternal() - { - Year = calendarTime.Year, - // NOTE: Nintendo's month range is 1-12, internal range is 0-11. - Month = (sbyte)(calendarTime.Month - 1), - Day = calendarTime.Day, - Hour = calendarTime.Hour, - Minute = calendarTime.Minute, - Second = calendarTime.Second - }; - - return ToPosixTimeInternal(in rules, calendarTimeInternal, out posixTime); - } - } -}
\ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneContentManager.cs b/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneContentManager.cs deleted file mode 100644 index 9367024e..00000000 --- a/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneContentManager.cs +++ /dev/null @@ -1,304 +0,0 @@ -using LibHac; -using LibHac.Common; -using LibHac.Fs; -using LibHac.Fs.Fsa; -using LibHac.FsSystem; -using LibHac.Ncm; -using LibHac.Tools.FsSystem; -using LibHac.Tools.FsSystem.NcaUtils; -using Ryujinx.Common.Logging; -using Ryujinx.Cpu; -using Ryujinx.HLE.Exceptions; -using Ryujinx.HLE.FileSystem; -using Ryujinx.HLE.HOS.Services.Time.Clock; -using Ryujinx.HLE.Utilities; -using System; -using System.Collections.Generic; -using System.IO; -using System.Text; -using TimeZoneRuleBox = Ryujinx.Common.Memory.Box<Ryujinx.HLE.HOS.Services.Time.TimeZone.TimeZoneRule>; - -namespace Ryujinx.HLE.HOS.Services.Time.TimeZone -{ - public class TimeZoneContentManager - { - private const long TimeZoneBinaryTitleId = 0x010000000000080E; - - private readonly string TimeZoneSystemTitleMissingErrorMessage = "TimeZoneBinary system title not found! TimeZone conversions will not work, provide the system archive to fix this error. (See https://github.com/Ryujinx/Ryujinx/wiki/Ryujinx-Setup-&-Configuration-Guide#initial-setup-continued---installation-of-firmware for more information)"; - - private VirtualFileSystem _virtualFileSystem; - private IntegrityCheckLevel _fsIntegrityCheckLevel; - private ContentManager _contentManager; - - public string[] LocationNameCache { get; private set; } - - internal TimeZoneManager Manager { get; private set; } - - public TimeZoneContentManager() - { - Manager = new TimeZoneManager(); - } - - public void InitializeInstance(VirtualFileSystem virtualFileSystem, ContentManager contentManager, IntegrityCheckLevel fsIntegrityCheckLevel) - { - _virtualFileSystem = virtualFileSystem; - _contentManager = contentManager; - _fsIntegrityCheckLevel = fsIntegrityCheckLevel; - - InitializeLocationNameCache(); - } - - public string SanityCheckDeviceLocationName(string locationName) - { - if (IsLocationNameValid(locationName)) - { - return locationName; - } - - Logger.Warning?.Print(LogClass.ServiceTime, $"Invalid device TimeZone {locationName}, switching back to UTC"); - - return "UTC"; - } - - internal void Initialize(TimeManager timeManager, Switch device) - { - InitializeInstance(device.FileSystem, device.System.ContentManager, device.System.FsIntegrityCheckLevel); - - ITickSource tickSource = device.System.TickSource; - - SteadyClockTimePoint timeZoneUpdatedTimePoint = timeManager.StandardSteadyClock.GetCurrentTimePoint(tickSource); - - string deviceLocationName = SanityCheckDeviceLocationName(device.Configuration.TimeZone); - - ResultCode result = GetTimeZoneBinary(deviceLocationName, out Stream timeZoneBinaryStream, out LocalStorage ncaFile); - - if (result == ResultCode.Success) - { - // TODO: Read TimeZoneVersion from sysarchive. - timeManager.SetupTimeZoneManager(deviceLocationName, timeZoneUpdatedTimePoint, (uint)LocationNameCache.Length, new UInt128(), timeZoneBinaryStream); - - ncaFile.Dispose(); - } - else - { - // In the case the user don't have the timezone system archive, we just mark the manager as initialized. - Manager.MarkInitialized(); - } - } - - private void InitializeLocationNameCache() - { - if (HasTimeZoneBinaryTitle()) - { - using (IStorage ncaFileStream = new LocalStorage(_virtualFileSystem.SwitchPathToSystemPath(GetTimeZoneBinaryTitleContentPath()), FileAccess.Read, FileMode.Open)) - { - Nca nca = new Nca(_virtualFileSystem.KeySet, ncaFileStream); - IFileSystem romfs = nca.OpenFileSystem(NcaSectionType.Data, _fsIntegrityCheckLevel); - - using var binaryListFile = new UniqueRef<IFile>(); - - romfs.OpenFile(ref binaryListFile.Ref, "/binaryList.txt".ToU8Span(), OpenMode.Read).ThrowIfFailure(); - - StreamReader reader = new StreamReader(binaryListFile.Get.AsStream()); - - List<string> locationNameList = new List<string>(); - - string locationName; - while ((locationName = reader.ReadLine()) != null) - { - locationNameList.Add(locationName); - } - - LocationNameCache = locationNameList.ToArray(); - } - } - else - { - LocationNameCache = new string[] { "UTC" }; - - Logger.Error?.Print(LogClass.ServiceTime, TimeZoneSystemTitleMissingErrorMessage); - } - } - - public IEnumerable<(int Offset, string Location, string Abbr)> ParseTzOffsets() - { - var tzBinaryContentPath = GetTimeZoneBinaryTitleContentPath(); - - if (string.IsNullOrEmpty(tzBinaryContentPath)) - { - return new[] { (0, "UTC", "UTC") }; - } - - List<(int Offset, string Location, string Abbr)> outList = new List<(int Offset, string Location, string Abbr)>(); - var now = DateTimeOffset.Now.ToUnixTimeSeconds(); - using (IStorage ncaStorage = new LocalStorage(_virtualFileSystem.SwitchPathToSystemPath(tzBinaryContentPath), FileAccess.Read, FileMode.Open)) - using (IFileSystem romfs = new Nca(_virtualFileSystem.KeySet, ncaStorage).OpenFileSystem(NcaSectionType.Data, _fsIntegrityCheckLevel)) - { - foreach (string locName in LocationNameCache) - { - if (locName.StartsWith("Etc")) - { - continue; - } - - using var tzif = new UniqueRef<IFile>(); - - if (romfs.OpenFile(ref tzif.Ref, $"/zoneinfo/{locName}".ToU8Span(), OpenMode.Read).IsFailure()) - { - Logger.Error?.Print(LogClass.ServiceTime, $"Error opening /zoneinfo/{locName}"); - continue; - } - - TimeZoneRuleBox tzRuleBox = new TimeZoneRuleBox(); - ref TimeZoneRule tzRule = ref tzRuleBox.Data; - - TimeZone.ParseTimeZoneBinary(ref tzRule, tzif.Get.AsStream()); - - - TimeTypeInfo ttInfo; - if (tzRule.TimeCount > 0) // Find the current transition period - { - int fin = 0; - for (int i = 0; i < tzRule.TimeCount; ++i) - { - if (tzRule.Ats[i] <= now) - { - fin = i; - } - } - ttInfo = tzRule.Ttis[tzRule.Types[fin]]; - } - else if (tzRule.TypeCount >= 1) // Otherwise, use the first offset in TTInfo - { - ttInfo = tzRule.Ttis[0]; - } - else - { - Logger.Error?.Print(LogClass.ServiceTime, $"Couldn't find UTC offset for zone {locName}"); - continue; - } - - var abbrStart = tzRule.Chars[ttInfo.AbbreviationListIndex..]; - int abbrEnd = abbrStart.IndexOf((byte)0); - - outList.Add((ttInfo.GmtOffset, locName, Encoding.UTF8.GetString(abbrStart[..abbrEnd]))); - } - } - - outList.Sort(); - - return outList; - } - - private bool IsLocationNameValid(string locationName) - { - foreach (string cachedLocationName in LocationNameCache) - { - if (cachedLocationName.Equals(locationName)) - { - return true; - } - } - - return false; - } - - public ResultCode SetDeviceLocationName(string locationName) - { - ResultCode result = GetTimeZoneBinary(locationName, out Stream timeZoneBinaryStream, out LocalStorage ncaFile); - - if (result == ResultCode.Success) - { - result = Manager.SetDeviceLocationNameWithTimeZoneRule(locationName, timeZoneBinaryStream); - - ncaFile.Dispose(); - } - - return result; - } - - public ResultCode LoadLocationNameList(uint index, out string[] outLocationNameArray, uint maxLength) - { - List<string> locationNameList = new List<string>(); - - for (int i = 0; i < LocationNameCache.Length && i < maxLength; i++) - { - if (i < index) - { - continue; - } - - string locationName = LocationNameCache[i]; - - // If the location name is too long, error out. - if (locationName.Length > 0x24) - { - outLocationNameArray = Array.Empty<string>(); - - return ResultCode.LocationNameTooLong; - } - - locationNameList.Add(locationName); - } - - outLocationNameArray = locationNameList.ToArray(); - - return ResultCode.Success; - } - - public string GetTimeZoneBinaryTitleContentPath() - { - return _contentManager.GetInstalledContentPath(TimeZoneBinaryTitleId, StorageId.BuiltInSystem, NcaContentType.Data); - } - - public bool HasTimeZoneBinaryTitle() - { - return !string.IsNullOrEmpty(GetTimeZoneBinaryTitleContentPath()); - } - - internal ResultCode GetTimeZoneBinary(string locationName, out Stream timeZoneBinaryStream, out LocalStorage ncaFile) - { - timeZoneBinaryStream = null; - ncaFile = null; - - if (!HasTimeZoneBinaryTitle() || !IsLocationNameValid(locationName)) - { - return ResultCode.TimeZoneNotFound; - } - - ncaFile = new LocalStorage(_virtualFileSystem.SwitchPathToSystemPath(GetTimeZoneBinaryTitleContentPath()), FileAccess.Read, FileMode.Open); - - Nca nca = new Nca(_virtualFileSystem.KeySet, ncaFile); - IFileSystem romfs = nca.OpenFileSystem(NcaSectionType.Data, _fsIntegrityCheckLevel); - - using var timeZoneBinaryFile = new UniqueRef<IFile>(); - - Result result = romfs.OpenFile(ref timeZoneBinaryFile.Ref, $"/zoneinfo/{locationName}".ToU8Span(), OpenMode.Read); - - timeZoneBinaryStream = timeZoneBinaryFile.Release().AsStream(); - - return (ResultCode)result.Value; - } - - internal ResultCode LoadTimeZoneRule(ref TimeZoneRule rules, string locationName) - { - rules = default; - - if (!HasTimeZoneBinaryTitle()) - { - throw new InvalidSystemResourceException(TimeZoneSystemTitleMissingErrorMessage); - } - - ResultCode result = GetTimeZoneBinary(locationName, out Stream timeZoneBinaryStream, out LocalStorage ncaFile); - - if (result == ResultCode.Success) - { - result = Manager.ParseTimeZoneRuleBinary(ref rules, timeZoneBinaryStream); - - ncaFile.Dispose(); - } - - return result; - } - } -} diff --git a/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneManager.cs b/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneManager.cs deleted file mode 100644 index ef4b7b39..00000000 --- a/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneManager.cs +++ /dev/null @@ -1,261 +0,0 @@ -using Ryujinx.Common.Memory; -using Ryujinx.HLE.HOS.Services.Time.Clock; -using System; -using System.IO; - -namespace Ryujinx.HLE.HOS.Services.Time.TimeZone -{ - class TimeZoneManager - { - private bool _isInitialized; - private Box<TimeZoneRule> _myRules; - private string _deviceLocationName; - private UInt128 _timeZoneRuleVersion; - private uint _totalLocationNameCount; - private SteadyClockTimePoint _timeZoneUpdateTimePoint; - private object _lock; - - public TimeZoneManager() - { - _isInitialized = false; - _deviceLocationName = "UTC"; - _timeZoneRuleVersion = new UInt128(); - _lock = new object(); - _myRules = new Box<TimeZoneRule>(); - - _timeZoneUpdateTimePoint = SteadyClockTimePoint.GetRandom(); - } - - public bool IsInitialized() - { - bool res; - - lock (_lock) - { - res = _isInitialized; - } - - return res; - } - - public void MarkInitialized() - { - lock (_lock) - { - _isInitialized = true; - } - } - - public ResultCode GetDeviceLocationName(out string deviceLocationName) - { - ResultCode result = ResultCode.UninitializedClock; - - deviceLocationName = null; - - lock (_lock) - { - if (_isInitialized) - { - deviceLocationName = _deviceLocationName; - result = ResultCode.Success; - } - } - - return result; - } - - public ResultCode SetDeviceLocationNameWithTimeZoneRule(string locationName, Stream timeZoneBinaryStream) - { - ResultCode result = ResultCode.TimeZoneConversionFailed; - - lock (_lock) - { - Box<TimeZoneRule> rules = new Box<TimeZoneRule>(); - - bool timeZoneConversionSuccess = TimeZone.ParseTimeZoneBinary(ref rules.Data, timeZoneBinaryStream); - - if (timeZoneConversionSuccess) - { - _deviceLocationName = locationName; - _myRules = rules; - result = ResultCode.Success; - } - } - - return result; - } - - public void SetTotalLocationNameCount(uint totalLocationNameCount) - { - lock (_lock) - { - _totalLocationNameCount = totalLocationNameCount; - } - } - - public ResultCode GetTotalLocationNameCount(out uint totalLocationNameCount) - { - ResultCode result = ResultCode.UninitializedClock; - - totalLocationNameCount = 0; - - lock (_lock) - { - if (_isInitialized) - { - totalLocationNameCount = _totalLocationNameCount; - result = ResultCode.Success; - } - } - - return result; - } - - public ResultCode SetUpdatedTime(SteadyClockTimePoint timeZoneUpdatedTimePoint, bool bypassUninitialized = false) - { - ResultCode result = ResultCode.UninitializedClock; - - lock (_lock) - { - if (_isInitialized || bypassUninitialized) - { - _timeZoneUpdateTimePoint = timeZoneUpdatedTimePoint; - result = ResultCode.Success; - } - } - - return result; - } - - public ResultCode GetUpdatedTime(out SteadyClockTimePoint timeZoneUpdatedTimePoint) - { - ResultCode result; - - lock (_lock) - { - if (_isInitialized) - { - timeZoneUpdatedTimePoint = _timeZoneUpdateTimePoint; - result = ResultCode.Success; - } - else - { - timeZoneUpdatedTimePoint = SteadyClockTimePoint.GetRandom(); - result = ResultCode.UninitializedClock; - } - } - - return result; - } - - public ResultCode ParseTimeZoneRuleBinary(ref TimeZoneRule outRules, Stream timeZoneBinaryStream) - { - ResultCode result = ResultCode.Success; - - lock (_lock) - { - bool timeZoneConversionSuccess = TimeZone.ParseTimeZoneBinary(ref outRules, timeZoneBinaryStream); - - if (!timeZoneConversionSuccess) - { - result = ResultCode.TimeZoneConversionFailed; - } - } - - return result; - } - - public void SetTimeZoneRuleVersion(UInt128 timeZoneRuleVersion) - { - lock (_lock) - { - _timeZoneRuleVersion = timeZoneRuleVersion; - } - } - - public ResultCode GetTimeZoneRuleVersion(out UInt128 timeZoneRuleVersion) - { - ResultCode result; - - lock (_lock) - { - if (_isInitialized) - { - timeZoneRuleVersion = _timeZoneRuleVersion; - result = ResultCode.Success; - } - else - { - timeZoneRuleVersion = new UInt128(); - result = ResultCode.UninitializedClock; - } - } - - return result; - } - - public ResultCode ToCalendarTimeWithMyRules(long time, out CalendarInfo calendar) - { - ResultCode result; - - lock (_lock) - { - if (_isInitialized) - { - result = ToCalendarTime(in _myRules.Data, time, out calendar); - } - else - { - calendar = new CalendarInfo(); - result = ResultCode.UninitializedClock; - } - } - - return result; - } - - public ResultCode ToCalendarTime(in TimeZoneRule rules, long time, out CalendarInfo calendar) - { - ResultCode result; - - lock (_lock) - { - result = TimeZone.ToCalendarTime(in rules, time, out calendar); - } - - return result; - } - - public ResultCode ToPosixTimeWithMyRules(CalendarTime calendarTime, out long posixTime) - { - ResultCode result; - - lock (_lock) - { - if (_isInitialized) - { - result = ToPosixTime(in _myRules.Data, calendarTime, out posixTime); - } - else - { - posixTime = 0; - result = ResultCode.UninitializedClock; - } - } - - return result; - } - - public ResultCode ToPosixTime(in TimeZoneRule rules, CalendarTime calendarTime, out long posixTime) - { - ResultCode result; - - lock (_lock) - { - result = TimeZone.ToPosixTime(in rules, calendarTime, out posixTime); - } - - return result; - } - } -} diff --git a/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/CalendarAdditionalInfo.cs b/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/CalendarAdditionalInfo.cs deleted file mode 100644 index a84a2785..00000000 --- a/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/CalendarAdditionalInfo.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Ryujinx.Common.Memory; -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.HOS.Services.Time.TimeZone -{ - [StructLayout(LayoutKind.Sequential, Pack = 0x4, Size = 0x18, CharSet = CharSet.Ansi)] - struct CalendarAdditionalInfo - { - public uint DayOfWeek; - public uint DayOfYear; - - public Array8<byte> TimezoneName; - - [MarshalAs(UnmanagedType.I1)] - public bool IsDaySavingTime; - - public Array3<byte> Padding; - - public int GmtOffset; - } -}
\ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/CalendarInfo.cs b/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/CalendarInfo.cs deleted file mode 100644 index 68e6245b..00000000 --- a/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/CalendarInfo.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.HOS.Services.Time.TimeZone -{ - [StructLayout(LayoutKind.Sequential, Pack = 0x4, Size = 0x20, CharSet = CharSet.Ansi)] - struct CalendarInfo - { - public CalendarTime Time; - public CalendarAdditionalInfo AdditionalInfo; - } -}
\ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/CalendarTime.cs b/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/CalendarTime.cs deleted file mode 100644 index d594223d..00000000 --- a/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/CalendarTime.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.HOS.Services.Time.TimeZone -{ - [StructLayout(LayoutKind.Sequential, Pack = 0x4, Size = 0x8)] - struct CalendarTime - { - public short Year; - public sbyte Month; - public sbyte Day; - public sbyte Hour; - public sbyte Minute; - public sbyte Second; - } -}
\ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/TimeTypeInfo.cs b/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/TimeTypeInfo.cs deleted file mode 100644 index b8b3d917..00000000 --- a/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/TimeTypeInfo.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Ryujinx.Common.Memory; -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.HOS.Services.Time.TimeZone -{ - [StructLayout(LayoutKind.Sequential, Size = Size, Pack = 4)] - public struct TimeTypeInfo - { - public const int Size = 0x10; - - public int GmtOffset; - - [MarshalAs(UnmanagedType.I1)] - public bool IsDaySavingTime; - - public Array3<byte> Padding1; - - public int AbbreviationListIndex; - - [MarshalAs(UnmanagedType.I1)] - public bool IsStandardTimeDaylight; - - [MarshalAs(UnmanagedType.I1)] - public bool IsGMT; - - public ushort Padding2; - } -}
\ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/TimeZoneRule.cs b/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/TimeZoneRule.cs deleted file mode 100644 index 67237f3d..00000000 --- a/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/TimeZoneRule.cs +++ /dev/null @@ -1,56 +0,0 @@ -using Ryujinx.Common.Utilities; -using System; -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.HOS.Services.Time.TimeZone -{ - [StructLayout(LayoutKind.Sequential, Pack = 4, Size = 0x4000, CharSet = CharSet.Ansi)] - public struct TimeZoneRule - { - public const int TzMaxTypes = 128; - public const int TzMaxChars = 50; - public const int TzMaxLeaps = 50; - public const int TzMaxTimes = 1000; - public const int TzNameMax = 255; - public const int TzCharsArraySize = 2 * (TzNameMax + 1); - - public int TimeCount; - public int TypeCount; - public int CharCount; - - [MarshalAs(UnmanagedType.I1)] - public bool GoBack; - - [MarshalAs(UnmanagedType.I1)] - public bool GoAhead; - - [StructLayout(LayoutKind.Sequential, Size = sizeof(long) * TzMaxTimes)] - private struct AtsStorageStruct { } - - private AtsStorageStruct _ats; - - public Span<long> Ats => SpanHelpers.AsSpan<AtsStorageStruct, long>(ref _ats); - - [StructLayout(LayoutKind.Sequential, Size = sizeof(byte) * TzMaxTimes)] - private struct TypesStorageStruct { } - - private TypesStorageStruct _types; - - public Span<byte> Types => SpanHelpers.AsByteSpan(ref _types); - - [StructLayout(LayoutKind.Sequential, Size = TimeTypeInfo.Size * TzMaxTypes)] - private struct TimeTypeInfoStorageStruct { } - - private TimeTypeInfoStorageStruct _ttis; - - public Span<TimeTypeInfo> Ttis => SpanHelpers.AsSpan<TimeTypeInfoStorageStruct, TimeTypeInfo>(ref _ttis); - - [StructLayout(LayoutKind.Sequential, Size = sizeof(byte) * TzCharsArraySize)] - private struct CharsStorageStruct { } - - private CharsStorageStruct _chars; - public Span<byte> Chars => SpanHelpers.AsByteSpan(ref _chars); - - public int DefaultType; - } -}
\ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/TzifHeader.cs b/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/TzifHeader.cs deleted file mode 100644 index 022c34a9..00000000 --- a/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/TzifHeader.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Ryujinx.Common.Memory; -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.HOS.Services.Time.TimeZone -{ - [StructLayout(LayoutKind.Sequential, Pack = 0x4, Size = 0x2C)] - struct TzifHeader - { - public Array4<byte> Magic; - public byte Version; - private Array15<byte> _reserved; - public int TtisGMTCount; - public int TtisSTDCount; - public int LeapCount; - public int TimeCount; - public int TypeCount; - public int CharCount; - } -}
\ No newline at end of file |
