mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2026-02-03 21:16:52 +00:00
1285 lines
38 KiB
C++
1285 lines
38 KiB
C++
// SPDX-FileCopyrightText: Copyright 2024-2026 shadPS4 Emulator Project
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
#include <chrono>
|
|
|
|
#include "common/logging/log.h"
|
|
#include "core/libraries/kernel/kernel.h"
|
|
#include "core/libraries/kernel/process.h"
|
|
#include "core/libraries/kernel/time.h"
|
|
#include "core/libraries/libs.h"
|
|
#include "core/libraries/rtc/rtc.h"
|
|
#include "core/libraries/rtc/rtc_error.h"
|
|
|
|
namespace Libraries::Rtc {
|
|
/*
|
|
* Internal code
|
|
*/
|
|
int _sceRtcTickSubMicroseconds(OrbisRtcTick* pTick0, const OrbisRtcTick* pTick1,
|
|
int64_t lSub) { // FUN_01003270
|
|
if (!pTick0 || !pTick1)
|
|
return ORBIS_RTC_ERROR_INVALID_POINTER;
|
|
|
|
if (lSub == 0) {
|
|
pTick0->tick = pTick1->tick;
|
|
return ORBIS_OK;
|
|
}
|
|
|
|
uint64_t t1 = pTick1->tick;
|
|
|
|
if (lSub < 0) {
|
|
if (t1 < static_cast<uint64_t>(-lSub))
|
|
return ORBIS_RTC_ERROR_INVALID_VALUE;
|
|
} else {
|
|
if ((~t1) < static_cast<uint64_t>(lSub))
|
|
return ORBIS_RTC_ERROR_INVALID_VALUE;
|
|
}
|
|
|
|
t1 += lSub;
|
|
pTick0->tick = t1;
|
|
|
|
return ORBIS_OK;
|
|
}
|
|
|
|
static const int MonthDays[2][13] = {
|
|
{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, // non-leap
|
|
{0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} // leap
|
|
};
|
|
|
|
// Leap-year calculation
|
|
inline bool leap_year(int year) {
|
|
if (year == (((year >> 4) / 19) * 400)) {
|
|
return true;
|
|
} else if (year == (((year >> 2) / 19) * 100)) {
|
|
return false;
|
|
} else {
|
|
return (year & 3) == 0;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Module code
|
|
*/
|
|
int PS4_SYSV_ABI sceRtcCheckValid(OrbisRtcDateTime* pTime) {
|
|
if (pTime == NULL)
|
|
return ORBIS_RTC_ERROR_INVALID_POINTER;
|
|
|
|
uint32_t year = pTime->year;
|
|
|
|
if (year == 0 || year > 9999)
|
|
return ORBIS_RTC_ERROR_INVALID_YEAR;
|
|
|
|
if (pTime->month == 0 || pTime->month > 12)
|
|
return ORBIS_RTC_ERROR_INVALID_MONTH;
|
|
|
|
if (pTime->day == 0)
|
|
return ORBIS_RTC_ERROR_INVALID_DAY;
|
|
|
|
int leap = leap_year(year);
|
|
|
|
if (pTime->day > MonthDays[leap][pTime->month])
|
|
return ORBIS_RTC_ERROR_INVALID_DAY;
|
|
|
|
if (pTime->hour >= 24)
|
|
return ORBIS_RTC_ERROR_INVALID_HOUR;
|
|
|
|
if (pTime->minute >= 60)
|
|
return ORBIS_RTC_ERROR_INVALID_MINUTE;
|
|
|
|
if (pTime->second >= 60)
|
|
return ORBIS_RTC_ERROR_INVALID_SECOND;
|
|
|
|
if (pTime->microsecond >= 1000000)
|
|
return ORBIS_RTC_ERROR_INVALID_MICROSECOND;
|
|
|
|
return ORBIS_OK;
|
|
}
|
|
|
|
int PS4_SYSV_ABI sceRtcCompareTick(OrbisRtcTick* pTick0, OrbisRtcTick* pTick1) {
|
|
if (pTick0 == nullptr || pTick1 == nullptr)
|
|
return ORBIS_RTC_ERROR_INVALID_POINTER;
|
|
|
|
int result = -1;
|
|
|
|
if (pTick1->tick <= pTick0->tick) {
|
|
result = (-((int)(pTick1->tick < pTick0->tick))) & 1;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
int PS4_SYSV_ABI sceRtcConvertLocalTimeToUtc(OrbisRtcTick* pLocalTime, OrbisRtcTick* pUtc) {
|
|
if (pLocalTime == NULL)
|
|
return ORBIS_RTC_ERROR_INVALID_POINTER;
|
|
|
|
time_t utc_time;
|
|
Kernel::OrbisKernelTimezone tz;
|
|
|
|
int result = Kernel::sceKernelConvertLocaltimeToUtc(
|
|
(pLocalTime->tick + 0xFF23400100D44000ULL) / 1000000ULL, 0xFFFFFFFF, &utc_time, &tz, NULL);
|
|
|
|
if (result >= 0) {
|
|
int offset_minutes = tz.tz_dsttime + tz.tz_minuteswest;
|
|
result = sceRtcTickAddMinutes(pUtc, pLocalTime, -offset_minutes);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
int PS4_SYSV_ABI sceRtcConvertUtcToLocalTime(OrbisRtcTick* pTickUtc, OrbisRtcTick* pTickLocal) {
|
|
LOG_TRACE(Lib_Rtc, "called");
|
|
if (pTickUtc == nullptr)
|
|
return ORBIS_RTC_ERROR_INVALID_POINTER;
|
|
|
|
Kernel::OrbisTimesec tsec{};
|
|
time_t local_time{};
|
|
|
|
// Convert PS4 UTC tick → Unix seconds
|
|
uint64_t utc_micro = (pTickUtc->tick + 0xFF23400100D44000ULL) / 1000000ULL;
|
|
s32 result = Kernel::sceKernelConvertUtcToLocaltime(utc_micro, &local_time, &tsec, nullptr);
|
|
if (result < 0)
|
|
return result;
|
|
|
|
// Apply timezone + DST offset
|
|
const int64_t offset_us = ((tsec.dst_sec + tsec.west_sec) / 60) * 60000000LL;
|
|
|
|
return _sceRtcTickSubMicroseconds(pTickLocal, pTickUtc, offset_us);
|
|
}
|
|
|
|
int PS4_SYSV_ABI sceRtcEnd() {
|
|
return ORBIS_OK;
|
|
}
|
|
|
|
int PS4_SYSV_ABI sceRtcFormatRFC2822(char* pszDateTime, const OrbisRtcTick* pTickUtc,
|
|
int iTimeZoneMinutes) {
|
|
LOG_TRACE(Lib_Rtc, "called");
|
|
|
|
if (pszDateTime == nullptr)
|
|
return ORBIS_RTC_ERROR_INVALID_POINTER;
|
|
|
|
OrbisRtcTick formatTick;
|
|
|
|
if (pTickUtc == nullptr) {
|
|
sceRtcGetCurrentTick(&formatTick);
|
|
} else {
|
|
formatTick.tick = pTickUtc->tick;
|
|
}
|
|
|
|
sceRtcTickAddMinutes(&formatTick, &formatTick, iTimeZoneMinutes);
|
|
|
|
OrbisRtcDateTime formatTime;
|
|
sceRtcSetTick(&formatTime, &formatTick);
|
|
|
|
int validTime = sceRtcCheckValid(&formatTime);
|
|
|
|
std::string formattedString;
|
|
|
|
if (validTime >= 0) {
|
|
int weekDay = sceRtcGetDayOfWeek(formatTime.year, formatTime.month, formatTime.day);
|
|
switch (weekDay) {
|
|
case 0:
|
|
formattedString = "Sun, ";
|
|
break;
|
|
case 1:
|
|
formattedString = "Mon, ";
|
|
break;
|
|
case 2:
|
|
formattedString = "Tue, ";
|
|
break;
|
|
case 3:
|
|
formattedString = "Wed, ";
|
|
break;
|
|
case 4:
|
|
formattedString = "Thu, ";
|
|
break;
|
|
case 5:
|
|
formattedString = "Fri, ";
|
|
break;
|
|
case 6:
|
|
formattedString = "Sat, ";
|
|
break;
|
|
}
|
|
|
|
if (formatTime.day < 10) {
|
|
formattedString += "0" + std::to_string(formatTime.day) + " ";
|
|
} else {
|
|
formattedString += std::to_string(formatTime.day) + " ";
|
|
}
|
|
|
|
switch (formatTime.month) {
|
|
case 1:
|
|
formattedString += "Jan ";
|
|
break;
|
|
case 2:
|
|
formattedString += "Feb ";
|
|
break;
|
|
case 3:
|
|
formattedString += "Mar ";
|
|
break;
|
|
case 4:
|
|
formattedString += "Apr ";
|
|
break;
|
|
case 5:
|
|
formattedString += "May ";
|
|
break;
|
|
case 6:
|
|
formattedString += "Jun ";
|
|
break;
|
|
case 7:
|
|
formattedString += "Jul ";
|
|
break;
|
|
case 8:
|
|
formattedString += "Aug ";
|
|
break;
|
|
case 9:
|
|
formattedString += "Sep ";
|
|
break;
|
|
case 10:
|
|
formattedString += "Oct ";
|
|
break;
|
|
case 11:
|
|
formattedString += "Nov ";
|
|
break;
|
|
case 12:
|
|
formattedString += "Dec ";
|
|
break;
|
|
}
|
|
|
|
formattedString += std::to_string(formatTime.year) + " ";
|
|
|
|
if (formatTime.hour < 10) {
|
|
formattedString += "0" + std::to_string(formatTime.hour) + ":";
|
|
} else {
|
|
formattedString += std::to_string(formatTime.hour) + ":";
|
|
}
|
|
|
|
if (formatTime.minute < 10) {
|
|
formattedString += "0" + std::to_string(formatTime.minute) + ":";
|
|
} else {
|
|
formattedString += std::to_string(formatTime.minute) + ":";
|
|
}
|
|
|
|
if (formatTime.second < 10) {
|
|
formattedString += "0" + std::to_string(formatTime.second) + " ";
|
|
} else {
|
|
formattedString += std::to_string(formatTime.second) + " ";
|
|
}
|
|
|
|
if (iTimeZoneMinutes == 0) {
|
|
formattedString += "+0000";
|
|
} else {
|
|
int timeZoneHours = iTimeZoneMinutes / 60;
|
|
int timeZoneRemainder = iTimeZoneMinutes % 60;
|
|
|
|
if (timeZoneHours < 0) {
|
|
formattedString += "-";
|
|
timeZoneHours *= -1;
|
|
} else {
|
|
formattedString += "+";
|
|
}
|
|
|
|
if (timeZoneHours < 10) {
|
|
formattedString += "0" + std::to_string(timeZoneHours);
|
|
} else {
|
|
formattedString += std::to_string(timeZoneHours);
|
|
}
|
|
|
|
if (timeZoneRemainder == 0) {
|
|
formattedString += "00";
|
|
} else {
|
|
if (timeZoneRemainder < 0)
|
|
timeZoneRemainder *= -1;
|
|
formattedString += std::to_string(timeZoneRemainder);
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < formattedString.size() + 1; ++i) {
|
|
pszDateTime[i] = formattedString.c_str()[i];
|
|
}
|
|
}
|
|
|
|
return ORBIS_OK;
|
|
}
|
|
|
|
int PS4_SYSV_ABI sceRtcFormatRFC2822LocalTime(char* pszDateTime, const OrbisRtcTick* pTickUtc) {
|
|
LOG_TRACE(Lib_Rtc, "called");
|
|
|
|
Kernel::OrbisKernelTimezone timeZone;
|
|
Kernel::sceKernelGettimezone(&timeZone);
|
|
|
|
return sceRtcFormatRFC2822(pszDateTime, pTickUtc,
|
|
-(timeZone.tz_minuteswest - (timeZone.tz_dsttime * 60)));
|
|
}
|
|
|
|
int PS4_SYSV_ABI sceRtcFormatRFC3339(char* pszDateTime, const OrbisRtcTick* pTickUtc,
|
|
int iTimeZoneMinutes) {
|
|
LOG_TRACE(Lib_Rtc, "called");
|
|
return sceRtcFormatRFC3339Precise(pszDateTime, pTickUtc, iTimeZoneMinutes);
|
|
}
|
|
|
|
int PS4_SYSV_ABI sceRtcFormatRFC3339LocalTime(char* pszDateTime, const OrbisRtcTick* pTickUtc) {
|
|
LOG_TRACE(Lib_Rtc, "called");
|
|
|
|
Kernel::OrbisKernelTimezone timeZone;
|
|
Kernel::sceKernelGettimezone(&timeZone);
|
|
|
|
return sceRtcFormatRFC3339(pszDateTime, pTickUtc,
|
|
-(timeZone.tz_minuteswest - (timeZone.tz_dsttime * 60)));
|
|
}
|
|
|
|
int PS4_SYSV_ABI sceRtcFormatRFC3339Precise(char* pszDateTime, const OrbisRtcTick* pTickUtc,
|
|
int iTimeZoneMinutes) {
|
|
LOG_TRACE(Lib_Rtc, "called");
|
|
|
|
if (pszDateTime == nullptr)
|
|
return ORBIS_RTC_ERROR_INVALID_POINTER;
|
|
|
|
OrbisRtcTick formatTick;
|
|
|
|
if (pTickUtc == nullptr) {
|
|
sceRtcGetCurrentTick(&formatTick);
|
|
} else {
|
|
formatTick.tick = pTickUtc->tick;
|
|
}
|
|
|
|
sceRtcTickAddMinutes(&formatTick, &formatTick, iTimeZoneMinutes);
|
|
|
|
OrbisRtcDateTime formatTime;
|
|
|
|
sceRtcSetTick(&formatTime, &formatTick);
|
|
|
|
std::string formattedString;
|
|
formattedString = std::to_string(formatTime.year) + "-";
|
|
|
|
if (formatTime.month < 10) {
|
|
formattedString += "0" + std::to_string(formatTime.month) + "-";
|
|
} else {
|
|
formattedString += std::to_string(formatTime.month) + "-";
|
|
}
|
|
|
|
if (formatTime.day < 10) {
|
|
formattedString += "0" + std::to_string(formatTime.day) + "T";
|
|
} else {
|
|
formattedString += std::to_string(formatTime.day) + "T";
|
|
}
|
|
|
|
if (formatTime.hour < 10) {
|
|
formattedString += "0" + std::to_string(formatTime.hour) + ":";
|
|
} else {
|
|
formattedString += std::to_string(formatTime.hour) + ":";
|
|
}
|
|
|
|
if (formatTime.minute < 10) {
|
|
formattedString += "0" + std::to_string(formatTime.minute) + ":";
|
|
} else {
|
|
formattedString += std::to_string(formatTime.minute) + ":";
|
|
}
|
|
|
|
if (formatTime.second < 10) {
|
|
formattedString += "0" + std::to_string(formatTime.second);
|
|
} else {
|
|
formattedString += std::to_string(formatTime.second);
|
|
}
|
|
|
|
if (formatTime.microsecond != 0) {
|
|
formattedString += "." + std::to_string(formatTime.microsecond / 1000).substr(0, 2);
|
|
} else {
|
|
formattedString += ".00";
|
|
}
|
|
|
|
if (iTimeZoneMinutes == 0) {
|
|
formattedString += "Z";
|
|
} else {
|
|
int timeZoneHours = iTimeZoneMinutes / 60;
|
|
int timeZoneRemainder = iTimeZoneMinutes % 60;
|
|
|
|
if (timeZoneHours < 0) {
|
|
formattedString += "-";
|
|
timeZoneHours *= -1;
|
|
} else {
|
|
formattedString += "+";
|
|
}
|
|
|
|
if (timeZoneHours < 10) {
|
|
formattedString += "0" + std::to_string(timeZoneHours);
|
|
} else {
|
|
formattedString += std::to_string(timeZoneHours);
|
|
}
|
|
|
|
if (timeZoneRemainder == 0) {
|
|
formattedString += ":00";
|
|
} else {
|
|
if (timeZoneRemainder < 0)
|
|
timeZoneRemainder *= -1;
|
|
formattedString += ":" + std::to_string(timeZoneRemainder);
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < formattedString.size() + 1; ++i) {
|
|
pszDateTime[i] = formattedString.c_str()[i];
|
|
}
|
|
|
|
return ORBIS_OK;
|
|
}
|
|
|
|
int PS4_SYSV_ABI sceRtcFormatRFC3339PreciseLocalTime(char* pszDateTime,
|
|
const OrbisRtcTick* pTickUtc) {
|
|
LOG_TRACE(Lib_Rtc, "called");
|
|
|
|
Kernel::OrbisKernelTimezone timeZone;
|
|
Kernel::sceKernelGettimezone(&timeZone);
|
|
|
|
return sceRtcFormatRFC3339Precise(pszDateTime, pTickUtc,
|
|
-(timeZone.tz_minuteswest - (timeZone.tz_dsttime * 60)));
|
|
}
|
|
|
|
int PS4_SYSV_ABI sceRtcGetCurrentAdNetworkTick(OrbisRtcTick* pTick) {
|
|
LOG_TRACE(Lib_Rtc, "called");
|
|
|
|
if (pTick == nullptr)
|
|
return ORBIS_RTC_ERROR_INVALID_POINTER;
|
|
|
|
Kernel::OrbisKernelTimespec clocktime;
|
|
int returnValue = Kernel::sceKernelClockGettime(Kernel::ORBIS_CLOCK_REALTIME, &clocktime);
|
|
|
|
if (returnValue == ORBIS_OK) {
|
|
pTick->tick = clocktime.tv_nsec / 1000 + clocktime.tv_sec * 1000000 + UNIX_EPOCH_TICKS;
|
|
} else {
|
|
return ORBIS_RTC_ERROR_NOT_INITIALIZED;
|
|
}
|
|
|
|
return ORBIS_OK;
|
|
}
|
|
|
|
int PS4_SYSV_ABI sceRtcGetCurrentClock(OrbisRtcDateTime* pTime, int timeZone) {
|
|
LOG_TRACE(Lib_Rtc, "called");
|
|
|
|
if (pTime == nullptr)
|
|
return ORBIS_RTC_ERROR_DATETIME_UNINITIALIZED;
|
|
|
|
Kernel::OrbisKernelTimespec clocktime;
|
|
int returnValue = Kernel::sceKernelClockGettime(Kernel::ORBIS_CLOCK_REALTIME, &clocktime);
|
|
|
|
if (returnValue == ORBIS_OK) {
|
|
OrbisRtcTick clockTick;
|
|
clockTick.tick = clocktime.tv_nsec / 1000 + clocktime.tv_sec * 1000000 + UNIX_EPOCH_TICKS;
|
|
|
|
sceRtcTickAddMinutes(&clockTick, &clockTick, timeZone);
|
|
sceRtcSetTick(pTime, &clockTick);
|
|
}
|
|
|
|
return returnValue;
|
|
}
|
|
|
|
int PS4_SYSV_ABI sceRtcGetCurrentClockLocalTime(OrbisRtcDateTime* pTime) {
|
|
LOG_TRACE(Lib_Rtc, "called");
|
|
if (!pTime)
|
|
return ORBIS_RTC_ERROR_INVALID_POINTER;
|
|
|
|
Kernel::OrbisKernelTimespec ts{};
|
|
int result = Kernel::sceKernelClockGettime(Kernel::ORBIS_CLOCK_REALTIME, &ts);
|
|
if (result < 0)
|
|
return result;
|
|
|
|
uint64_t _tick =
|
|
static_cast<uint64_t>(ts.tv_sec) * 1000000ULL + static_cast<uint64_t>(ts.tv_nsec) / 1000ULL;
|
|
uint64_t tick = _tick + UNIX_EPOCH_TICKS;
|
|
|
|
time_t local_time{};
|
|
Kernel::OrbisTimesec tzsec{};
|
|
result = sceKernelConvertUtcToLocaltime(_tick / 1000000ULL, &local_time, &tzsec, nullptr);
|
|
if (result < 0)
|
|
return result;
|
|
|
|
OrbisRtcTick rtcTick{tick};
|
|
|
|
int64_t offset_minutes = static_cast<s32>(tzsec.dst_sec + tzsec.west_sec) / 60;
|
|
result = sceRtcTickAddMinutes(&rtcTick, &rtcTick, offset_minutes);
|
|
if (result < 0)
|
|
return result;
|
|
|
|
result = sceRtcSetTick(pTime, &rtcTick);
|
|
return result;
|
|
}
|
|
|
|
int PS4_SYSV_ABI sceRtcGetCurrentDebugNetworkTick(OrbisRtcTick* pTick) {
|
|
LOG_TRACE(Lib_Rtc, "called");
|
|
|
|
if (pTick == nullptr)
|
|
return ORBIS_RTC_ERROR_INVALID_POINTER;
|
|
|
|
Kernel::OrbisKernelTimespec clocktime;
|
|
int returnValue = Kernel::sceKernelClockGettime(Kernel::ORBIS_CLOCK_REALTIME, &clocktime);
|
|
|
|
if (returnValue == ORBIS_OK) {
|
|
pTick->tick = clocktime.tv_nsec / 1000 + clocktime.tv_sec * 1000000 + UNIX_EPOCH_TICKS;
|
|
} else {
|
|
return ORBIS_RTC_ERROR_NOT_INITIALIZED;
|
|
}
|
|
|
|
return ORBIS_OK;
|
|
}
|
|
|
|
int PS4_SYSV_ABI sceRtcGetCurrentNetworkTick(OrbisRtcTick* pTick) {
|
|
LOG_TRACE(Lib_Rtc, "called");
|
|
|
|
if (pTick == nullptr)
|
|
return ORBIS_RTC_ERROR_INVALID_POINTER;
|
|
|
|
Kernel::OrbisKernelTimespec clocktime;
|
|
int returnValue = Kernel::sceKernelClockGettime(Kernel::ORBIS_CLOCK_REALTIME, &clocktime);
|
|
|
|
if (returnValue == ORBIS_OK) {
|
|
pTick->tick = clocktime.tv_nsec / 1000 + clocktime.tv_sec * 1000000 + UNIX_EPOCH_TICKS;
|
|
} else {
|
|
return ORBIS_RTC_ERROR_NOT_INITIALIZED;
|
|
}
|
|
|
|
return ORBIS_OK;
|
|
}
|
|
|
|
int PS4_SYSV_ABI sceRtcGetCurrentRawNetworkTick(OrbisRtcTick* pTick) {
|
|
LOG_TRACE(Lib_Rtc, "called");
|
|
|
|
if (pTick == nullptr)
|
|
return ORBIS_RTC_ERROR_INVALID_POINTER;
|
|
|
|
Kernel::OrbisKernelTimespec clocktime;
|
|
int returnValue = Kernel::sceKernelClockGettime(Kernel::ORBIS_CLOCK_REALTIME, &clocktime);
|
|
|
|
if (returnValue == ORBIS_OK) {
|
|
pTick->tick = clocktime.tv_nsec / 1000 + clocktime.tv_sec * 1000000 + UNIX_EPOCH_TICKS;
|
|
} else {
|
|
return ORBIS_RTC_ERROR_NOT_INITIALIZED;
|
|
}
|
|
|
|
return ORBIS_OK;
|
|
}
|
|
|
|
int PS4_SYSV_ABI sceRtcGetCurrentTick(OrbisRtcTick* pTick) {
|
|
LOG_TRACE(Lib_Rtc, "called");
|
|
|
|
if (pTick == nullptr)
|
|
return ORBIS_RTC_ERROR_DATETIME_UNINITIALIZED;
|
|
|
|
Kernel::OrbisKernelTimespec clocktime;
|
|
int returnValue = Kernel::sceKernelClockGettime(Kernel::ORBIS_CLOCK_REALTIME, &clocktime);
|
|
|
|
if (returnValue >= 0) {
|
|
pTick->tick = clocktime.tv_nsec / 1000 + clocktime.tv_sec * 1000000 + UNIX_EPOCH_TICKS;
|
|
}
|
|
|
|
return ORBIS_OK;
|
|
}
|
|
|
|
int PS4_SYSV_ABI sceRtcGetDayOfWeek(int year, int month, int day) {
|
|
LOG_TRACE(Lib_Rtc, "called");
|
|
|
|
int sdk_version = 0;
|
|
if (Kernel::sceKernelGetCompiledSdkVersion(&sdk_version) != ORBIS_OK)
|
|
sdk_version = 0;
|
|
|
|
// Year/month validation
|
|
if (sdk_version < 0x3000000) {
|
|
if (year < 1)
|
|
return ORBIS_RTC_ERROR_INVALID_YEAR;
|
|
if (month <= 0 || month > 12)
|
|
return ORBIS_RTC_ERROR_INVALID_MONTH;
|
|
} else {
|
|
if (year < 1 || year > 9999)
|
|
return ORBIS_RTC_ERROR_INVALID_YEAR;
|
|
if (month <= 0 || month > 12)
|
|
return ORBIS_RTC_ERROR_INVALID_MONTH;
|
|
}
|
|
|
|
int daysInMonth = sceRtcGetDaysInMonth(year, month);
|
|
if (day <= 0 || day > daysInMonth)
|
|
return ORBIS_RTC_ERROR_INVALID_DAY;
|
|
|
|
// Zeller's congruence adjustment
|
|
if (month < 3) {
|
|
month += 12;
|
|
year -= 1;
|
|
}
|
|
|
|
int weekday =
|
|
((13 * month + 8) / 5 - (year / 100) + year + (year / 4) + (year / 400) + day) % 7;
|
|
return weekday;
|
|
}
|
|
|
|
int PS4_SYSV_ABI sceRtcGetDaysInMonth(int year, int month) {
|
|
LOG_TRACE(Lib_Rtc, "called");
|
|
|
|
if (year <= 0)
|
|
return ORBIS_RTC_ERROR_INVALID_YEAR;
|
|
if (month <= 0 || month > 12)
|
|
return ORBIS_RTC_ERROR_INVALID_MONTH;
|
|
|
|
bool isLeap = leap_year(year);
|
|
return MonthDays[isLeap ? 1 : 0][month];
|
|
}
|
|
|
|
int PS4_SYSV_ABI sceRtcGetDosTime(OrbisRtcDateTime* pTime, u32* dosTime) {
|
|
LOG_TRACE(Lib_Rtc, "called");
|
|
|
|
if (pTime == nullptr || dosTime == nullptr)
|
|
return ORBIS_RTC_ERROR_INVALID_POINTER;
|
|
|
|
// Check if the RTC time is valid
|
|
int result = sceRtcCheckValid(pTime);
|
|
if (result != ORBIS_OK)
|
|
return result;
|
|
|
|
uint16_t year = pTime->year;
|
|
uint8_t month = pTime->month;
|
|
uint8_t day = pTime->day;
|
|
|
|
if (year < 1980) {
|
|
*dosTime = 0;
|
|
return ORBIS_OK;
|
|
} else if (year < 2108) {
|
|
*dosTime = ((pTime->second >> 1) & 0x1F) | // seconds / 2
|
|
((pTime->minute & 0x3F) << 5) | // minutes
|
|
((pTime->hour & 0x1F) << 11) | // hours
|
|
((((month & 0x0F) * 0x20 + 0x8800 + (year * 0x200)) | (day & 0x1F))
|
|
<< 16); // day/month/year
|
|
return ORBIS_OK;
|
|
} else {
|
|
*dosTime = 0xFF9FBF7D;
|
|
return ORBIS_RTC_ERROR_INVALID_YEAR;
|
|
}
|
|
}
|
|
|
|
int PS4_SYSV_ABI sceRtcGetTick(OrbisRtcDateTime* pTime, OrbisRtcTick* pTick) {
|
|
LOG_TRACE(Lib_Rtc, "called");
|
|
|
|
if (pTime == nullptr || pTick == nullptr)
|
|
return ORBIS_RTC_ERROR_INVALID_POINTER;
|
|
|
|
int isTimeValid = sceRtcCheckValid(pTime);
|
|
if (isTimeValid != 0)
|
|
return isTimeValid;
|
|
|
|
if (pTime->month > 2) {
|
|
pTime->month -= 3;
|
|
} else {
|
|
pTime->month += 9;
|
|
pTime->year -= 1;
|
|
}
|
|
|
|
int c = pTime->year / 100;
|
|
int ya = pTime->year - 100 * c;
|
|
|
|
u64 days;
|
|
u64 msec;
|
|
|
|
days = ((146097 * c) >> 2) + ((1461 * ya) >> 2) + (153 * pTime->month + 2) / 5 + pTime->day;
|
|
days -= 307;
|
|
days *= 86400000000;
|
|
|
|
msec = pTime->hour * 3600000000 + pTime->minute * 60000000 + pTime->second * 1000000 +
|
|
pTime->microsecond;
|
|
|
|
pTick->tick = days + msec;
|
|
|
|
return ORBIS_OK;
|
|
}
|
|
|
|
u32 PS4_SYSV_ABI sceRtcGetTickResolution() {
|
|
LOG_TRACE(Lib_Rtc, "called");
|
|
|
|
return 1000000;
|
|
}
|
|
|
|
int PS4_SYSV_ABI sceRtcGetTime_t(OrbisRtcDateTime* pTime, time_t* llTime) {
|
|
LOG_TRACE(Lib_Rtc, "called");
|
|
|
|
if (pTime == nullptr || llTime == nullptr)
|
|
return ORBIS_RTC_ERROR_INVALID_POINTER;
|
|
|
|
int isValid = sceRtcCheckValid(pTime);
|
|
if (isValid != ORBIS_OK) {
|
|
return isValid;
|
|
}
|
|
|
|
OrbisRtcTick timeTick;
|
|
sceRtcGetTick(pTime, &timeTick);
|
|
|
|
if (timeTick.tick < UNIX_EPOCH_TICKS) {
|
|
*llTime = 0;
|
|
} else {
|
|
*llTime = (timeTick.tick - UNIX_EPOCH_TICKS) / 1000000;
|
|
}
|
|
|
|
return ORBIS_OK;
|
|
}
|
|
|
|
int PS4_SYSV_ABI sceRtcGetWin32FileTime(OrbisRtcDateTime* pTime, uint64_t* ulWin32Time) {
|
|
LOG_TRACE(Lib_Rtc, "called");
|
|
|
|
if (pTime == nullptr || ulWin32Time == nullptr)
|
|
return ORBIS_RTC_ERROR_INVALID_POINTER;
|
|
|
|
int isValid = sceRtcCheckValid(pTime);
|
|
if (isValid != ORBIS_OK) {
|
|
return isValid;
|
|
}
|
|
|
|
OrbisRtcTick timeTick;
|
|
sceRtcGetTick(pTime, &timeTick);
|
|
|
|
if (timeTick.tick < WIN32_FILETIME_EPOCH_TICKS) {
|
|
*ulWin32Time = 0;
|
|
} else {
|
|
*ulWin32Time = (timeTick.tick - WIN32_FILETIME_EPOCH_TICKS) * 10;
|
|
}
|
|
|
|
return ORBIS_OK;
|
|
}
|
|
|
|
int PS4_SYSV_ABI sceRtcInit() {
|
|
return ORBIS_OK;
|
|
}
|
|
|
|
int PS4_SYSV_ABI sceRtcIsLeapYear(int yearInt) {
|
|
LOG_TRACE(Lib_Rtc, "called");
|
|
|
|
if (yearInt < 1)
|
|
return ORBIS_RTC_ERROR_INVALID_YEAR;
|
|
|
|
using namespace std::chrono;
|
|
|
|
year_month_day_last ymdl{year(yearInt) / February / last};
|
|
return (ymdl.day() == 29d);
|
|
}
|
|
|
|
int GetMonthFromString(std::string monthStr) {
|
|
if (monthStr == "Jan")
|
|
return 1;
|
|
|
|
if (monthStr == "Feb")
|
|
return 2;
|
|
|
|
if (monthStr == "Mar")
|
|
return 3;
|
|
|
|
if (monthStr == "Apr")
|
|
return 4;
|
|
|
|
if (monthStr == "May")
|
|
return 5;
|
|
|
|
if (monthStr == "Jun")
|
|
return 6;
|
|
|
|
if (monthStr == "Jul")
|
|
return 7;
|
|
|
|
if (monthStr == "Aug")
|
|
return 8;
|
|
|
|
if (monthStr == "Sep")
|
|
return 9;
|
|
|
|
if (monthStr == "Oct")
|
|
return 10;
|
|
|
|
if (monthStr == "Nov")
|
|
return 11;
|
|
|
|
if (monthStr == "Dec")
|
|
return 12;
|
|
|
|
return 1;
|
|
}
|
|
|
|
int PS4_SYSV_ABI sceRtcParseDateTime(OrbisRtcTick* pTickUtc, const char* pszDateTime) {
|
|
LOG_TRACE(Lib_Rtc, "called");
|
|
|
|
if (pTickUtc == nullptr || pszDateTime == nullptr)
|
|
return ORBIS_RTC_ERROR_INVALID_POINTER;
|
|
|
|
std::string dateTimeString = std::string(pszDateTime);
|
|
|
|
char formatKey = dateTimeString[19];
|
|
OrbisRtcDateTime dateTime;
|
|
|
|
if (formatKey == 'Z' || formatKey == '-' || formatKey == '+' || formatKey == '.') {
|
|
// RFC3339
|
|
sceRtcParseRFC3339(pTickUtc, pszDateTime);
|
|
} else if (formatKey == ':') {
|
|
// RFC2822
|
|
dateTime.day = std::stoi(dateTimeString.substr(5, 2));
|
|
dateTime.month = GetMonthFromString(dateTimeString.substr(8, 3));
|
|
dateTime.year = std::stoi(dateTimeString.substr(12, 4));
|
|
dateTime.hour = std::stoi(dateTimeString.substr(17, 2));
|
|
dateTime.minute = std::stoi(dateTimeString.substr(20, 2));
|
|
dateTime.second = std::stoi(dateTimeString.substr(23, 2));
|
|
dateTime.microsecond = 0;
|
|
|
|
sceRtcGetTick(&dateTime, pTickUtc);
|
|
|
|
if (dateTimeString[26] == '+') {
|
|
int timeZoneOffset = std::stoi(dateTimeString.substr(27, 2)) * 60;
|
|
timeZoneOffset += std::stoi(dateTimeString.substr(29, 2));
|
|
sceRtcTickAddMinutes(pTickUtc, pTickUtc, timeZoneOffset);
|
|
} else if (dateTimeString[26] == '-') {
|
|
int timeZoneOffset = std::stoi(dateTimeString.substr(27, 2)) * 60;
|
|
timeZoneOffset += std::stoi(dateTimeString.substr(29, 2));
|
|
timeZoneOffset *= -1;
|
|
sceRtcTickAddMinutes(pTickUtc, pTickUtc, timeZoneOffset);
|
|
}
|
|
|
|
} else {
|
|
// asctime
|
|
dateTime.month = GetMonthFromString(dateTimeString.substr(4, 3));
|
|
dateTime.day = std::stoi(dateTimeString.substr(8, 2));
|
|
dateTime.hour = std::stoi(dateTimeString.substr(11, 2));
|
|
dateTime.minute = std::stoi(dateTimeString.substr(14, 2));
|
|
dateTime.second = std::stoi(dateTimeString.substr(17, 2));
|
|
dateTime.year = std::stoi(dateTimeString.substr(20, 4));
|
|
dateTime.microsecond = 0;
|
|
|
|
sceRtcGetTick(&dateTime, pTickUtc);
|
|
}
|
|
|
|
return ORBIS_OK;
|
|
}
|
|
|
|
int PS4_SYSV_ABI sceRtcParseRFC3339(OrbisRtcTick* pTickUtc, const char* pszDateTime) {
|
|
LOG_TRACE(Lib_Rtc, "called");
|
|
|
|
if (pTickUtc == nullptr || pszDateTime == nullptr)
|
|
return ORBIS_RTC_ERROR_INVALID_POINTER;
|
|
|
|
std::string dateTimeString = std::string(pszDateTime);
|
|
|
|
OrbisRtcDateTime dateTime;
|
|
dateTime.year = std::stoi(dateTimeString.substr(0, 4));
|
|
dateTime.month = std::stoi(dateTimeString.substr(5, 2));
|
|
dateTime.day = std::stoi(dateTimeString.substr(8, 2));
|
|
dateTime.hour = std::stoi(dateTimeString.substr(11, 2));
|
|
dateTime.minute = std::stoi(dateTimeString.substr(14, 2));
|
|
dateTime.second = std::stoi(dateTimeString.substr(17, 2));
|
|
s32 timezone_pos = 22;
|
|
if (dateTimeString[19] == '.') {
|
|
dateTime.microsecond = std::stoi(dateTimeString.substr(20, 2));
|
|
} else {
|
|
timezone_pos = 19;
|
|
dateTime.microsecond = 0;
|
|
}
|
|
|
|
sceRtcGetTick(&dateTime, pTickUtc);
|
|
|
|
if (dateTimeString[timezone_pos] != 'Z') {
|
|
if (dateTimeString[timezone_pos] == '-') {
|
|
int timeZoneOffset = std::stoi(dateTimeString.substr(timezone_pos + 1, 2)) * 60;
|
|
timeZoneOffset += std::stoi(dateTimeString.substr(timezone_pos + 4, 2));
|
|
timeZoneOffset *= -1;
|
|
sceRtcTickAddMinutes(pTickUtc, pTickUtc, timeZoneOffset);
|
|
} else if (dateTimeString[timezone_pos] == '+') {
|
|
int timeZoneOffset = std::stoi(dateTimeString.substr(timezone_pos + 1, 2)) * 60;
|
|
timeZoneOffset += std::stoi(dateTimeString.substr(timezone_pos + 4, 2));
|
|
sceRtcTickAddMinutes(pTickUtc, pTickUtc, timeZoneOffset);
|
|
}
|
|
}
|
|
|
|
return ORBIS_OK;
|
|
}
|
|
|
|
void PS4_SYSV_ABI sceRtcSetConf(void* p1, void* p2, s32 minuteswest, s32 dsttime) {
|
|
LOG_INFO(Lib_Rtc, "called");
|
|
Kernel::OrbisKernelTimezone tz{minuteswest, dsttime};
|
|
Kernel::sceKernelSettimeofday(0, &tz);
|
|
return;
|
|
}
|
|
|
|
int PS4_SYSV_ABI sceRtcSetCurrentAdNetworkTick(OrbisRtcTick* pTick) {
|
|
LOG_INFO(Lib_Rtc, "called");
|
|
if (UNIX_EPOCH_TICKS >= pTick->tick) {
|
|
return ORBIS_RTC_ERROR_INVALID_VALUE;
|
|
}
|
|
s32 ret = 0;
|
|
if (pTick != nullptr) {
|
|
u64 temp = pTick->tick - UNIX_EPOCH_TICKS;
|
|
Kernel::OrbisKernelTimespec ts(temp / 1000000, temp % 1000000);
|
|
ret = Kernel::posix_clock_settime(ORBIS_RTC_CLOCK_ID_AD_NETWORK, &ts);
|
|
} else {
|
|
ret = Kernel::posix_clock_settime(ORBIS_RTC_CLOCK_ID_AD_NETWORK, nullptr);
|
|
}
|
|
if (ret < 0) {
|
|
return Kernel::ErrnoToSceKernelError(*Kernel::__Error());
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int PS4_SYSV_ABI sceRtcSetCurrentDebugNetworkTick(OrbisRtcTick* pTick) {
|
|
LOG_INFO(Lib_Rtc, "called");
|
|
if (UNIX_EPOCH_TICKS >= pTick->tick) {
|
|
return ORBIS_RTC_ERROR_INVALID_VALUE;
|
|
}
|
|
s32 ret = 0;
|
|
if (pTick != nullptr) {
|
|
u64 temp = pTick->tick - UNIX_EPOCH_TICKS;
|
|
Kernel::OrbisKernelTimespec ts(temp / 1000000, temp % 1000000);
|
|
ret = Kernel::posix_clock_settime(ORBIS_RTC_CLOCK_ID_DEBUG_NETWORK, &ts);
|
|
} else {
|
|
ret = Kernel::posix_clock_settime(ORBIS_RTC_CLOCK_ID_DEBUG_NETWORK, nullptr);
|
|
}
|
|
if (ret < 0) {
|
|
return Kernel::ErrnoToSceKernelError(*Kernel::__Error());
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int PS4_SYSV_ABI sceRtcSetCurrentNetworkTick(OrbisRtcTick* pTick) {
|
|
LOG_INFO(Lib_Rtc, "called");
|
|
if (UNIX_EPOCH_TICKS >= pTick->tick) {
|
|
return ORBIS_RTC_ERROR_INVALID_VALUE;
|
|
}
|
|
s32 ret = 0;
|
|
if (pTick != nullptr) {
|
|
u64 temp = pTick->tick - UNIX_EPOCH_TICKS;
|
|
Kernel::OrbisKernelTimespec ts(temp / 1000000, temp % 1000000);
|
|
ret = Kernel::posix_clock_settime(ORBIS_RTC_CLOCK_ID_NETWORK, &ts);
|
|
} else {
|
|
ret = Kernel::posix_clock_settime(ORBIS_RTC_CLOCK_ID_NETWORK, nullptr);
|
|
}
|
|
if (ret < 0) {
|
|
return Kernel::ErrnoToSceKernelError(*Kernel::__Error());
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int PS4_SYSV_ABI sceRtcSetCurrentTick(OrbisRtcTick* pTick) {
|
|
LOG_INFO(Lib_Rtc, "called");
|
|
if (pTick == nullptr) {
|
|
return ORBIS_RTC_ERROR_INVALID_POINTER;
|
|
}
|
|
if (UNIX_EPOCH_TICKS >= pTick->tick) {
|
|
return ORBIS_RTC_ERROR_INVALID_VALUE;
|
|
}
|
|
s64 temp = pTick->tick - UNIX_EPOCH_TICKS;
|
|
Kernel::OrbisKernelTimeval tv(temp / 1000000, temp % 1000000);
|
|
return Kernel::sceKernelSettimeofday(&tv, nullptr);
|
|
}
|
|
|
|
int PS4_SYSV_ABI sceRtcSetDosTime(OrbisRtcDateTime* pTime, u32 dosTime) {
|
|
LOG_TRACE(Lib_Rtc, "called");
|
|
|
|
if (pTime == nullptr)
|
|
return ORBIS_RTC_ERROR_INVALID_POINTER;
|
|
|
|
pTime->microsecond = 0;
|
|
pTime->second = (dosTime << 1) & 0x3e;
|
|
pTime->minute = (dosTime >> 5) & 0x3f;
|
|
pTime->hour = (dosTime & 0xf800) >> 0xb;
|
|
|
|
int16_t days = dosTime >> 0x10;
|
|
|
|
pTime->day = days & 0x1f;
|
|
pTime->month = (days >> 5) & 0x0f;
|
|
pTime->year = (days >> 9) + 1980;
|
|
return ORBIS_OK;
|
|
}
|
|
|
|
int PS4_SYSV_ABI sceRtcSetTick(OrbisRtcDateTime* pTime, OrbisRtcTick* pTick) {
|
|
LOG_TRACE(Lib_Rtc, "called");
|
|
|
|
if (pTime == nullptr || pTick == nullptr)
|
|
return ORBIS_RTC_ERROR_INVALID_POINTER;
|
|
|
|
u32 ly, ld, lm, j;
|
|
u64 days, msec;
|
|
|
|
days = pTick->tick / 86400000000;
|
|
msec = pTick->tick % 86400000000;
|
|
|
|
days += 307;
|
|
|
|
j = (days << 2) - 1;
|
|
ly = j / 146097;
|
|
|
|
j -= (146097 * ly);
|
|
ld = j >> 2;
|
|
|
|
j = ((ld << 2) + 3) / 1461;
|
|
ld = (((ld << 2) + 7) - 1461 * j) >> 2;
|
|
|
|
lm = (5 * ld - 3) / 153;
|
|
ld = (5 * ld + 2 - 153 * lm) / 5;
|
|
ly = 100 * ly + j;
|
|
|
|
if (lm < 10) {
|
|
lm += 3;
|
|
} else {
|
|
lm -= 9;
|
|
ly++;
|
|
}
|
|
|
|
pTime->year = ly;
|
|
pTime->month = lm;
|
|
pTime->day = ld;
|
|
|
|
pTime->hour = msec / 3600000000;
|
|
msec %= 3600000000;
|
|
pTime->minute = msec / 60000000;
|
|
msec %= 60000000;
|
|
pTime->second = msec / 1000000;
|
|
msec %= 1000000;
|
|
pTime->microsecond = msec;
|
|
|
|
return ORBIS_OK;
|
|
}
|
|
|
|
int PS4_SYSV_ABI sceRtcSetTime_t(OrbisRtcDateTime* pTime, time_t llTime) {
|
|
LOG_TRACE(Lib_Rtc, "called");
|
|
|
|
if (pTime == nullptr)
|
|
return ORBIS_RTC_ERROR_INVALID_POINTER;
|
|
|
|
int sdk_version;
|
|
int sdkResult = Kernel::sceKernelGetCompiledSdkVersion(&sdk_version);
|
|
if (sdkResult != ORBIS_OK) {
|
|
sdk_version = 0;
|
|
}
|
|
|
|
OrbisRtcTick newTick;
|
|
if (sdk_version < 0x3000000) {
|
|
newTick.tick = (llTime & 0xffffffff) * 1000000;
|
|
} else {
|
|
if (llTime < 0) {
|
|
return ORBIS_RTC_ERROR_INVALID_VALUE;
|
|
}
|
|
newTick.tick = llTime * 1000000;
|
|
}
|
|
|
|
newTick.tick += UNIX_EPOCH_TICKS;
|
|
sceRtcSetTick(pTime, &newTick);
|
|
|
|
return ORBIS_OK;
|
|
}
|
|
|
|
int PS4_SYSV_ABI sceRtcSetWin32FileTime(OrbisRtcDateTime* pTime, int64_t ulWin32Time) {
|
|
LOG_TRACE(Lib_Rtc, "called");
|
|
|
|
if (pTime == nullptr)
|
|
return ORBIS_RTC_ERROR_INVALID_POINTER;
|
|
|
|
u64 convertedTime = (ulWin32Time / 10) + WIN32_FILETIME_EPOCH_TICKS;
|
|
|
|
OrbisRtcTick convertedTick;
|
|
convertedTick.tick = convertedTime;
|
|
|
|
sceRtcSetTick(pTime, &convertedTick);
|
|
|
|
return ORBIS_OK;
|
|
}
|
|
|
|
int PS4_SYSV_ABI sceRtcTickAddDays(OrbisRtcTick* pTick1, OrbisRtcTick* pTick2, int32_t lAdd) {
|
|
LOG_TRACE(Lib_Rtc, "called");
|
|
|
|
if (pTick1 == nullptr || pTick2 == nullptr)
|
|
return ORBIS_RTC_ERROR_INVALID_POINTER;
|
|
|
|
pTick1->tick = (lAdd * 86400000000) + pTick2->tick;
|
|
|
|
return ORBIS_OK;
|
|
}
|
|
|
|
int PS4_SYSV_ABI sceRtcTickAddHours(OrbisRtcTick* pTick1, OrbisRtcTick* pTick2, int32_t lAdd) {
|
|
LOG_TRACE(Lib_Rtc, "called");
|
|
|
|
if (pTick1 == nullptr || pTick2 == nullptr)
|
|
return ORBIS_RTC_ERROR_INVALID_POINTER;
|
|
|
|
pTick1->tick = (int64_t(lAdd) * 3600000000LL) + pTick2->tick;
|
|
|
|
return ORBIS_OK;
|
|
}
|
|
|
|
int PS4_SYSV_ABI sceRtcTickAddMicroseconds(OrbisRtcTick* pTick1, OrbisRtcTick* pTick2,
|
|
int64_t lAdd) {
|
|
LOG_TRACE(Lib_Rtc, "called");
|
|
|
|
if (pTick1 == nullptr || pTick2 == nullptr)
|
|
return ORBIS_RTC_ERROR_INVALID_POINTER;
|
|
|
|
pTick1->tick = lAdd + pTick2->tick;
|
|
|
|
return ORBIS_OK;
|
|
}
|
|
|
|
int PS4_SYSV_ABI sceRtcTickAddMinutes(OrbisRtcTick* pTick1, OrbisRtcTick* pTick2, int64_t lAdd) {
|
|
LOG_TRACE(Lib_Rtc, "called");
|
|
|
|
if (!pTick1 || !pTick2)
|
|
return ORBIS_RTC_ERROR_INVALID_POINTER;
|
|
|
|
pTick1->tick = pTick2->tick + (lAdd * 60000000ULL);
|
|
|
|
return ORBIS_OK;
|
|
}
|
|
|
|
int PS4_SYSV_ABI sceRtcTickAddMonths(OrbisRtcTick* pTick1, OrbisRtcTick* pTick2, int32_t lAdd) {
|
|
LOG_TRACE(Lib_Rtc, "called");
|
|
|
|
if (pTick1 == nullptr || pTick2 == nullptr)
|
|
return ORBIS_RTC_ERROR_INVALID_POINTER;
|
|
|
|
if (lAdd == 0) {
|
|
pTick1->tick = pTick2->tick;
|
|
return ORBIS_OK;
|
|
}
|
|
|
|
OrbisRtcDateTime time;
|
|
s64 s;
|
|
s64 tempMonth;
|
|
|
|
sceRtcSetTick(&time, pTick1);
|
|
|
|
if (lAdd >= 0) {
|
|
s = 1;
|
|
} else {
|
|
s = -1;
|
|
}
|
|
|
|
time.year += (lAdd / 12);
|
|
tempMonth = time.month + (lAdd % 12) - 1;
|
|
|
|
if (tempMonth > 11 || tempMonth < 0) {
|
|
tempMonth -= s * 12;
|
|
time.year += s;
|
|
}
|
|
|
|
time.month = tempMonth + 1;
|
|
|
|
using namespace std::chrono;
|
|
year chronoYear = year(time.year);
|
|
month chronoMonth = month(time.month);
|
|
int lastDay =
|
|
static_cast<int>(unsigned(year_month_day_last{chronoYear / chronoMonth / last}.day()));
|
|
|
|
if (time.day > lastDay) {
|
|
time.day = lastDay;
|
|
}
|
|
|
|
int timeIsValid = sceRtcCheckValid(&time);
|
|
if (timeIsValid == ORBIS_OK) {
|
|
sceRtcGetTick(&time, pTick1);
|
|
} else {
|
|
return timeIsValid;
|
|
}
|
|
|
|
return ORBIS_OK;
|
|
}
|
|
|
|
int PS4_SYSV_ABI sceRtcTickAddSeconds(OrbisRtcTick* pTick1, OrbisRtcTick* pTick2, int64_t lAdd) {
|
|
LOG_TRACE(Lib_Rtc, "called");
|
|
|
|
if (pTick1 == nullptr || pTick2 == nullptr)
|
|
return ORBIS_RTC_ERROR_INVALID_POINTER;
|
|
|
|
pTick1->tick = (lAdd * 1000000) + pTick2->tick;
|
|
|
|
return ORBIS_OK;
|
|
}
|
|
|
|
int PS4_SYSV_ABI sceRtcTickAddTicks(OrbisRtcTick* pTick1, OrbisRtcTick* pTick2, int64_t lAdd) {
|
|
LOG_TRACE(Lib_Rtc, "called");
|
|
|
|
if (pTick1 == nullptr || pTick2 == nullptr)
|
|
return ORBIS_RTC_ERROR_INVALID_POINTER;
|
|
|
|
pTick1->tick = lAdd + pTick2->tick;
|
|
|
|
return ORBIS_OK;
|
|
}
|
|
|
|
int PS4_SYSV_ABI sceRtcTickAddWeeks(OrbisRtcTick* pTick1, OrbisRtcTick* pTick2, int32_t lAdd) {
|
|
LOG_TRACE(Lib_Rtc, "called");
|
|
|
|
if (pTick1 == nullptr || pTick2 == nullptr)
|
|
return ORBIS_RTC_ERROR_INVALID_POINTER;
|
|
|
|
pTick1->tick = (int64_t(lAdd) * 604800000000LL) + pTick2->tick;
|
|
|
|
return ORBIS_OK;
|
|
}
|
|
|
|
int PS4_SYSV_ABI sceRtcTickAddYears(OrbisRtcTick* pTick1, OrbisRtcTick* pTick2, int32_t lAdd) {
|
|
LOG_TRACE(Lib_Rtc, "called");
|
|
|
|
if (pTick1 == nullptr || pTick2 == nullptr)
|
|
return ORBIS_RTC_ERROR_INVALID_POINTER;
|
|
|
|
if (lAdd == 0) {
|
|
pTick1->tick = pTick2->tick;
|
|
return ORBIS_OK;
|
|
}
|
|
|
|
OrbisRtcDateTime time{};
|
|
sceRtcSetTick(&time, pTick2);
|
|
|
|
time.year += lAdd;
|
|
|
|
int result = sceRtcCheckValid(&time);
|
|
if (result != ORBIS_OK)
|
|
return result;
|
|
|
|
sceRtcGetTick(&time, pTick1);
|
|
return ORBIS_OK;
|
|
}
|
|
|
|
void RegisterLib(Core::Loader::SymbolsResolver* sym) {
|
|
LIB_FUNCTION("lPEBYdVX0XQ", "libSceRtc", 1, "libSceRtc", sceRtcCheckValid);
|
|
LIB_FUNCTION("fNaZ4DbzHAE", "libSceRtc", 1, "libSceRtc", sceRtcCompareTick);
|
|
LIB_FUNCTION("8Yr143yEnRo", "libSceRtc", 1, "libSceRtc", sceRtcConvertLocalTimeToUtc);
|
|
LIB_FUNCTION("M1TvFst-jrM", "libSceRtc", 1, "libSceRtc", sceRtcConvertUtcToLocalTime);
|
|
LIB_FUNCTION("8SljQx6pDP8", "libSceRtc", 1, "libSceRtc", sceRtcEnd);
|
|
LIB_FUNCTION("eiuobaF-hK4", "libSceRtc", 1, "libSceRtc", sceRtcFormatRFC2822);
|
|
LIB_FUNCTION("AxHBk3eat04", "libSceRtc", 1, "libSceRtc", sceRtcFormatRFC2822LocalTime);
|
|
LIB_FUNCTION("WJ3rqFwymew", "libSceRtc", 1, "libSceRtc", sceRtcFormatRFC3339);
|
|
LIB_FUNCTION("DwuHIlLGW8I", "libSceRtc", 1, "libSceRtc", sceRtcFormatRFC3339LocalTime);
|
|
LIB_FUNCTION("lja0nNPWojg", "libSceRtc", 1, "libSceRtc", sceRtcFormatRFC3339Precise);
|
|
LIB_FUNCTION("tOZ6fwwHZOA", "libSceRtc", 1, "libSceRtc", sceRtcFormatRFC3339PreciseLocalTime);
|
|
LIB_FUNCTION("LN3Zcb72Q0c", "libSceRtc", 1, "libSceRtc", sceRtcGetCurrentAdNetworkTick);
|
|
LIB_FUNCTION("8lfvnRMqwEM", "libSceRtc", 1, "libSceRtc", sceRtcGetCurrentClock);
|
|
LIB_FUNCTION("ZPD1YOKI+Kw", "libSceRtc", 1, "libSceRtc", sceRtcGetCurrentClockLocalTime);
|
|
LIB_FUNCTION("Ot1DE3gif84", "libSceRtc", 1, "libSceRtc", sceRtcGetCurrentDebugNetworkTick);
|
|
LIB_FUNCTION("zO9UL3qIINQ", "libSceRtc", 1, "libSceRtc", sceRtcGetCurrentNetworkTick);
|
|
LIB_FUNCTION("HWxHOdbM-Pg", "libSceRtc", 1, "libSceRtc", sceRtcGetCurrentRawNetworkTick);
|
|
LIB_FUNCTION("18B2NS1y9UU", "libSceRtc", 1, "libSceRtc", sceRtcGetCurrentTick);
|
|
LIB_FUNCTION("CyIK-i4XdgQ", "libSceRtc", 1, "libSceRtc", sceRtcGetDayOfWeek);
|
|
LIB_FUNCTION("3O7Ln8AqJ1o", "libSceRtc", 1, "libSceRtc", sceRtcGetDaysInMonth);
|
|
LIB_FUNCTION("E7AR4o7Ny7E", "libSceRtc", 1, "libSceRtc", sceRtcGetDosTime);
|
|
LIB_FUNCTION("8w-H19ip48I", "libSceRtc", 1, "libSceRtc", sceRtcGetTick);
|
|
LIB_FUNCTION("jMNwqYr4R-k", "libSceRtc", 1, "libSceRtc", sceRtcGetTickResolution);
|
|
LIB_FUNCTION("BtqmpTRXHgk", "libSceRtc", 1, "libSceRtc", sceRtcGetTime_t);
|
|
LIB_FUNCTION("jfRO0uTjtzA", "libSceRtc", 1, "libSceRtc", sceRtcGetWin32FileTime);
|
|
LIB_FUNCTION("LlodCMDbk3o", "libSceRtc", 1, "libSceRtc", sceRtcInit);
|
|
LIB_FUNCTION("Ug8pCwQvh0c", "libSceRtc", 1, "libSceRtc", sceRtcIsLeapYear);
|
|
LIB_FUNCTION("NxEI1KByvCI", "libSceRtc", 1, "libSceRtc", sceRtcParseDateTime);
|
|
LIB_FUNCTION("99bMGglFW3I", "libSceRtc", 1, "libSceRtc", sceRtcParseRFC3339);
|
|
LIB_FUNCTION("fFLgmNUpChg", "libSceRtc", 1, "libSceRtc", sceRtcSetConf);
|
|
LIB_FUNCTION("sV2tK+yOhBU", "libSceRtc", 1, "libSceRtc", sceRtcSetCurrentAdNetworkTick);
|
|
LIB_FUNCTION("VLDUPKmw5L8", "libSceRtc", 1, "libSceRtc", sceRtcSetCurrentDebugNetworkTick);
|
|
LIB_FUNCTION("qhDBtIo+auw", "libSceRtc", 1, "libSceRtc", sceRtcSetCurrentNetworkTick);
|
|
LIB_FUNCTION("d4fHLCGmY80", "libSceRtc", 1, "libSceRtc", sceRtcSetCurrentTick);
|
|
LIB_FUNCTION("aYPCd1cChyg", "libSceRtc", 1, "libSceRtc", sceRtcSetDosTime);
|
|
LIB_FUNCTION("ueega6v3GUw", "libSceRtc", 1, "libSceRtc", sceRtcSetTick);
|
|
LIB_FUNCTION("bDEVVP4bTjQ", "libSceRtc", 1, "libSceRtc", sceRtcSetTime_t);
|
|
LIB_FUNCTION("n5JiAJXsbcs", "libSceRtc", 1, "libSceRtc", sceRtcSetWin32FileTime);
|
|
LIB_FUNCTION("NR1J0N7L2xY", "libSceRtc", 1, "libSceRtc", sceRtcTickAddDays);
|
|
LIB_FUNCTION("MDc5cd8HfCA", "libSceRtc", 1, "libSceRtc", sceRtcTickAddHours);
|
|
LIB_FUNCTION("XPIiw58C+GM", "libSceRtc", 1, "libSceRtc", sceRtcTickAddMicroseconds);
|
|
LIB_FUNCTION("mn-tf4QiFzk", "libSceRtc", 1, "libSceRtc", sceRtcTickAddMinutes);
|
|
LIB_FUNCTION("CL6y9q-XbuQ", "libSceRtc", 1, "libSceRtc", sceRtcTickAddMonths);
|
|
LIB_FUNCTION("07O525HgICs", "libSceRtc", 1, "libSceRtc", sceRtcTickAddSeconds);
|
|
LIB_FUNCTION("AqVMssr52Rc", "libSceRtc", 1, "libSceRtc", sceRtcTickAddTicks);
|
|
LIB_FUNCTION("gI4t194c2W8", "libSceRtc", 1, "libSceRtc", sceRtcTickAddWeeks);
|
|
LIB_FUNCTION("-5y2uJ62qS8", "libSceRtc", 1, "libSceRtc", sceRtcTickAddYears);
|
|
};
|
|
|
|
} // namespace Libraries::Rtc
|