Implement psc's ITimeZoneService
This commit is contained in:
parent
9fba0659d6
commit
dc95f7535f
4 changed files with 560 additions and 2 deletions
|
@ -0,0 +1,295 @@
|
||||||
|
using ARMeilleure.Memory;
|
||||||
|
using Ryujinx.Common;
|
||||||
|
using Ryujinx.Common.Logging;
|
||||||
|
using Ryujinx.HLE.HOS.Services.Time.Clock;
|
||||||
|
using Ryujinx.HLE.HOS.Services.Time.TimeZone;
|
||||||
|
using Ryujinx.HLE.Utilities;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Services.Time.StaticService
|
||||||
|
{
|
||||||
|
class ITimeZoneServiceForPsc : IpcService
|
||||||
|
{
|
||||||
|
private TimeZoneManagerForPsc _timeZoneManager;
|
||||||
|
private bool _writePermission;
|
||||||
|
|
||||||
|
public ITimeZoneServiceForPsc(TimeZoneManagerForPsc timeZoneManager, bool writePermission)
|
||||||
|
{
|
||||||
|
_timeZoneManager = timeZoneManager;
|
||||||
|
_writePermission = writePermission;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command(0)]
|
||||||
|
// GetDeviceLocationName() -> nn::time::LocationName
|
||||||
|
public ResultCode GetDeviceLocationName(ServiceCtx context)
|
||||||
|
{
|
||||||
|
ResultCode result = _timeZoneManager.GetDeviceLocationName(out string deviceLocationName);
|
||||||
|
|
||||||
|
if (result == ResultCode.Success)
|
||||||
|
{
|
||||||
|
WriteLocationName(context, deviceLocationName);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command(1)]
|
||||||
|
// SetDeviceLocationName(nn::time::LocationName)
|
||||||
|
public ResultCode SetDeviceLocationName(ServiceCtx context)
|
||||||
|
{
|
||||||
|
if (!_writePermission)
|
||||||
|
{
|
||||||
|
return ResultCode.PermissionDenied;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultCode.NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command(2)]
|
||||||
|
// GetTotalLocationNameCount() -> u32
|
||||||
|
public ResultCode GetTotalLocationNameCount(ServiceCtx context)
|
||||||
|
{
|
||||||
|
ResultCode result = _timeZoneManager.GetTotalLocationNameCount(out uint totalLocationNameCount);
|
||||||
|
|
||||||
|
if (result == ResultCode.Success)
|
||||||
|
{
|
||||||
|
context.ResponseData.Write(totalLocationNameCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultCode.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command(3)]
|
||||||
|
// LoadLocationNameList(u32 index) -> (u32 outCount, buffer<nn::time::LocationName, 6>)
|
||||||
|
public ResultCode LoadLocationNameList(ServiceCtx context)
|
||||||
|
{
|
||||||
|
return ResultCode.NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command(4)]
|
||||||
|
// LoadTimeZoneRule(nn::time::LocationName locationName) -> buffer<nn::time::TimeZoneRule, 0x16>
|
||||||
|
public ResultCode LoadTimeZoneRule(ServiceCtx context)
|
||||||
|
{
|
||||||
|
return ResultCode.NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command(5)] // 2.0.0+
|
||||||
|
// GetTimeZoneRuleVersion() -> nn::time::TimeZoneRuleVersion
|
||||||
|
public ResultCode GetTimeZoneRuleVersion(ServiceCtx context)
|
||||||
|
{
|
||||||
|
ResultCode result = _timeZoneManager.GetTimeZoneRuleVersion(out UInt128 timeZoneRuleVersion);
|
||||||
|
|
||||||
|
if (result == ResultCode.Success)
|
||||||
|
{
|
||||||
|
context.ResponseData.WriteStruct(timeZoneRuleVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command(6)] // 5.0.0+
|
||||||
|
// GetDeviceLocationNameAndUpdatedTime() -> (nn::time::LocationName, nn::time::SteadyClockTimePoint)
|
||||||
|
public ResultCode GetDeviceLocationNameAndUpdatedTime(ServiceCtx context)
|
||||||
|
{
|
||||||
|
ResultCode result = _timeZoneManager.GetDeviceLocationName(out string deviceLocationName);
|
||||||
|
|
||||||
|
if (result == ResultCode.Success)
|
||||||
|
{
|
||||||
|
result = _timeZoneManager.GetUpdatedTime(out SteadyClockTimePoint timeZoneUpdateTimePoint);
|
||||||
|
|
||||||
|
if (result == ResultCode.Success)
|
||||||
|
{
|
||||||
|
WriteLocationName(context, deviceLocationName);
|
||||||
|
|
||||||
|
// Skip padding
|
||||||
|
context.ResponseData.BaseStream.Position += 0x4;
|
||||||
|
|
||||||
|
context.ResponseData.WriteStruct(timeZoneUpdateTimePoint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command(7)] // 9.0.0+
|
||||||
|
// SetDeviceLocationNameWithTimeZoneRule(nn::time::LocationName locationName, buffer<nn::time::TimeZoneBinary, 0x21> timeZoneBinary)
|
||||||
|
public ResultCode SetDeviceLocationNameWithTimeZoneRule(ServiceCtx context)
|
||||||
|
{
|
||||||
|
if (!_writePermission)
|
||||||
|
{
|
||||||
|
return ResultCode.PermissionDenied;
|
||||||
|
}
|
||||||
|
|
||||||
|
(long bufferPosition, long bufferSize) = context.Request.GetBufferType0x21();
|
||||||
|
|
||||||
|
string locationName = Encoding.ASCII.GetString(context.RequestData.ReadBytes(0x24)).TrimEnd('\0');
|
||||||
|
|
||||||
|
ResultCode result;
|
||||||
|
|
||||||
|
using (MemoryStream timeZoneBinaryStream = new MemoryStream(context.Memory.ReadBytes(bufferPosition, bufferSize)))
|
||||||
|
{
|
||||||
|
result = _timeZoneManager.SetDeviceLocationNameWithTimeZoneRule(locationName, timeZoneBinaryStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command(8)] // 9.0.0+
|
||||||
|
// ParseTimeZoneBinary(buffer<nn::time::TimeZoneBinary, 0x21> timeZoneBinary) -> buffer<nn::time::TimeZoneRule, 0x16>
|
||||||
|
public ResultCode ParseTimeZoneBinary(ServiceCtx context)
|
||||||
|
{
|
||||||
|
(long bufferPosition, long bufferSize) = context.Request.GetBufferType0x21();
|
||||||
|
|
||||||
|
long timeZoneRuleBufferPosition = context.Request.ReceiveBuff[0].Position;
|
||||||
|
long timeZoneRuleBufferSize = context.Request.ReceiveBuff[0].Size;
|
||||||
|
|
||||||
|
if (timeZoneRuleBufferSize != 0x4000)
|
||||||
|
{
|
||||||
|
// TODO: find error code here
|
||||||
|
Logger.PrintError(LogClass.ServiceTime, $"TimeZoneRule buffer size is 0x{timeZoneRuleBufferSize:x} (expected 0x4000)");
|
||||||
|
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
ResultCode result;
|
||||||
|
|
||||||
|
using (MemoryStream timeZoneBinaryStream = new MemoryStream(context.Memory.ReadBytes(bufferPosition, bufferSize)))
|
||||||
|
{
|
||||||
|
result = _timeZoneManager.ParseTimeZoneRuleBinary(out TimeZoneRule timeZoneRule, timeZoneBinaryStream);
|
||||||
|
|
||||||
|
if (result == ResultCode.Success)
|
||||||
|
{
|
||||||
|
MemoryHelper.Write(context.Memory, timeZoneRuleBufferPosition, timeZoneRule);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command(20)] // 9.0.0+
|
||||||
|
// GetDeviceLocationNameOperationEventReadableHandle() -> handle<copy>
|
||||||
|
public ResultCode GetDeviceLocationNameOperationEventReadableHandle(ServiceCtx context)
|
||||||
|
{
|
||||||
|
return ResultCode.NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command(100)]
|
||||||
|
// ToCalendarTime(nn::time::PosixTime time, buffer<nn::time::TimeZoneRule, 0x15> rules) -> (nn::time::CalendarTime, nn::time::sf::CalendarAdditionalInfo)
|
||||||
|
public ResultCode ToCalendarTime(ServiceCtx context)
|
||||||
|
{
|
||||||
|
long posixTime = context.RequestData.ReadInt64();
|
||||||
|
long bufferPosition = context.Request.SendBuff[0].Position;
|
||||||
|
long bufferSize = context.Request.SendBuff[0].Size;
|
||||||
|
|
||||||
|
if (bufferSize != 0x4000)
|
||||||
|
{
|
||||||
|
// TODO: find error code here
|
||||||
|
Logger.PrintError(LogClass.ServiceTime, $"TimeZoneRule buffer size is 0x{bufferSize:x} (expected 0x4000)");
|
||||||
|
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
TimeZoneRule rules = MemoryHelper.Read<TimeZoneRule>(context.Memory, bufferPosition);
|
||||||
|
|
||||||
|
ResultCode resultCode = TimeZoneManager.ToCalendarTime(rules, posixTime, out CalendarInfo calendar);
|
||||||
|
|
||||||
|
if (resultCode == 0)
|
||||||
|
{
|
||||||
|
context.ResponseData.WriteStruct(calendar);
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command(101)]
|
||||||
|
// ToCalendarTimeWithMyRule(nn::time::PosixTime) -> (nn::time::CalendarTime, nn::time::sf::CalendarAdditionalInfo)
|
||||||
|
public ResultCode ToCalendarTimeWithMyRule(ServiceCtx context)
|
||||||
|
{
|
||||||
|
long posixTime = context.RequestData.ReadInt64();
|
||||||
|
|
||||||
|
ResultCode resultCode = _timeZoneManager.ToCalendarTimeWithMyRules(posixTime, out CalendarInfo calendar);
|
||||||
|
|
||||||
|
if (resultCode == 0)
|
||||||
|
{
|
||||||
|
context.ResponseData.WriteStruct(calendar);
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command(201)]
|
||||||
|
// ToPosixTime(nn::time::CalendarTime calendarTime, buffer<nn::time::TimeZoneRule, 0x15> rules) -> (u32 outCount, buffer<nn::time::PosixTime, 0xa>)
|
||||||
|
public ResultCode ToPosixTime(ServiceCtx context)
|
||||||
|
{
|
||||||
|
long inBufferPosition = context.Request.SendBuff[0].Position;
|
||||||
|
long inBufferSize = context.Request.SendBuff[0].Size;
|
||||||
|
|
||||||
|
CalendarTime calendarTime = context.RequestData.ReadStruct<CalendarTime>();
|
||||||
|
|
||||||
|
if (inBufferSize != 0x4000)
|
||||||
|
{
|
||||||
|
// TODO: find error code here
|
||||||
|
Logger.PrintError(LogClass.ServiceTime, $"TimeZoneRule buffer size is 0x{inBufferSize:x} (expected 0x4000)");
|
||||||
|
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
TimeZoneRule rules = MemoryHelper.Read<TimeZoneRule>(context.Memory, inBufferPosition);
|
||||||
|
|
||||||
|
ResultCode resultCode = TimeZoneManager.ToPosixTime(rules, calendarTime, out long posixTime);
|
||||||
|
|
||||||
|
if (resultCode == 0)
|
||||||
|
{
|
||||||
|
long outBufferPosition = context.Request.RecvListBuff[0].Position;
|
||||||
|
long outBufferSize = context.Request.RecvListBuff[0].Size;
|
||||||
|
|
||||||
|
context.Memory.WriteInt64(outBufferPosition, posixTime);
|
||||||
|
context.ResponseData.Write(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command(202)]
|
||||||
|
// ToPosixTimeWithMyRule(nn::time::CalendarTime calendarTime) -> (u32 outCount, buffer<nn::time::PosixTime, 0xa>)
|
||||||
|
public ResultCode ToPosixTimeWithMyRule(ServiceCtx context)
|
||||||
|
{
|
||||||
|
CalendarTime calendarTime = context.RequestData.ReadStruct<CalendarTime>();
|
||||||
|
|
||||||
|
ResultCode resultCode = _timeZoneManager.ToPosixTimeWithMyRules(calendarTime, out long posixTime);
|
||||||
|
|
||||||
|
if (resultCode == 0)
|
||||||
|
{
|
||||||
|
long outBufferPosition = context.Request.RecvListBuff[0].Position;
|
||||||
|
long outBufferSize = context.Request.RecvListBuff[0].Size;
|
||||||
|
|
||||||
|
context.Memory.WriteInt64(outBufferPosition, posixTime);
|
||||||
|
|
||||||
|
// There could be only one result on one calendar as leap seconds aren't supported.
|
||||||
|
context.ResponseData.Write(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WriteLocationName(ServiceCtx context, string locationName)
|
||||||
|
{
|
||||||
|
char[] locationNameArray = locationName.ToCharArray();
|
||||||
|
|
||||||
|
int padding = 0x24 - locationNameArray.Length;
|
||||||
|
|
||||||
|
Debug.Assert(padding < 0, "LocationName exceeded limit (0x24 bytes)");
|
||||||
|
|
||||||
|
context.ResponseData.Write(locationNameArray);
|
||||||
|
|
||||||
|
for (int index = 0; index < padding; index++)
|
||||||
|
{
|
||||||
|
context.ResponseData.Write((byte)0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -903,7 +903,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
|
||||||
return ParsePosixName(name.ToCharArray(), out outRules, false);
|
return ParsePosixName(name.ToCharArray(), out outRules, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static unsafe bool LoadTimeZoneRules(out TimeZoneRule outRules, Stream inputData)
|
internal static unsafe bool ParseTimeZoneBinary(out TimeZoneRule outRules, Stream inputData)
|
||||||
{
|
{
|
||||||
outRules = new TimeZoneRule
|
outRules = new TimeZoneRule
|
||||||
{
|
{
|
||||||
|
|
|
@ -222,7 +222,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
|
||||||
IFileSystem romfs = nca.OpenFileSystem(NcaSectionType.Data, _device.System.FsIntegrityCheckLevel);
|
IFileSystem romfs = nca.OpenFileSystem(NcaSectionType.Data, _device.System.FsIntegrityCheckLevel);
|
||||||
Stream tzIfStream = romfs.OpenFile($"zoneinfo/{locationName}", OpenMode.Read).AsStream();
|
Stream tzIfStream = romfs.OpenFile($"zoneinfo/{locationName}", OpenMode.Read).AsStream();
|
||||||
|
|
||||||
if (!TimeZone.LoadTimeZoneRules(out outRules, tzIfStream))
|
if (!TimeZone.ParseTimeZoneBinary(out outRules, tzIfStream))
|
||||||
{
|
{
|
||||||
return ResultCode.TimeZoneConversionFailed;
|
return ResultCode.TimeZoneConversionFailed;
|
||||||
}
|
}
|
||||||
|
|
263
Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneManagerForPsc.cs
Normal file
263
Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneManagerForPsc.cs
Normal file
|
@ -0,0 +1,263 @@
|
||||||
|
using Ryujinx.HLE.HOS.Services.Time.Clock;
|
||||||
|
using Ryujinx.HLE.Utilities;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading;
|
||||||
|
using static Ryujinx.HLE.HOS.Services.Time.TimeZone.TimeZoneRule;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
|
||||||
|
{
|
||||||
|
class TimeZoneManagerForPsc
|
||||||
|
{
|
||||||
|
private bool _isInitialized;
|
||||||
|
private TimeZoneRule _myRules;
|
||||||
|
private string _deviceLocationName;
|
||||||
|
private UInt128 _timeZoneRuleVersion;
|
||||||
|
private uint _totalLocationNameCount;
|
||||||
|
private SteadyClockTimePoint _timeZoneUpdateTimePoint;
|
||||||
|
private object _lock;
|
||||||
|
|
||||||
|
public TimeZoneManagerForPsc()
|
||||||
|
{
|
||||||
|
_isInitialized = false;
|
||||||
|
_deviceLocationName = null;
|
||||||
|
_timeZoneRuleVersion = new UInt128();
|
||||||
|
_lock = new object();
|
||||||
|
|
||||||
|
// Empty rules
|
||||||
|
_myRules = new TimeZoneRule
|
||||||
|
{
|
||||||
|
Ats = new long[TzMaxTimes],
|
||||||
|
Types = new byte[TzMaxTimes],
|
||||||
|
Ttis = new TimeTypeInfo[TzMaxTypes],
|
||||||
|
Chars = new char[TzCharsArraySize]
|
||||||
|
};
|
||||||
|
|
||||||
|
_timeZoneUpdateTimePoint = SteadyClockTimePoint.GetRandom();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsInitialized()
|
||||||
|
{
|
||||||
|
return _isInitialized;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void MarkInitialized()
|
||||||
|
{
|
||||||
|
_isInitialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResultCode GetDeviceLocationName(out string deviceLocationName)
|
||||||
|
{
|
||||||
|
ResultCode result = ResultCode.UninitializedClock;
|
||||||
|
|
||||||
|
deviceLocationName = null;
|
||||||
|
|
||||||
|
Monitor.Enter(_lock);
|
||||||
|
|
||||||
|
if (_isInitialized)
|
||||||
|
{
|
||||||
|
deviceLocationName = _deviceLocationName;
|
||||||
|
result = ResultCode.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
Monitor.Exit(_lock);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResultCode SetDeviceLocationNameWithTimeZoneRule(string locationName, Stream timeZoneBinaryStream)
|
||||||
|
{
|
||||||
|
ResultCode result = ResultCode.TimeZoneConversionFailed;
|
||||||
|
|
||||||
|
Monitor.Enter(_lock);
|
||||||
|
|
||||||
|
bool timeZoneConversionSuccess = TimeZone.ParseTimeZoneBinary(out TimeZoneRule rules, timeZoneBinaryStream);
|
||||||
|
|
||||||
|
if (timeZoneConversionSuccess)
|
||||||
|
{
|
||||||
|
_deviceLocationName = locationName;
|
||||||
|
_myRules = rules;
|
||||||
|
result = ResultCode.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
Monitor.Exit(_lock);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetTotalLocationNameCount(uint totalLocationNameCount)
|
||||||
|
{
|
||||||
|
Monitor.Enter(_lock);
|
||||||
|
_totalLocationNameCount = totalLocationNameCount;
|
||||||
|
Monitor.Exit(_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResultCode GetTotalLocationNameCount(out uint totalLocationNameCount)
|
||||||
|
{
|
||||||
|
ResultCode result = ResultCode.UninitializedClock;
|
||||||
|
|
||||||
|
totalLocationNameCount = 0;
|
||||||
|
|
||||||
|
Monitor.Enter(_lock);
|
||||||
|
|
||||||
|
if (_isInitialized)
|
||||||
|
{
|
||||||
|
totalLocationNameCount = _totalLocationNameCount;
|
||||||
|
result = ResultCode.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
Monitor.Exit(_lock);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResultCode SetUpdatedTime(SteadyClockTimePoint timeZoneUpdatedTimePoint)
|
||||||
|
{
|
||||||
|
ResultCode result = ResultCode.UninitializedClock;
|
||||||
|
|
||||||
|
Monitor.Enter(_lock);
|
||||||
|
|
||||||
|
if (_isInitialized)
|
||||||
|
{
|
||||||
|
_timeZoneUpdateTimePoint = timeZoneUpdatedTimePoint;
|
||||||
|
result = ResultCode.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
Monitor.Exit(_lock);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResultCode GetUpdatedTime(out SteadyClockTimePoint timeZoneUpdatedTimePoint)
|
||||||
|
{
|
||||||
|
ResultCode result;
|
||||||
|
|
||||||
|
Monitor.Enter(_lock);
|
||||||
|
|
||||||
|
if (_isInitialized)
|
||||||
|
{
|
||||||
|
timeZoneUpdatedTimePoint = _timeZoneUpdateTimePoint;
|
||||||
|
result = ResultCode.Success;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
timeZoneUpdatedTimePoint = SteadyClockTimePoint.GetRandom();
|
||||||
|
result = ResultCode.UninitializedClock;
|
||||||
|
}
|
||||||
|
|
||||||
|
Monitor.Exit(_lock);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResultCode ParseTimeZoneRuleBinary(out TimeZoneRule outRules, Stream timeZoneBinaryStream)
|
||||||
|
{
|
||||||
|
ResultCode result = ResultCode.Success;
|
||||||
|
|
||||||
|
Monitor.Enter(_lock);
|
||||||
|
|
||||||
|
bool timeZoneConversionSuccess = TimeZone.ParseTimeZoneBinary(out outRules, timeZoneBinaryStream);
|
||||||
|
|
||||||
|
if (!timeZoneConversionSuccess)
|
||||||
|
{
|
||||||
|
result = ResultCode.TimeZoneConversionFailed;
|
||||||
|
}
|
||||||
|
|
||||||
|
Monitor.Exit(_lock);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetTimeZoneRuleVersion(UInt128 timeZoneRuleVersion)
|
||||||
|
{
|
||||||
|
Monitor.Enter(_lock);
|
||||||
|
_timeZoneRuleVersion = timeZoneRuleVersion;
|
||||||
|
Monitor.Exit(_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResultCode GetTimeZoneRuleVersion(out UInt128 timeZoneRuleVersion)
|
||||||
|
{
|
||||||
|
ResultCode result;
|
||||||
|
|
||||||
|
Monitor.Enter(_lock);
|
||||||
|
|
||||||
|
if (_isInitialized)
|
||||||
|
{
|
||||||
|
timeZoneRuleVersion = _timeZoneRuleVersion;
|
||||||
|
result = ResultCode.Success;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
timeZoneRuleVersion = new UInt128();
|
||||||
|
result = ResultCode.UninitializedClock;
|
||||||
|
}
|
||||||
|
|
||||||
|
Monitor.Exit(_lock);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResultCode ToCalendarTimeWithMyRules(long time, out CalendarInfo calendar)
|
||||||
|
{
|
||||||
|
ResultCode result;
|
||||||
|
|
||||||
|
Monitor.Enter(_lock);
|
||||||
|
|
||||||
|
if (_isInitialized)
|
||||||
|
{
|
||||||
|
result = ToCalendarTime(_myRules, time, out calendar);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
calendar = new CalendarInfo();
|
||||||
|
result = ResultCode.UninitializedClock;
|
||||||
|
}
|
||||||
|
|
||||||
|
Monitor.Exit(_lock);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResultCode ToCalendarTime(TimeZoneRule rules, long time, out CalendarInfo calendar)
|
||||||
|
{
|
||||||
|
Monitor.Enter(_lock);
|
||||||
|
|
||||||
|
ResultCode result = TimeZone.ToCalendarTime(rules, time, out calendar);
|
||||||
|
|
||||||
|
Monitor.Exit(_lock);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResultCode ToPosixTimeWithMyRules(CalendarTime calendarTime, out long posixTime)
|
||||||
|
{
|
||||||
|
ResultCode result;
|
||||||
|
|
||||||
|
Monitor.Enter(_lock);
|
||||||
|
|
||||||
|
if (_isInitialized)
|
||||||
|
{
|
||||||
|
result = ToPosixTime(_myRules, calendarTime, out posixTime);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
posixTime = 0;
|
||||||
|
result = ResultCode.UninitializedClock;
|
||||||
|
}
|
||||||
|
|
||||||
|
Monitor.Exit(_lock);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResultCode ToPosixTime(TimeZoneRule rules, CalendarTime calendarTime, out long posixTime)
|
||||||
|
{
|
||||||
|
Monitor.Enter(_lock);
|
||||||
|
|
||||||
|
ResultCode result = TimeZone.ToPosixTime(rules, calendarTime, out posixTime);
|
||||||
|
|
||||||
|
Monitor.Exit(_lock);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue