aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneManager.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneManager.cs')
-rw-r--r--Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneManager.cs349
1 files changed, 164 insertions, 185 deletions
diff --git a/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneManager.cs b/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneManager.cs
index 2497f6a3..1a80365a 100644
--- a/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneManager.cs
+++ b/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneManager.cs
@@ -1,50 +1,28 @@
-using LibHac.Fs;
-using LibHac.Fs.NcaUtils;
-using Ryujinx.Common.Logging;
-using Ryujinx.HLE.FileSystem;
-using System;
-using System.Collections.Generic;
-using System.Collections.ObjectModel;
+using Ryujinx.HLE.HOS.Services.Time.Clock;
+using Ryujinx.HLE.Utilities;
using System.IO;
-using TimeZoneConverter;
-using TimeZoneConverter.Posix;
-
using static Ryujinx.HLE.HOS.Services.Time.TimeZone.TimeZoneRule;
namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
{
- public sealed class TimeZoneManager
+ class TimeZoneManager
{
- private const long TimeZoneBinaryTitleId = 0x010000000000080E;
-
- private static TimeZoneManager instance;
-
- private static object instanceLock = new object();
-
- private Switch _device;
- private TimeZoneRule _myRules;
- private string _deviceLocationName;
- private string[] _locationNameCache;
-
- public static TimeZoneManager Instance
+ private bool _isInitialized;
+ private TimeZoneRule _myRules;
+ private string _deviceLocationName;
+ private UInt128 _timeZoneRuleVersion;
+ private uint _totalLocationNameCount;
+ private SteadyClockTimePoint _timeZoneUpdateTimePoint;
+ private object _lock;
+
+ public TimeZoneManager()
{
- get
- {
- lock (instanceLock)
- {
- if (instance == null)
- {
- instance = new TimeZoneManager();
- }
-
- return instance;
- }
- }
- }
+ _isInitialized = false;
+ _deviceLocationName = "UTC";
+ _timeZoneRuleVersion = new UInt128();
+ _lock = new object();
- TimeZoneManager()
- {
- // Empty rules (UTC)
+ // Empty rules
_myRules = new TimeZoneRule
{
Ats = new long[TzMaxTimes],
@@ -53,236 +31,237 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
Chars = new char[TzCharsArraySize]
};
- _deviceLocationName = "UTC";
+ _timeZoneUpdateTimePoint = SteadyClockTimePoint.GetRandom();
}
- internal void Initialize(Switch device)
+ public bool IsInitialized()
{
- _device = device;
+ bool res;
+
+ lock (_lock)
+ {
+ res = _isInitialized;
+ }
- InitializeLocationNameCache();
+ return res;
}
- private void InitializeLocationNameCache()
+ public void MarkInitialized()
{
- if (HasTimeZoneBinaryTitle())
+ lock (_lock)
{
- using (IStorage ncaFileStream = new LocalStorage(_device.FileSystem.SwitchPathToSystemPath(GetTimeZoneBinaryTitleContentPath()), FileAccess.Read, FileMode.Open))
- {
- Nca nca = new Nca(_device.System.KeySet, ncaFileStream);
- IFileSystem romfs = nca.OpenFileSystem(NcaSectionType.Data, _device.System.FsIntegrityCheckLevel);
- Stream binaryListStream = romfs.OpenFile("binaryList.txt", OpenMode.Read).AsStream();
-
- StreamReader reader = new StreamReader(binaryListStream);
+ _isInitialized = true;
+ }
+ }
- List<string> locationNameList = new List<string>();
+ public ResultCode GetDeviceLocationName(out string deviceLocationName)
+ {
+ ResultCode result = ResultCode.UninitializedClock;
- string locationName;
- while ((locationName = reader.ReadLine()) != null)
- {
- locationNameList.Add(locationName);
- }
+ deviceLocationName = null;
- _locationNameCache = locationNameList.ToArray();
+ lock (_lock)
+ {
+ if (_isInitialized)
+ {
+ deviceLocationName = _deviceLocationName;
+ result = ResultCode.Success;
}
}
- else
- {
- ReadOnlyCollection<TimeZoneInfo> timeZoneInfos = TimeZoneInfo.GetSystemTimeZones();
- _locationNameCache = new string[timeZoneInfos.Count];
- int i = 0;
+ return result;
+ }
- foreach (TimeZoneInfo timeZoneInfo in timeZoneInfos)
- {
- bool needConversion = TZConvert.TryWindowsToIana(timeZoneInfo.Id, out string convertedName);
- if (needConversion)
- {
- _locationNameCache[i] = convertedName;
- }
- else
- {
- _locationNameCache[i] = timeZoneInfo.Id;
- }
- i++;
- }
+ public ResultCode SetDeviceLocationNameWithTimeZoneRule(string locationName, Stream timeZoneBinaryStream)
+ {
+ ResultCode result = ResultCode.TimeZoneConversionFailed;
- // As we aren't using the system archive, "UTC" might not exist on the host system.
- // Load from C# TimeZone APIs UTC id.
- string utcId = TimeZoneInfo.Utc.Id;
- bool utcNeedConversion = TZConvert.TryWindowsToIana(utcId, out string utcConvertedName);
- if (utcNeedConversion)
+ lock (_lock)
+ {
+ bool timeZoneConversionSuccess = TimeZone.ParseTimeZoneBinary(out TimeZoneRule rules, timeZoneBinaryStream);
+
+ if (timeZoneConversionSuccess)
{
- utcId = utcConvertedName;
+ _deviceLocationName = locationName;
+ _myRules = rules;
+ result = ResultCode.Success;
}
+ }
- _deviceLocationName = utcId;
+ return result;
+ }
+
+ public void SetTotalLocationNameCount(uint totalLocationNameCount)
+ {
+ lock (_lock)
+ {
+ _totalLocationNameCount = totalLocationNameCount;
}
}
- private bool IsLocationNameValid(string locationName)
+ public ResultCode GetTotalLocationNameCount(out uint totalLocationNameCount)
{
- foreach (string cachedLocationName in _locationNameCache)
+ ResultCode result = ResultCode.UninitializedClock;
+
+ totalLocationNameCount = 0;
+
+ lock (_lock)
{
- if (cachedLocationName.Equals(locationName))
+ if (_isInitialized)
{
- return true;
+ totalLocationNameCount = _totalLocationNameCount;
+ result = ResultCode.Success;
}
}
- return false;
- }
- public string GetDeviceLocationName()
- {
- return _deviceLocationName;
+ return result;
}
- public ResultCode SetDeviceLocationName(string locationName)
+ public ResultCode SetUpdatedTime(SteadyClockTimePoint timeZoneUpdatedTimePoint, bool bypassUninitialized = false)
{
- ResultCode resultCode = LoadTimeZoneRules(out TimeZoneRule rules, locationName);
+ ResultCode result = ResultCode.UninitializedClock;
- if (resultCode == 0)
+ lock (_lock)
{
- _myRules = rules;
- _deviceLocationName = locationName;
+ if (_isInitialized || bypassUninitialized)
+ {
+ _timeZoneUpdateTimePoint = timeZoneUpdatedTimePoint;
+ result = ResultCode.Success;
+ }
}
- return resultCode;
+ return result;
}
- public ResultCode LoadLocationNameList(uint index, out string[] outLocationNameArray, uint maxLength)
+ public ResultCode GetUpdatedTime(out SteadyClockTimePoint timeZoneUpdatedTimePoint)
{
- List<string> locationNameList = new List<string>();
+ ResultCode result;
- for (int i = 0; i < _locationNameCache.Length && i < maxLength; i++)
+ lock (_lock)
{
- if (i < index)
+ if (_isInitialized)
{
- continue;
+ timeZoneUpdatedTimePoint = _timeZoneUpdateTimePoint;
+ result = ResultCode.Success;
}
-
- string locationName = _locationNameCache[i];
-
- // If the location name is too long, error out.
- if (locationName.Length > 0x24)
+ else
{
- outLocationNameArray = new string[0];
-
- return ResultCode.LocationNameTooLong;
+ timeZoneUpdatedTimePoint = SteadyClockTimePoint.GetRandom();
+ result = ResultCode.UninitializedClock;
}
-
- locationNameList.Add(locationName);
}
- outLocationNameArray = locationNameList.ToArray();
-
- return ResultCode.Success;
+ return result;
}
- public uint GetTotalLocationNameCount()
+ public ResultCode ParseTimeZoneRuleBinary(out TimeZoneRule outRules, Stream timeZoneBinaryStream)
{
- return (uint)_locationNameCache.Length;
- }
+ ResultCode result = ResultCode.Success;
- public string GetTimeZoneBinaryTitleContentPath()
- {
- return _device.System.ContentManager.GetInstalledContentPath(TimeZoneBinaryTitleId, StorageId.NandSystem, ContentType.Data);
- }
+ lock (_lock)
+ {
+ bool timeZoneConversionSuccess = TimeZone.ParseTimeZoneBinary(out outRules, timeZoneBinaryStream);
- public bool HasTimeZoneBinaryTitle()
- {
- return !string.IsNullOrEmpty(GetTimeZoneBinaryTitleContentPath());
+ if (!timeZoneConversionSuccess)
+ {
+ result = ResultCode.TimeZoneConversionFailed;
+ }
+ }
+
+ return result;
}
- internal ResultCode LoadTimeZoneRules(out TimeZoneRule outRules, string locationName)
+ public void SetTimeZoneRuleVersion(UInt128 timeZoneRuleVersion)
{
- outRules = new TimeZoneRule
+ lock (_lock)
{
- Ats = new long[TzMaxTimes],
- Types = new byte[TzMaxTimes],
- Ttis = new TimeTypeInfo[TzMaxTypes],
- Chars = new char[TzCharsArraySize]
- };
-
- if (!IsLocationNameValid(locationName))
- {
- return ResultCode.TimeZoneNotFound;
+ _timeZoneRuleVersion = timeZoneRuleVersion;
}
+ }
+
+ public ResultCode GetTimeZoneRuleVersion(out UInt128 timeZoneRuleVersion)
+ {
+ ResultCode result;
- if (!HasTimeZoneBinaryTitle())
+ lock (_lock)
{
- // If the user doesn't have the system archives, we generate a POSIX rule string and parse it to generate a incomplete TimeZoneRule
- // TODO: As for now not having system archives is fine, we should enforce the usage of system archives later.
- Logger.PrintWarning(LogClass.ServiceTime, "TimeZoneBinary system archive not found! Time conversions will not be accurate!");
- try
+ if (_isInitialized)
{
- TimeZoneInfo info = TZConvert.GetTimeZoneInfo(locationName);
- string posixRule = PosixTimeZone.FromTimeZoneInfo(info);
-
- if (!TimeZone.ParsePosixName(posixRule, out outRules))
- {
- return ResultCode.TimeZoneConversionFailed;
- }
-
- return 0;
+ timeZoneRuleVersion = _timeZoneRuleVersion;
+ result = ResultCode.Success;
}
- catch (TimeZoneNotFoundException)
+ else
{
- Logger.PrintWarning(LogClass.ServiceTime, $"Timezone not found for string: {locationName})");
-
- return ResultCode.TimeZoneNotFound;
+ timeZoneRuleVersion = new UInt128();
+ result = ResultCode.UninitializedClock;
}
}
- else
+
+ return result;
+ }
+
+ public ResultCode ToCalendarTimeWithMyRules(long time, out CalendarInfo calendar)
+ {
+ ResultCode result;
+
+ lock (_lock)
{
- using (IStorage ncaFileStream = new LocalStorage(_device.FileSystem.SwitchPathToSystemPath(GetTimeZoneBinaryTitleContentPath()), FileAccess.Read, FileMode.Open))
+ if (_isInitialized)
{
- Nca nca = new Nca(_device.System.KeySet, ncaFileStream);
- IFileSystem romfs = nca.OpenFileSystem(NcaSectionType.Data, _device.System.FsIntegrityCheckLevel);
- Stream tzIfStream = romfs.OpenFile($"zoneinfo/{locationName}", OpenMode.Read).AsStream();
-
- if (!TimeZone.LoadTimeZoneRules(out outRules, tzIfStream))
- {
- return ResultCode.TimeZoneConversionFailed;
- }
+ result = ToCalendarTime(_myRules, time, out calendar);
+ }
+ else
+ {
+ calendar = new CalendarInfo();
+ result = ResultCode.UninitializedClock;
}
-
- return 0;
}
- }
- internal ResultCode ToCalendarTimeWithMyRules(long time, out CalendarInfo calendar)
- {
- return ToCalendarTime(_myRules, time, out calendar);
+ return result;
}
- internal static ResultCode ToCalendarTime(TimeZoneRule rules, long time, out CalendarInfo calendar)
+ public ResultCode ToCalendarTime(TimeZoneRule rules, long time, out CalendarInfo calendar)
{
- ResultCode error = TimeZone.ToCalendarTime(rules, time, out calendar);
+ ResultCode result;
- if (error != ResultCode.Success)
+ lock (_lock)
{
- return error;
+ result = TimeZone.ToCalendarTime(rules, time, out calendar);
}
- return ResultCode.Success;
+ return result;
}
- internal ResultCode ToPosixTimeWithMyRules(CalendarTime calendarTime, out long posixTime)
+ public ResultCode ToPosixTimeWithMyRules(CalendarTime calendarTime, out long posixTime)
{
- return ToPosixTime(_myRules, calendarTime, out posixTime);
+ ResultCode result;
+
+ lock (_lock)
+ {
+ if (_isInitialized)
+ {
+ result = ToPosixTime(_myRules, calendarTime, out posixTime);
+ }
+ else
+ {
+ posixTime = 0;
+ result = ResultCode.UninitializedClock;
+ }
+ }
+
+ return result;
}
- internal static ResultCode ToPosixTime(TimeZoneRule rules, CalendarTime calendarTime, out long posixTime)
+ public ResultCode ToPosixTime(TimeZoneRule rules, CalendarTime calendarTime, out long posixTime)
{
- ResultCode error = TimeZone.ToPosixTime(rules, calendarTime, out posixTime);
+ ResultCode result;
- if (error != ResultCode.Success)
+ lock (_lock)
{
- return error;
+ result = TimeZone.ToPosixTime(rules, calendarTime, out posixTime);
}
- return ResultCode.Success;
+ return result;
}
}
-} \ No newline at end of file
+}