Merge pull request #4822 from unknownbrackets/rtc

Fix some date conversions in sceRtc
This commit is contained in:
Henrik Rydgård 2013-12-14 01:15:49 -08:00
commit f449d03691
2 changed files with 109 additions and 95 deletions

View file

@ -44,6 +44,10 @@ const u64 rtcMagicOffset = 62135596800000000ULL;
// This is the # of microseconds between January 1, 0001 and January 1, 1601 (for Win32 FILETIME.)
const u64 rtcFiletimeOffset = 50491123200000000ULL;
// 400 years is a convenient number, since leap days and everything cycle every 400 years.
// 400 years is in other words 20871 full weeks.
const u64 rtc400YearTicks = (u64)20871 * 7 * 24 * 3600 * 1000000ULL;
const int PSP_TIME_INVALID_YEAR = -1;
const int PSP_TIME_INVALID_MONTH = -2;
const int PSP_TIME_INVALID_DAY = -3;
@ -153,7 +157,7 @@ void __RtcTmToPspTime(ScePspDateTime &t, tm *val)
void __RtcTicksToPspTime(ScePspDateTime &t, u64 ticks)
{
int numYearAdd = 0;
if(ticks < 1000000ULL)
if (ticks < 1000000ULL)
{
t.year = 1;
t.month = 1;
@ -164,16 +168,18 @@ void __RtcTicksToPspTime(ScePspDateTime &t, u64 ticks)
t.microsecond = ticks % 1000000ULL;
return;
}
else if(ticks < rtcMagicOffset )
else if (ticks < rtcMagicOffset)
{
// Need to get a year past 1970 for gmtime
// Add enough 400 year to pass over 1970.
// Each 400 year are equal
// 400 year is 20871 weeks
u64 ticks400Y = (u64)20871 * 7 * 24 * 3600 * 1000000ULL;
numYearAdd = (int) ((rtcMagicOffset - ticks) / ticks400Y + 1);
ticks += ticks400Y * numYearAdd;
numYearAdd = (int) ((rtcMagicOffset - ticks) / rtc400YearTicks + 1);
ticks += rtc400YearTicks * numYearAdd;
}
while (ticks >= rtcMagicOffset + rtc400YearTicks)
{
ticks -= rtc400YearTicks;
--numYearAdd;
}
time_t time = (ticks - rtcMagicOffset) / 1000000ULL;
@ -207,10 +213,22 @@ u64 __RtcPspTimeToTicks(ScePspDateTime &pt)
local.tm_sec = pt.second;
local.tm_isdst = 0;
s64 tickOffset = 0;
while (local.tm_year < 70)
{
tickOffset -= rtc400YearTicks;
local.tm_year += 400;
}
while (local.tm_year >= 470)
{
tickOffset += rtc400YearTicks;
local.tm_year -= 400;
}
time_t seconds = rtc_timegm(&local);
u64 result = rtcMagicOffset + (u64) seconds * 1000000ULL;
result += pt.microsecond;
return result;
return result + tickOffset;
}
bool __RtcValidatePspTime(ScePspDateTime &t)
@ -369,41 +387,45 @@ u32 sceRtcGetDayOfWeek(u32 year, u32 month, u32 day)
return local.tm_wday;
}
u32 sceRtcGetDaysInMonth(u32 year, u32 month)
bool __RtcIsLeapYear(u32 year)
{
DEBUG_LOG(SCERTC, "sceRtcGetDaysInMonth(%d, %d)", year, month);
u32 numberOfDays;
if (year == 0 || month == 0 || month > 12)
return SCE_KERNEL_ERROR_INVALID_ARGUMENT;
return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
}
int __RtcDaysInMonth(u32 year, u32 month)
{
switch (month)
{
case 4:
case 6:
case 9:
case 11:
numberOfDays = 30;
break;
return 30;
case 2:
if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
numberOfDays = 29;
else
numberOfDays = 28;
break;
if (__RtcIsLeapYear(year))
return 29;
return 28;
default:
numberOfDays = 31;
break;
return 31;
}
}
return numberOfDays;
u32 sceRtcGetDaysInMonth(u32 year, u32 month)
{
DEBUG_LOG(SCERTC, "sceRtcGetDaysInMonth(%d, %d)", year, month);
if (year == 0 || month == 0 || month > 12)
return SCE_KERNEL_ERROR_INVALID_ARGUMENT;
return __RtcDaysInMonth(year, month);
}
u32 sceRtcIsLeapYear(u32 year)
{
DEBUG_LOG(SCERTC, "sceRtcIsLeapYear(%d)", year);
return (year % 4 == 0) && (!(year % 100 == 0) || (year % 400 == 0));
return __RtcIsLeapYear(year) ? 1 : 0;
}
int sceRtcConvertLocalTimeToUTC(u32 tickLocalPtr,u32 tickUTCPtr)
@ -472,19 +494,19 @@ int sceRtcCheckValid(u32 datePtr)
{
return PSP_TIME_INVALID_DAY;
}
else if (pt.day > 31) // TODO: Needs to check actual days in month, including leaps
else if (pt.day > __RtcDaysInMonth((s16)pt.year, (s16)pt.month))
{
return PSP_TIME_INVALID_DAY;
}
else if (pt.hour > 23)
else if (pt.hour < 0 || pt.hour > 23)
{
return PSP_TIME_INVALID_HOUR;
}
else if (pt.minute > 59)
else if (pt.minute < 0 || pt.minute > 59)
{
return PSP_TIME_INVALID_MINUTES;
}
else if (pt.second > 59)
else if (pt.second < 0 || pt.second > 59)
{
return PSP_TIME_INVALID_SECONDS;
}
@ -753,7 +775,7 @@ int sceRtcTickAddHours(u32 destTickPtr, u32 srcTickPtr, int numHours)
if (Memory::IsValidAddress(destTickPtr) && Memory::IsValidAddress(srcTickPtr))
{
s64 srcTick = (s64)Memory::Read_U64(srcTickPtr);
srcTick += numHours*3600000000UL;
srcTick += numHours * 3600ULL * 1000000ULL;
Memory::Write_U64(srcTick, destTickPtr);
}
DEBUG_LOG(SCERTC, "sceRtcTickAddMinutes(%d,%d,%d)", destTickPtr, srcTickPtr, numHours);
@ -766,7 +788,7 @@ int sceRtcTickAddDays(u32 destTickPtr, u32 srcTickPtr, int numDays)
{
s64 srcTick = (s64)Memory::Read_U64(srcTickPtr);
srcTick += numDays*86400000000UL;
srcTick += numDays * 86400ULL * 1000000ULL;
Memory::Write_U64(srcTick, destTickPtr);
}
DEBUG_LOG(SCERTC, "sceRtcTickAddDays(%d,%d,%d)", destTickPtr, srcTickPtr, numDays);
@ -779,7 +801,7 @@ int sceRtcTickAddWeeks(u32 destTickPtr, u32 srcTickPtr, int numWeeks)
{
s64 srcTick = (s64)Memory::Read_U64(srcTickPtr);
srcTick += numWeeks*604800000000UL;
srcTick += numWeeks * 7ULL * 86400ULL * 1000000ULL;
Memory::Write_U64(srcTick, destTickPtr);
}
DEBUG_LOG(SCERTC, "sceRtcTickAddWeeks(%d,%d,%d)", destTickPtr, srcTickPtr, numWeeks);
@ -788,79 +810,69 @@ int sceRtcTickAddWeeks(u32 destTickPtr, u32 srcTickPtr, int numWeeks)
int sceRtcTickAddMonths(u32 destTickPtr, u32 srcTickPtr, int numMonths)
{
if (Memory::IsValidAddress(destTickPtr) && Memory::IsValidAddress(srcTickPtr))
if (!Memory::IsValidAddress(destTickPtr) || !Memory::IsValidAddress(srcTickPtr))
{
u64 srcTick = Memory::Read_U64(srcTickPtr);
ScePspDateTime pt;
memset(&pt, 0, sizeof(pt));
__RtcTicksToPspTime(pt,srcTick);
if(((pt.year-1)*12+pt.month) + numMonths < 1 || ((pt.year-1)*12+pt.month) + numMonths > 9999*12)
{
srcTick = 0;
}
else
{
if(numMonths < 0)
{
pt.year += numMonths/12;
int restMonth = pt.month + numMonths%12;
if(restMonth < 1)
{
pt.month = 12+restMonth;
pt.year--;
}
else
{
pt.month = restMonth;
}
}
else
{
pt.year += numMonths/12;
pt.month += numMonths%12;
if(pt.month > 12)
{
pt.month -= 12;
pt.year++;
}
}
u64 yearTicks = __RtcPspTimeToTicks(pt);
srcTick =yearTicks;
}
Memory::Write_U64(srcTick, destTickPtr);
WARN_LOG(SCERTC, "sceRtcTickAddMonths(%08x, %08x, %d): invalid address", destTickPtr, srcTickPtr, numMonths);
return -1;
}
DEBUG_LOG(SCERTC, "sceRtcTickAddMonths(%d,%d,%d)", destTickPtr, srcTickPtr, numMonths);
u64 srcTick = Memory::Read_U64(srcTickPtr);
ScePspDateTime pt;
memset(&pt, 0, sizeof(pt));
__RtcTicksToPspTime(pt,srcTick);
pt.year += numMonths / 12;
pt.month += numMonths % 12;
if (pt.month < 1)
{
pt.month += 12;
pt.year--;
}
if (pt.month > 12)
{
pt.month -= 12;
pt.year++;
}
if (__RtcValidatePspTime(pt))
{
// Did we land on a year that isn't a leap year?
if (pt.month == 2 && pt.day == 29 && !__RtcIsLeapYear((s16)pt.year))
pt.day = 28;
Memory::Write_U64(__RtcPspTimeToTicks(pt), destTickPtr);
}
DEBUG_LOG(SCERTC, "sceRtcTickAddMonths(%08x, %08x = %lld, %d)", destTickPtr, srcTickPtr, srcTick, numMonths);
return 0;
}
int sceRtcTickAddYears(u32 destTickPtr, u32 srcTickPtr, int numYears)
{
if (Memory::IsValidAddress(destTickPtr) && Memory::IsValidAddress(srcTickPtr))
if (!Memory::IsValidAddress(destTickPtr) || !Memory::IsValidAddress(srcTickPtr))
{
u64 srcTick = Memory::Read_U64(srcTickPtr);
ScePspDateTime pt;
memset(&pt, 0, sizeof(pt));
__RtcTicksToPspTime(pt,srcTick);
if(pt.year + numYears <= 0 || pt.year + numYears > 9999)
{
srcTick = 0;
}
else
{
pt.year += numYears;
u64 yearTicks = __RtcPspTimeToTicks(pt);
srcTick =yearTicks;
}
Memory::Write_U64(srcTick, destTickPtr);
WARN_LOG(SCERTC, "sceRtcTickAddYears(%08x, %08x, %d): invalid address", destTickPtr, srcTickPtr, numYears);
return -1;
}
DEBUG_LOG(SCERTC, "sceRtcTickAddYears(%d,%d,%d)", destTickPtr, srcTickPtr, numYears);
u64 srcTick = Memory::Read_U64(srcTickPtr);
ScePspDateTime pt;
memset(&pt, 0, sizeof(pt));
__RtcTicksToPspTime(pt, srcTick);
pt.year += numYears;
if (__RtcValidatePspTime(pt))
{
// Did we land on a year that isn't a leap year?
if (pt.month == 2 && pt.day == 29 && !__RtcIsLeapYear((s16)pt.year))
pt.day = 28;
Memory::Write_U64(__RtcPspTimeToTicks(pt), destTickPtr);
}
DEBUG_LOG(SCERTC, "sceRtcTickAddYears(%08x, %08x = %lld, %d)", destTickPtr, srcTickPtr, srcTick, numYears);
return 0;
}

View file

@ -337,7 +337,7 @@ def run_tests(test_list, args):
if len(test_filenames):
# TODO: Maybe --compare should detect --graphics?
cmdline = [PPSSPP_EXE, '--compare', '--timeout=' + str(TIMEOUT), '@-']
cmdline.extend([i for i in args if i not in ['-g']])
cmdline.extend([i for i in args if i not in ['-g', '-m']])
c = Command(cmdline, '\n'.join(test_filenames))
c.run(TIMEOUT * len(test_filenames))
@ -364,6 +364,8 @@ def main():
tests = tests_good
else:
tests = tests_next + tests_good
elif '-m' in args:
tests = [i for i in tests_next + tests_good if i.startswith(tests[0])]
run_tests(tests, args)