diff options
Diffstat (limited to 'Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneManager.cs')
-rw-r--r-- | Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneManager.cs | 349 |
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 +} |