#ifndef _WIN32 #include <unistd.h> #include <sys/time.h> #if __APPLE__ #include <mach/mach_time.h> #endif #else #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif #include <windows.h> #endif #include <stdio.h> #include <stdarg.h> #include <time.h> #include "CBasics.hpp" #if __APPLE__ static u64 MachToDolphinNum; static u64 MachToDolphinDenom; #elif _WIN32 static LARGE_INTEGER PerfFrequency; #endif namespace urde { void CBasics::Initialize() { #if __APPLE__ mach_timebase_info_data_t timebase; mach_timebase_info(&timebase); MachToDolphinNum = GetGCTicksPerSec() * timebase.numer; MachToDolphinDenom = 1000000000ull * timebase.denom; #elif _WIN32 QueryPerformanceFrequency(&PerfFrequency); #endif } const char* CBasics::Stringize(const char* fmt, ...) { static char STRINGIZE_STR[2048] = {0}; va_list ap; va_start(ap, fmt); vsnprintf(STRINGIZE_STR, 2048, fmt, ap); va_end(ap); return STRINGIZE_STR; } u64 CBasics::GetGCTicks() { #if __APPLE__ return mach_absolute_time() * MachToDolphinNum / MachToDolphinDenom; #elif __linux__ || __FreeBSD__ struct timespec tp; clock_gettime(CLOCK_MONOTONIC, &tp); return u64((tp.tv_sec * 1000000000ull) + tp.tv_nsec) * GetGCTicksPerSec() / 1000000000ull; #elif _WIN32 LARGE_INTEGER perf; QueryPerformanceCounter(&perf); perf.QuadPart *= GetGCTicksPerSec(); perf.QuadPart /= PerfFrequency.QuadPart; return perf.QuadPart; #else return 0; #endif } const u64 CBasics::SECONDS_TO_2000 = 946684800LL; const u64 CBasics::TICKS_PER_SECOND = 60750000LL; #ifndef _WIN32 static struct tm* localtime_r(const time_t& time, struct tm& timeSt, long& gmtOff) { auto ret = ::localtime_r(&time, &timeSt); if (!ret) return nullptr; gmtOff = ret->tm_gmtoff; return ret; } #else static struct tm* localtime_r(const time_t& time, struct tm& timeSt, long& gmtOff) { struct tm _gmSt; auto reta = localtime_s(&timeSt, &time); auto retb = gmtime_s(&_gmSt, &time); if (reta || retb) return nullptr; gmtOff = mktime(&timeSt) - mktime(&_gmSt); return &timeSt; } #endif OSTime CBasics::ToWiiTime(std::chrono::system_clock::time_point time) { auto sec = std::chrono::time_point_cast<std::chrono::seconds>(time); auto us = std::chrono::duration_cast<std::chrono::microseconds>((time - sec)).count(); time_t sysTime = std::chrono::system_clock::to_time_t(sec); struct tm _timeSt; long gmtOff; struct tm* timeSt = localtime_r(sysTime, _timeSt, gmtOff); if (!timeSt) return 0; /* Returning local */ return OSTime(TICKS_PER_SECOND * ((sysTime + gmtOff) - SECONDS_TO_2000) + us * TICKS_PER_SECOND / 1000000); } std::chrono::system_clock::time_point CBasics::FromWiiTime(OSTime wiiTime) { auto div = std::lldiv(SECONDS_TO_2000 + wiiTime, TICKS_PER_SECOND); time_t time = time_t(div.quot); time_t sysTime = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); struct tm _timeSt; long gmtOff; struct tm* timeSt = localtime_r(sysTime, _timeSt, gmtOff); if (!timeSt) return std::chrono::system_clock::from_time_t(0); /* Returning GMT */ return std::chrono::system_clock::from_time_t(time - gmtOff) + std::chrono::microseconds(div.rem * 1000000 / TICKS_PER_SECOND); } OSCalendarTime CBasics::ToCalendarTime(std::chrono::system_clock::time_point time) { OSCalendarTime ret; auto sec = std::chrono::time_point_cast<std::chrono::seconds>(time); auto us = std::chrono::duration_cast<std::chrono::microseconds>((time - sec)).count(); time_t sysTime = std::chrono::system_clock::to_time_t(sec); struct tm _timeSt; long gmtOff; struct tm* timeSt = localtime_r(sysTime, _timeSt, gmtOff); if (!timeSt) return {}; ret.x0_sec = timeSt->tm_sec; ret.x4_min = timeSt->tm_min; ret.x8_hour = timeSt->tm_hour; ret.xc_mday = timeSt->tm_mday; ret.x10_mon = timeSt->tm_mon; ret.x14_year = timeSt->tm_year + 1900; ret.x18_wday = timeSt->tm_wday; ret.x1c_yday = timeSt->tm_yday; auto div = std::ldiv(us, 1000); ret.x20_msec = div.quot; ret.x24_usec = div.rem; return ret; } }