Compare commits
7 Commits
__refs_pul
...
__refs_pul
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bc699ace15 | ||
|
|
f7d59f3e0e | ||
|
|
2c67bbf609 | ||
|
|
5692c48ab7 | ||
|
|
80b4bd3583 | ||
|
|
22263ccaa4 | ||
|
|
ef8acc9c3d |
@@ -7,7 +7,7 @@ if grep -nrI '\s$' src *.yml *.txt *.md Doxyfile .gitignore .gitmodules .ci* dis
|
||||
fi
|
||||
|
||||
# Default clang-format points to default 3.5 version one
|
||||
CLANG_FORMAT=clang-format-10
|
||||
CLANG_FORMAT=clang-format-6.0
|
||||
$CLANG_FORMAT --version
|
||||
|
||||
if [ "$TRAVIS_EVENT_TYPE" = "pull_request" ]; then
|
||||
|
||||
@@ -7,7 +7,7 @@ if grep -nrI '\s$' src *.yml *.txt *.md Doxyfile .gitignore .gitmodules .travis*
|
||||
fi
|
||||
|
||||
# Default clang-format points to default 3.5 version one
|
||||
CLANG_FORMAT=clang-format-10.0
|
||||
CLANG_FORMAT=clang-format-6.0
|
||||
$CLANG_FORMAT --version
|
||||
|
||||
if [ "$TRAVIS_EVENT_TYPE" = "pull_request" ]; then
|
||||
|
||||
@@ -159,15 +159,15 @@ macro(yuzu_find_packages)
|
||||
# Capitalization matters here. We need the naming to match the generated paths from Conan
|
||||
set(REQUIRED_LIBS
|
||||
# Cmake Pkg Prefix Version Conan Pkg
|
||||
"Boost 1.73 boost/1.73.0"
|
||||
"Catch2 2.13 catch2/2.13.0"
|
||||
"fmt 7.0 fmt/7.0.3"
|
||||
"Boost 1.71 boost/1.72.0"
|
||||
"Catch2 2.11 catch2/2.11.0"
|
||||
"fmt 7.0 fmt/7.0.1"
|
||||
# can't use until https://github.com/bincrafters/community/issues/1173
|
||||
#"libzip 1.5 libzip/1.5.2@bincrafters/stable"
|
||||
"lz4 1.8 lz4/1.9.2"
|
||||
"nlohmann_json 3.8 nlohmann_json/3.8.0"
|
||||
"nlohmann_json 3.7 nlohmann_json/3.7.3"
|
||||
"ZLIB 1.2 zlib/1.2.11"
|
||||
"zstd 1.4 zstd/1.4.5"
|
||||
"zstd 1.4 zstd/1.4.4"
|
||||
)
|
||||
|
||||
foreach(PACKAGE ${REQUIRED_LIBS})
|
||||
@@ -456,7 +456,7 @@ endif()
|
||||
# against all the src files. This should be used before making a pull request.
|
||||
# =======================================================================
|
||||
|
||||
set(CLANG_FORMAT_POSTFIX "-10")
|
||||
set(CLANG_FORMAT_POSTFIX "-6.0")
|
||||
find_program(CLANG_FORMAT
|
||||
NAMES clang-format${CLANG_FORMAT_POSTFIX}
|
||||
clang-format
|
||||
|
||||
2
externals/dynarmic
vendored
2
externals/dynarmic
vendored
Submodule externals/dynarmic updated: 0e1112b7df...82417da780
57
externals/microprofile/microprofile.h
vendored
57
externals/microprofile/microprofile.h
vendored
@@ -152,11 +152,9 @@ typedef uint16_t MicroProfileGroupId;
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <atomic>
|
||||
|
||||
#ifndef MICROPROFILE_API
|
||||
#define MICROPROFILE_API
|
||||
@@ -607,45 +605,28 @@ struct MicroProfileFrameState
|
||||
|
||||
struct MicroProfileThreadLog
|
||||
{
|
||||
std::array<MicroProfileLogEntry, MICROPROFILE_BUFFER_SIZE> Log{};
|
||||
MicroProfileLogEntry Log[MICROPROFILE_BUFFER_SIZE];
|
||||
|
||||
std::atomic<uint32_t> nPut{0};
|
||||
std::atomic<uint32_t> nGet{0};
|
||||
uint32_t nActive = 0;
|
||||
uint32_t nGpu = 0;
|
||||
ThreadIdType nThreadId{};
|
||||
std::atomic<uint32_t> nPut;
|
||||
std::atomic<uint32_t> nGet;
|
||||
uint32_t nActive;
|
||||
uint32_t nGpu;
|
||||
ThreadIdType nThreadId;
|
||||
|
||||
std::array<uint32_t, MICROPROFILE_STACK_MAX> nStack{};
|
||||
std::array<int64_t, MICROPROFILE_STACK_MAX> nChildTickStack{};
|
||||
uint32_t nStackPos = 0;
|
||||
uint32_t nStack[MICROPROFILE_STACK_MAX];
|
||||
int64_t nChildTickStack[MICROPROFILE_STACK_MAX];
|
||||
uint32_t nStackPos;
|
||||
|
||||
|
||||
std::array<uint8_t, MICROPROFILE_MAX_GROUPS> nGroupStackPos{};
|
||||
std::array<int64_t, MICROPROFILE_MAX_GROUPS> nGroupTicks{};
|
||||
std::array<int64_t, MICROPROFILE_MAX_GROUPS> nAggregateGroupTicks{};
|
||||
uint8_t nGroupStackPos[MICROPROFILE_MAX_GROUPS];
|
||||
int64_t nGroupTicks[MICROPROFILE_MAX_GROUPS];
|
||||
int64_t nAggregateGroupTicks[MICROPROFILE_MAX_GROUPS];
|
||||
enum
|
||||
{
|
||||
THREAD_MAX_LEN = 64,
|
||||
};
|
||||
char ThreadName[64]{};
|
||||
int nFreeListNext = 0;
|
||||
|
||||
void Reset() {
|
||||
Log.fill({});
|
||||
nPut = 0;
|
||||
nGet = 0;
|
||||
nActive = 0;
|
||||
nGpu = 0;
|
||||
nThreadId = {};
|
||||
nStack.fill(0);
|
||||
nChildTickStack.fill(0);
|
||||
nStackPos = 0;
|
||||
nGroupStackPos.fill(0);
|
||||
nGroupTicks.fill(0);
|
||||
nAggregateGroupTicks.fill(0);
|
||||
std::fill(std::begin(ThreadName), std::end(ThreadName), '\0');
|
||||
nFreeListNext = 0;
|
||||
}
|
||||
char ThreadName[64];
|
||||
int nFreeListNext;
|
||||
};
|
||||
|
||||
#if MICROPROFILE_GPU_TIMERS_D3D11
|
||||
@@ -1170,7 +1151,6 @@ MicroProfileThreadLog* MicroProfileCreateThreadLog(const char* pName)
|
||||
MP_ASSERT(pLog->nPut.load() == 0);
|
||||
MP_ASSERT(pLog->nGet.load() == 0);
|
||||
S.nFreeListHead = S.Pool[S.nFreeListHead]->nFreeListNext;
|
||||
pLog->Reset();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1178,6 +1158,7 @@ MicroProfileThreadLog* MicroProfileCreateThreadLog(const char* pName)
|
||||
S.nMemUsage += sizeof(MicroProfileThreadLog);
|
||||
S.Pool[S.nNumLogs++] = pLog;
|
||||
}
|
||||
memset(pLog, 0, sizeof(*pLog));
|
||||
int len = (int)strlen(pName);
|
||||
int maxlen = sizeof(pLog->ThreadName)-1;
|
||||
len = len < maxlen ? len : maxlen;
|
||||
@@ -1225,8 +1206,8 @@ void MicroProfileOnThreadExit()
|
||||
{
|
||||
S.Frames[i].nLogStart[nLogIndex] = 0;
|
||||
}
|
||||
pLog->nGroupStackPos.fill(0);
|
||||
pLog->nGroupTicks.fill(0);
|
||||
memset(pLog->nGroupStackPos, 0, sizeof(pLog->nGroupStackPos));
|
||||
memset(pLog->nGroupTicks, 0, sizeof(pLog->nGroupTicks));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
212
externals/microprofile/microprofileui.h
vendored
212
externals/microprofile/microprofileui.h
vendored
@@ -169,13 +169,14 @@ MICROPROFILEUI_API void MicroProfileCustomGroup(const char* pCustomName, uint32_
|
||||
MICROPROFILEUI_API void MicroProfileCustomGroupAddTimer(const char* pCustomName, const char* pGroup, const char* pTimer);
|
||||
|
||||
#ifdef MICROPROFILEUI_IMPL
|
||||
#include <inttypes.h>
|
||||
#ifdef _WIN32
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <math.h>
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
|
||||
MICROPROFILE_DEFINE(g_MicroProfileDetailed, "MicroProfile", "Detailed View", 0x8888000);
|
||||
MICROPROFILE_DEFINE(g_MicroProfileDrawGraph, "MicroProfile", "Draw Graph", 0xff44ee00);
|
||||
@@ -226,10 +227,10 @@ struct SOptionDesc
|
||||
uint8_t nIndex;
|
||||
bool bSelected;
|
||||
};
|
||||
static const std::array<uint32_t, 6> g_MicroProfileAggregatePresets{0, 10, 20, 30, 60, 120};
|
||||
static const std::array<float, 10> g_MicroProfileReferenceTimePresets{5.f, 10.f, 15.f,20.f, 33.33f, 66.66f, 100.f, 250.f, 500.f, 1000.f};
|
||||
static const std::array<uint32_t, 4> g_MicroProfileOpacityPresets{0x40, 0x80, 0xc0, 0xff};
|
||||
static const std::array<const char*, 7> g_MicroProfilePresetNames
|
||||
static uint32_t g_MicroProfileAggregatePresets[] = {0, 10, 20, 30, 60, 120};
|
||||
static float g_MicroProfileReferenceTimePresets[] = {5.f, 10.f, 15.f,20.f, 33.33f, 66.66f, 100.f, 250.f, 500.f, 1000.f};
|
||||
static uint32_t g_MicroProfileOpacityPresets[] = {0x40, 0x80, 0xc0, 0xff};
|
||||
static const char* g_MicroProfilePresetNames[] =
|
||||
{
|
||||
MICROPROFILE_DEFAULT_PRESET,
|
||||
"Render",
|
||||
@@ -242,8 +243,8 @@ static const std::array<const char*, 7> g_MicroProfilePresetNames
|
||||
|
||||
enum
|
||||
{
|
||||
MICROPROFILE_NUM_REFERENCE_PRESETS = g_MicroProfileReferenceTimePresets.size(),
|
||||
MICROPROFILE_NUM_OPACITY_PRESETS = g_MicroProfileOpacityPresets.size(),
|
||||
MICROPROFILE_NUM_REFERENCE_PRESETS = sizeof(g_MicroProfileReferenceTimePresets)/sizeof(g_MicroProfileReferenceTimePresets[0]),
|
||||
MICROPROFILE_NUM_OPACITY_PRESETS = sizeof(g_MicroProfileOpacityPresets)/sizeof(g_MicroProfileOpacityPresets[0]),
|
||||
#if MICROPROFILE_CONTEXT_SWITCH_TRACE
|
||||
MICROPROFILE_OPTION_SIZE = MICROPROFILE_NUM_REFERENCE_PRESETS + MICROPROFILE_NUM_OPACITY_PRESETS * 2 + 2 + 7,
|
||||
#else
|
||||
@@ -325,9 +326,9 @@ struct MicroProfileUI
|
||||
|
||||
MicroProfileUI g_MicroProfileUI;
|
||||
#define UI g_MicroProfileUI
|
||||
static const std::array<uint32_t, 2> g_nMicroProfileBackColors{ 0x474747, 0x313131 };
|
||||
static uint32_t g_nMicroProfileBackColors[2] = { 0x474747, 0x313131 };
|
||||
#define MICROPROFILE_NUM_CONTEXT_SWITCH_COLORS 16
|
||||
static const std::array<uint32_t, MICROPROFILE_NUM_CONTEXT_SWITCH_COLORS> g_nMicroProfileContextSwitchThreadColors //palette generated by http://tools.medialab.sciences-po.fr/iwanthue/index.php
|
||||
static uint32_t g_nMicroProfileContextSwitchThreadColors[MICROPROFILE_NUM_CONTEXT_SWITCH_COLORS] = //palette generated by http://tools.medialab.sciences-po.fr/iwanthue/index.php
|
||||
{
|
||||
0x63607B,
|
||||
0x755E2B,
|
||||
@@ -355,7 +356,7 @@ void MicroProfileInitUI()
|
||||
{
|
||||
bInitialized = true;
|
||||
memset(&g_MicroProfileUI, 0, sizeof(g_MicroProfileUI));
|
||||
UI.nActiveMenu = UINT32_MAX;
|
||||
UI.nActiveMenu = (uint32_t)-1;
|
||||
UI.fDetailedOffsetTarget = UI.fDetailedOffset = 0.f;
|
||||
UI.fDetailedRangeTarget = UI.fDetailedRange = 50.f;
|
||||
|
||||
@@ -367,7 +368,7 @@ void MicroProfileInitUI()
|
||||
UI.nWidth = 100;
|
||||
UI.nHeight = 100;
|
||||
|
||||
UI.nCustomActive = UINT32_MAX;
|
||||
UI.nCustomActive = (uint32_t)-1;
|
||||
UI.nCustomTimerCount = 0;
|
||||
UI.nCustomCount = 0;
|
||||
|
||||
@@ -497,8 +498,8 @@ inline void MicroProfileDrawFloatWindow(uint32_t nX, uint32_t nY, const char** p
|
||||
{
|
||||
MicroProfileDrawBox(nX-MICROPROFILE_TEXT_WIDTH, nY, nX, nY + MICROPROFILE_TEXT_WIDTH, pColors[i]|0xff000000);
|
||||
}
|
||||
MicroProfileDrawText(nX + 1, nY + 1, UINT32_MAX, ppStrings[i0], (uint32_t)strlen(ppStrings[i0]));
|
||||
MicroProfileDrawText(nX + nWidth - nStringLengths[i0+1] * (MICROPROFILE_TEXT_WIDTH+1), nY + 1, UINT32_MAX, ppStrings[i0+1], (uint32_t)strlen(ppStrings[i0+1]));
|
||||
MicroProfileDrawText(nX + 1, nY + 1, (uint32_t)-1, ppStrings[i0], (uint32_t)strlen(ppStrings[i0]));
|
||||
MicroProfileDrawText(nX + nWidth - nStringLengths[i0+1] * (MICROPROFILE_TEXT_WIDTH+1), nY + 1, (uint32_t)-1, ppStrings[i0+1], (uint32_t)strlen(ppStrings[i0+1]));
|
||||
nY += (MICROPROFILE_TEXT_HEIGHT+1);
|
||||
}
|
||||
}
|
||||
@@ -521,7 +522,7 @@ inline void MicroProfileDrawTextBox(uint32_t nX, uint32_t nY, const char** ppStr
|
||||
MicroProfileDrawBox(nX, nY, nX + nWidth, nY + nHeight, 0xff000000);
|
||||
for(uint32_t i = 0; i < nNumStrings; ++i)
|
||||
{
|
||||
MicroProfileDrawText(nX + 1, nY + 1, UINT32_MAX, ppStrings[i], (uint32_t)strlen(ppStrings[i]));
|
||||
MicroProfileDrawText(nX + 1, nY + 1, (uint32_t)-1, ppStrings[i], (uint32_t)strlen(ppStrings[i]));
|
||||
nY += (MICROPROFILE_TEXT_HEIGHT+1);
|
||||
}
|
||||
}
|
||||
@@ -780,7 +781,7 @@ inline void MicroProfileDrawDetailedContextSwitchBars(uint32_t nY, uint32_t nThr
|
||||
{
|
||||
MicroProfile& S = *MicroProfileGet();
|
||||
int64_t nTickIn = -1;
|
||||
uint32_t nThreadBefore = UINT32_MAX;
|
||||
uint32_t nThreadBefore = -1;
|
||||
float fToMs = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondCpu());
|
||||
float fMsToScreen = UI.nWidth / UI.fDetailedRange;
|
||||
float fMouseX = (float)UI.nMouseX;
|
||||
@@ -948,10 +949,10 @@ inline void MicroProfileDrawDetailedBars(uint32_t nWidth, uint32_t nHeight, int
|
||||
|
||||
uint32_t nContextSwitchHoverThreadAfter = S.nContextSwitchHoverThreadAfter;
|
||||
uint32_t nContextSwitchHoverThreadBefore = S.nContextSwitchHoverThreadBefore;
|
||||
S.nContextSwitchHoverThread = S.nContextSwitchHoverThreadAfter = S.nContextSwitchHoverThreadBefore = UINT32_MAX;
|
||||
S.nContextSwitchHoverThread = S.nContextSwitchHoverThreadAfter = S.nContextSwitchHoverThreadBefore = -1;
|
||||
|
||||
uint32_t nContextSwitchStart = UINT32_MAX;
|
||||
uint32_t nContextSwitchEnd = UINT32_MAX;
|
||||
uint32_t nContextSwitchStart = -1;
|
||||
uint32_t nContextSwitchEnd = -1;
|
||||
S.nContextSwitchHoverCpuNext = 0xff;
|
||||
S.nContextSwitchHoverTickIn = -1;
|
||||
S.nContextSwitchHoverTickOut = -1;
|
||||
@@ -1004,10 +1005,9 @@ inline void MicroProfileDrawDetailedBars(uint32_t nWidth, uint32_t nHeight, int
|
||||
}while(pFrameLogFirst != pFrameFirst);
|
||||
|
||||
|
||||
if (nGet == UINT32_MAX) {
|
||||
if(nGet == (uint32_t)-1)
|
||||
continue;
|
||||
}
|
||||
MP_ASSERT(nGet != UINT32_MAX);
|
||||
MP_ASSERT(nGet != (uint32_t)-1);
|
||||
|
||||
nPut = pFrameLogLast->nLogStart[i];
|
||||
|
||||
@@ -1023,9 +1023,9 @@ inline void MicroProfileDrawDetailedBars(uint32_t nWidth, uint32_t nHeight, int
|
||||
int64_t nBaseTicks = bGpu ? nBaseTicksGpu : nBaseTicksCpu;
|
||||
char ThreadName[MicroProfileThreadLog::THREAD_MAX_LEN + 16];
|
||||
uint64_t nThreadId = pLog->nThreadId;
|
||||
snprintf(ThreadName, sizeof(ThreadName)-1, "%04" PRIx64 ": %s", nThreadId, &pLog->ThreadName[0] );
|
||||
snprintf(ThreadName, sizeof(ThreadName)-1, "%04llx: %s", nThreadId, &pLog->ThreadName[0] );
|
||||
nY += 3;
|
||||
uint32_t nThreadColor = UINT32_MAX;
|
||||
uint32_t nThreadColor = -1;
|
||||
if(pLog->nThreadId == nContextSwitchHoverThreadAfter || pLog->nThreadId == nContextSwitchHoverThreadBefore)
|
||||
nThreadColor = UI.nHoverColorShared|0x906060;
|
||||
MicroProfileDrawText(0, nY, nThreadColor, &ThreadName[0], (uint32_t)strlen(&ThreadName[0]));
|
||||
@@ -1048,7 +1048,7 @@ inline void MicroProfileDrawDetailedBars(uint32_t nWidth, uint32_t nHeight, int
|
||||
uint32_t nEnd = nRange[j][1];
|
||||
for(uint32_t k = nStart; k < nEnd; ++k)
|
||||
{
|
||||
MicroProfileLogEntry* pEntry = &pLog->Log[k];
|
||||
MicroProfileLogEntry* pEntry = pLog->Log + k;
|
||||
int nType = MicroProfileLogType(*pEntry);
|
||||
if(MP_LOG_ENTER == nType)
|
||||
{
|
||||
@@ -1066,7 +1066,7 @@ inline void MicroProfileDrawDetailedBars(uint32_t nWidth, uint32_t nHeight, int
|
||||
continue;
|
||||
}
|
||||
|
||||
MicroProfileLogEntry* pEntryEnter = &pLog->Log[nStack[nStackPos-1]];
|
||||
MicroProfileLogEntry* pEntryEnter = pLog->Log + nStack[nStackPos-1];
|
||||
if(MicroProfileLogTimerIndex(*pEntryEnter) != MicroProfileLogTimerIndex(*pEntry))
|
||||
{
|
||||
//uprintf("mismatch %llx %llx\n", pEntryEnter->nToken, pEntry->nToken);
|
||||
@@ -1126,7 +1126,7 @@ inline void MicroProfileDrawDetailedBars(uint32_t nWidth, uint32_t nHeight, int
|
||||
uint32_t nIntegerWidth = (uint32_t)(fXEnd - fXStart);
|
||||
if(nIntegerWidth)
|
||||
{
|
||||
if(bHover && UI.nActiveMenu == UINT32_MAX)
|
||||
if(bHover && UI.nActiveMenu == -1)
|
||||
{
|
||||
nHoverToken = MicroProfileLogTimerIndex(*pEntry);
|
||||
#if MICROPROFILE_DEBUG
|
||||
@@ -1146,7 +1146,7 @@ inline void MicroProfileDrawDetailedBars(uint32_t nWidth, uint32_t nHeight, int
|
||||
int nCharacters = (nTextWidth - 2*MICROPROFILE_TEXT_WIDTH) / MICROPROFILE_TEXT_WIDTH;
|
||||
if(nCharacters>0)
|
||||
{
|
||||
MicroProfileDrawText(fXStartText + 1, fYStart + 1, UINT32_MAX, S.TimerInfo[nTimerIndex].pName, MicroProfileMin<uint32_t>(S.TimerInfo[nTimerIndex].nNameLen, nCharacters));
|
||||
MicroProfileDrawText(fXStartText+1, fYStart+1, -1, S.TimerInfo[nTimerIndex].pName, MicroProfileMin<uint32_t>(S.TimerInfo[nTimerIndex].nNameLen, nCharacters));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1158,7 +1158,7 @@ inline void MicroProfileDrawDetailedBars(uint32_t nWidth, uint32_t nHeight, int
|
||||
int nLineX = (int)floor(fXAvg+0.5f);
|
||||
if(nLineX != (int)nLinesDrawn[nStackPos])
|
||||
{
|
||||
if(bHover && UI.nActiveMenu == UINT32_MAX)
|
||||
if(bHover && UI.nActiveMenu == -1)
|
||||
{
|
||||
nHoverToken = (uint32_t)MicroProfileLogTimerIndex(*pEntry);
|
||||
nHoverTime = MicroProfileLogTickDifference(nTickStart, nTickEnd);
|
||||
@@ -1235,9 +1235,9 @@ inline void MicroProfileDrawDetailedBars(uint32_t nWidth, uint32_t nHeight, int
|
||||
// nThreadId is 32-bit on Windows
|
||||
int nStrLen = snprintf(ThreadName, sizeof(ThreadName)-1, "%04x: %s%s", nThreadId, cLocal, i < nNumThreadsBase ? &S.Pool[i]->ThreadName[0] : MICROPROFILE_THREAD_NAME_FROM_ID(nThreadId) );
|
||||
#else
|
||||
int nStrLen = snprintf(ThreadName, sizeof(ThreadName)-1, "%04" PRIx64 ": %s%s", nThreadId, cLocal, i < nNumThreadsBase ? &S.Pool[i]->ThreadName[0] : MICROPROFILE_THREAD_NAME_FROM_ID(nThreadId) );
|
||||
int nStrLen = snprintf(ThreadName, sizeof(ThreadName)-1, "%04llx: %s%s", nThreadId, cLocal, i < nNumThreadsBase ? &S.Pool[i]->ThreadName[0] : MICROPROFILE_THREAD_NAME_FROM_ID(nThreadId) );
|
||||
#endif
|
||||
uint32_t nThreadColor = UINT32_MAX;
|
||||
uint32_t nThreadColor = -1;
|
||||
if(nThreadId == nContextSwitchHoverThreadAfter || nThreadId == nContextSwitchHoverThreadBefore)
|
||||
nThreadColor = UI.nHoverColorShared|0x906060;
|
||||
MicroProfileDrawDetailedContextSwitchBars(nY+2, nThreadId, nContextSwitchStart, nContextSwitchEnd, nBaseTicksCpu, nBaseY);
|
||||
@@ -1249,6 +1249,9 @@ inline void MicroProfileDrawDetailedBars(uint32_t nWidth, uint32_t nHeight, int
|
||||
|
||||
S.nContextSwitchHoverCpu = S.nContextSwitchHoverCpuNext;
|
||||
|
||||
|
||||
|
||||
|
||||
UI.pDisplayMouseOver = pMouseOverNext;
|
||||
|
||||
if(!S.nRunning)
|
||||
@@ -1283,10 +1286,10 @@ inline void MicroProfileDrawDetailedBars(uint32_t nWidth, uint32_t nHeight, int
|
||||
float fStartTextWidth = (float)((1+MICROPROFILE_TEXT_WIDTH) * nLenStart);
|
||||
float fStartTextX = fXStart - fStartTextWidth - 2;
|
||||
MicroProfileDrawBox(fStartTextX, nBaseY, fStartTextX + fStartTextWidth + 2, MICROPROFILE_TEXT_HEIGHT + 2 + nBaseY, 0x33000000, MicroProfileBoxTypeFlat);
|
||||
MicroProfileDrawText(fStartTextX+1, nBaseY, UINT32_MAX, sBuffer, nLenStart);
|
||||
MicroProfileDrawText(fStartTextX+1, nBaseY, (uint32_t)-1, sBuffer, nLenStart);
|
||||
uint32_t nLenEnd = snprintf(sBuffer, sizeof(sBuffer)-1, "%.2fms", fMsEnd);
|
||||
MicroProfileDrawBox(fXEnd+1, nBaseY, fXEnd+1+(1+MICROPROFILE_TEXT_WIDTH) * nLenEnd + 3, MICROPROFILE_TEXT_HEIGHT + 2 + nBaseY, 0x33000000, MicroProfileBoxTypeFlat);
|
||||
MicroProfileDrawText(fXEnd+2, nBaseY+1, UINT32_MAX, sBuffer, nLenEnd);
|
||||
MicroProfileDrawText(fXEnd+2, nBaseY+1, (uint32_t)-1, sBuffer, nLenEnd);
|
||||
|
||||
if(UI.nMouseRight)
|
||||
{
|
||||
@@ -1313,10 +1316,10 @@ inline void MicroProfileDrawDetailedBars(uint32_t nWidth, uint32_t nHeight, int
|
||||
float fStartTextWidth = (float)((1+MICROPROFILE_TEXT_WIDTH) * nLenStart);
|
||||
float fStartTextX = fXStart - fStartTextWidth - 2;
|
||||
MicroProfileDrawBox(fStartTextX, nBaseY, fStartTextX + fStartTextWidth + 2, MICROPROFILE_TEXT_HEIGHT + 2 + nBaseY, 0x33000000, MicroProfileBoxTypeFlat);
|
||||
MicroProfileDrawText(fStartTextX+1, nBaseY, UINT32_MAX, sBuffer, nLenStart);
|
||||
MicroProfileDrawText(fStartTextX+1, nBaseY, (uint32_t)-1, sBuffer, nLenStart);
|
||||
uint32_t nLenEnd = snprintf(sBuffer, sizeof(sBuffer)-1, "%.2fms", fMsEnd);
|
||||
MicroProfileDrawBox(fXEnd+1, nBaseY, fXEnd+1+(1+MICROPROFILE_TEXT_WIDTH) * nLenEnd + 3, MICROPROFILE_TEXT_HEIGHT + 2 + nBaseY, 0x33000000, MicroProfileBoxTypeFlat);
|
||||
MicroProfileDrawText(fXEnd+2, nBaseY+1, UINT32_MAX, sBuffer, nLenEnd);
|
||||
MicroProfileDrawText(fXEnd+2, nBaseY+1, (uint32_t)-1, sBuffer, nLenEnd);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1362,7 +1365,7 @@ inline void MicroProfileDrawDetailedFrameHistory(uint32_t nWidth, uint32_t nHeig
|
||||
fBaseX = fXStart;
|
||||
uint32_t nColor = MICROPROFILE_FRAME_HISTORY_COLOR_CPU;
|
||||
if(nIndex == nSelectedFrame)
|
||||
nColor = UINT32_MAX;
|
||||
nColor = (uint32_t)-1;
|
||||
MicroProfileDrawBox(fXStart, nBaseY + fScale * nBarHeight, fXEnd, nBaseY+MICROPROFILE_FRAME_HISTORY_HEIGHT, nColor, MicroProfileBoxTypeBar);
|
||||
if(pNext->nFrameStartCpu > nCpuStart)
|
||||
{
|
||||
@@ -1384,7 +1387,7 @@ inline void MicroProfileDrawDetailedView(uint32_t nWidth, uint32_t nHeight)
|
||||
uint32_t nBaseY = MICROPROFILE_TEXT_HEIGHT + 1;
|
||||
|
||||
int nSelectedFrame = -1;
|
||||
if(UI.nMouseY > nBaseY && UI.nMouseY <= nBaseY + MICROPROFILE_FRAME_HISTORY_HEIGHT && UI.nActiveMenu == UINT32_MAX)
|
||||
if(UI.nMouseY > nBaseY && UI.nMouseY <= nBaseY + MICROPROFILE_FRAME_HISTORY_HEIGHT && UI.nActiveMenu == -1)
|
||||
{
|
||||
|
||||
nSelectedFrame = ((MICROPROFILE_NUM_FRAMES) * (UI.nWidth-UI.nMouseX) / UI.nWidth);
|
||||
@@ -1422,7 +1425,7 @@ inline void MicroProfileDrawHeader(int32_t nX, uint32_t nWidth, const char* pNam
|
||||
if(pName)
|
||||
{
|
||||
MicroProfileDrawBox(nX-8, MICROPROFILE_TEXT_HEIGHT + 2, nX + nWidth+5, MICROPROFILE_TEXT_HEIGHT + 2 + (MICROPROFILE_TEXT_HEIGHT+1), 0xff000000|g_nMicroProfileBackColors[1]);
|
||||
MicroProfileDrawText(nX, MICROPROFILE_TEXT_HEIGHT + 2, UINT32_MAX, pName, (uint32_t)strlen(pName));
|
||||
MicroProfileDrawText(nX, MICROPROFILE_TEXT_HEIGHT + 2, (uint32_t)-1, pName, (uint32_t)strlen(pName));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1437,7 +1440,7 @@ inline void MicroProfileLoopActiveGroupsDraw(int32_t nX, int32_t nY, const char*
|
||||
uint32_t nCount = 0;
|
||||
for(uint32_t j = 0; j < MICROPROFILE_MAX_GROUPS; ++j)
|
||||
{
|
||||
uint64_t nMask = 1ULL << j;
|
||||
uint64_t nMask = 1ll << j;
|
||||
if(nMask & nGroup)
|
||||
{
|
||||
nY += MICROPROFILE_TEXT_HEIGHT + 1;
|
||||
@@ -1518,7 +1521,7 @@ inline void MicroProfileCalcTimers(float* pTimers, float* pAverage, float* pMax,
|
||||
}
|
||||
}
|
||||
}
|
||||
nMask <<= 1;
|
||||
nMask <<= 1ll;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1540,7 +1543,7 @@ inline void MicroProfileDrawBarArrayCallback(uint32_t nTimer, uint32_t nIdx, uin
|
||||
snprintf(sBuffer, SBUF_MAX-1, "%5.2f", pTimers[nIdx]);
|
||||
if (!pTimers2)
|
||||
MicroProfileDrawBox(nX + nTextWidth, nY, nX + nTextWidth + fWidth * pTimers[nIdx+1], nY + nHeight, UI.nOpacityForeground|S.TimerInfo[nTimer].nColor, MicroProfileBoxTypeBar);
|
||||
MicroProfileDrawText(nX, nY, UINT32_MAX, sBuffer, (uint32_t)strlen(sBuffer));
|
||||
MicroProfileDrawText(nX, nY, (uint32_t)-1, sBuffer, (uint32_t)strlen(sBuffer));
|
||||
}
|
||||
|
||||
|
||||
@@ -1561,7 +1564,7 @@ inline void MicroProfileDrawBarCallCountCallback(uint32_t nTimer, uint32_t nIdx,
|
||||
MicroProfile& S = *MicroProfileGet();
|
||||
char sBuffer[SBUF_MAX];
|
||||
int nLen = snprintf(sBuffer, SBUF_MAX-1, "%5d", S.Frame[nTimer].nCount);//fix
|
||||
MicroProfileDrawText(nX, nY, UINT32_MAX, sBuffer, nLen);
|
||||
MicroProfileDrawText(nX, nY, (uint32_t)-1, sBuffer, nLen);
|
||||
}
|
||||
|
||||
inline uint32_t MicroProfileDrawBarCallCount(int32_t nX, int32_t nY, const char* pName)
|
||||
@@ -1585,7 +1588,7 @@ inline void MicroProfileDrawBarMetaAverageCallback(uint32_t nTimer, uint32_t nId
|
||||
float fRcpFrames = pArgs->fRcpFrames;
|
||||
char sBuffer[SBUF_MAX];
|
||||
int nLen = snprintf(sBuffer, SBUF_MAX-1, "%5.2f", pCounters[nTimer] * fRcpFrames);
|
||||
MicroProfileDrawText(nX - nLen * (MICROPROFILE_TEXT_WIDTH+1), nY, UINT32_MAX, sBuffer, nLen);
|
||||
MicroProfileDrawText(nX - nLen * (MICROPROFILE_TEXT_WIDTH+1), nY, (uint32_t)-1, sBuffer, nLen);
|
||||
}
|
||||
|
||||
inline uint32_t MicroProfileDrawBarMetaAverage(int32_t nX, int32_t nY, uint64_t* pCounters, const char* pName, uint32_t nTotalHeight)
|
||||
@@ -1606,8 +1609,8 @@ inline void MicroProfileDrawBarMetaCountCallback(uint32_t nTimer, uint32_t nIdx,
|
||||
{
|
||||
uint64_t* pCounters = (uint64_t*)pExtra;
|
||||
char sBuffer[SBUF_MAX];
|
||||
int nLen = snprintf(sBuffer, SBUF_MAX-1, "%5" PRIu64, pCounters[nTimer]);
|
||||
MicroProfileDrawText(nX - nLen * (MICROPROFILE_TEXT_WIDTH+1), nY, UINT32_MAX, sBuffer, nLen);
|
||||
int nLen = snprintf(sBuffer, SBUF_MAX-1, "%5llu", pCounters[nTimer]);
|
||||
MicroProfileDrawText(nX - nLen * (MICROPROFILE_TEXT_WIDTH+1), nY, (uint32_t)-1, sBuffer, nLen);
|
||||
}
|
||||
|
||||
inline uint32_t MicroProfileDrawBarMetaCount(int32_t nX, int32_t nY, uint64_t* pCounters, const char* pName, uint32_t nTotalHeight)
|
||||
@@ -1664,7 +1667,7 @@ bool MicroProfileDrawGraph(uint32_t nScreenWidth, uint32_t nScreenHeight)
|
||||
if(bMouseOver)
|
||||
{
|
||||
float fXAvg = fMouseXPrc * MICROPROFILE_GRAPH_WIDTH + nX;
|
||||
MicroProfileDrawLineVertical(fXAvg, nY, nY + MICROPROFILE_GRAPH_HEIGHT, UINT32_MAX);
|
||||
MicroProfileDrawLineVertical(fXAvg, nY, nY + MICROPROFILE_GRAPH_HEIGHT, (uint32_t)-1);
|
||||
}
|
||||
|
||||
|
||||
@@ -1703,7 +1706,7 @@ bool MicroProfileDrawGraph(uint32_t nScreenWidth, uint32_t nScreenHeight)
|
||||
|
||||
char buf[32];
|
||||
int nLen = snprintf(buf, sizeof(buf)-1, "%5.2fms", S.fReferenceTime);
|
||||
MicroProfileDrawText(nX+1, fY1 - (2+MICROPROFILE_TEXT_HEIGHT), UINT32_MAX, buf, nLen);
|
||||
MicroProfileDrawText(nX+1, fY1 - (2+MICROPROFILE_TEXT_HEIGHT), (uint32_t)-1, buf, nLen);
|
||||
}
|
||||
|
||||
|
||||
@@ -1779,7 +1782,7 @@ void MicroProfileDumpTimers()
|
||||
|
||||
for(uint32_t j = 0; j < MICROPROFILE_MAX_GROUPS; ++j)
|
||||
{
|
||||
uint64_t nMask = 1ULL << j;
|
||||
uint64_t nMask = 1ll << j;
|
||||
if(nMask & nActiveGroup)
|
||||
{
|
||||
MICROPROFILE_PRINTF("%s\n", S.GroupInfo[j].pName);
|
||||
@@ -1820,7 +1823,7 @@ inline void MicroProfileDrawBarView(uint32_t nScreenWidth, uint32_t nScreenHeigh
|
||||
uint32_t nNumGroups = 0;
|
||||
for(uint32_t j = 0; j < MICROPROFILE_MAX_GROUPS; ++j)
|
||||
{
|
||||
if(nActiveGroup & (1ULL << j))
|
||||
if(nActiveGroup & (1ll << j))
|
||||
{
|
||||
nNumTimers += S.GroupInfo[j].nNumTimers;
|
||||
nNumGroups += 1;
|
||||
@@ -1875,7 +1878,7 @@ inline void MicroProfileDrawBarView(uint32_t nScreenWidth, uint32_t nScreenHeigh
|
||||
for(uint32_t i = 0; i < nNumTimers+nNumGroups+1; ++i)
|
||||
{
|
||||
uint32_t nY0 = nY + i * (nHeight + 1);
|
||||
bool bInside = (UI.nActiveMenu == UINT32_MAX) && ((UI.nMouseY >= nY0) && (UI.nMouseY < (nY0 + nHeight + 1)));
|
||||
bool bInside = (UI.nActiveMenu == -1) && ((UI.nMouseY >= nY0) && (UI.nMouseY < (nY0 + nHeight + 1)));
|
||||
MicroProfileDrawBox(nX, nY0, nWidth+nX, nY0 + (nHeight+1)+1, UI.nOpacityBackground | (g_nMicroProfileBackColors[nColorIndex++ & 1] + ((bInside) ? 0x002c2c2c : 0)));
|
||||
}
|
||||
nX += 10;
|
||||
@@ -1924,22 +1927,22 @@ inline void MicroProfileDrawBarView(uint32_t nScreenWidth, uint32_t nScreenHeigh
|
||||
nY = nHeight + 3 - UI.nOffsetY;
|
||||
for(uint32_t i = 0; i < nNumTimers+nNumGroups+1; ++i)
|
||||
{
|
||||
const uint32_t nY0 = nY + i * (nHeight + 1);
|
||||
const bool bInside = (UI.nActiveMenu == UINT32_MAX) && ((UI.nMouseY >= nY0) && (UI.nMouseY < (nY0 + nHeight + 1)));
|
||||
uint32_t nY0 = nY + i * (nHeight + 1);
|
||||
bool bInside = (UI.nActiveMenu == -1) && ((UI.nMouseY >= nY0) && (UI.nMouseY < (nY0 + nHeight + 1)));
|
||||
MicroProfileDrawBox(nX, nY0, nTimerWidth, nY0 + (nHeight+1)+1, 0xff0000000 | (g_nMicroProfileBackColors[nColorIndex++ & 1] + ((bInside) ? 0x002c2c2c : 0)));
|
||||
}
|
||||
nX += MicroProfileDrawBarLegend(nX, nY, nTotalHeight, nTimerWidth-5) + 1;
|
||||
|
||||
for(uint32_t j = 0; j < MICROPROFILE_MAX_GROUPS; ++j)
|
||||
{
|
||||
if(nActiveGroup & (1ULL << j))
|
||||
if(nActiveGroup & (1ll << j))
|
||||
{
|
||||
MicroProfileDrawText(nX, nY + (1+nHeight) * nLegendOffset, UINT32_MAX, S.GroupInfo[j].pName, S.GroupInfo[j].nNameLen);
|
||||
MicroProfileDrawText(nX, nY + (1+nHeight) * nLegendOffset, (uint32_t)-1, S.GroupInfo[j].pName, S.GroupInfo[j].nNameLen);
|
||||
nLegendOffset += S.GroupInfo[j].nNumTimers+1;
|
||||
}
|
||||
}
|
||||
MicroProfileDrawHeader(nX, nTimerWidth-5, "Group");
|
||||
MicroProfileDrawTextRight(nTimerWidth-3, MICROPROFILE_TEXT_HEIGHT + 2, UINT32_MAX, "Timer", 5);
|
||||
MicroProfileDrawTextRight(nTimerWidth-3, MICROPROFILE_TEXT_HEIGHT + 2, (uint32_t)-1, "Timer", 5);
|
||||
MicroProfileDrawLineVertical(nTimerWidth, 0, nTotalHeight+nY, UI.nOpacityBackground|g_nMicroProfileBackColors[0]|g_nMicroProfileBackColors[1]);
|
||||
MicroProfileDrawLineHorizontal(0, nWidth, 2*MICROPROFILE_TEXT_HEIGHT + 3, UI.nOpacityBackground|g_nMicroProfileBackColors[0]|g_nMicroProfileBackColors[1]);
|
||||
}
|
||||
@@ -2000,7 +2003,7 @@ inline const char* MicroProfileUIMenuGroups(int nIndex, bool* bSelected)
|
||||
}
|
||||
else
|
||||
{
|
||||
*bSelected = 0 != (S.nActiveGroupWanted & (1ULL << Item.nIndex));
|
||||
*bSelected = 0 != (S.nActiveGroupWanted & (1ll << Item.nIndex));
|
||||
snprintf(buffer, sizeof(buffer)-1, " %s", Item.pName);
|
||||
}
|
||||
return buffer;
|
||||
@@ -2012,18 +2015,16 @@ inline const char* MicroProfileUIMenuGroups(int nIndex, bool* bSelected)
|
||||
inline const char* MicroProfileUIMenuAggregate(int nIndex, bool* bSelected)
|
||||
{
|
||||
MicroProfile& S = *MicroProfileGet();
|
||||
if(static_cast<uint32_t>(nIndex) < g_MicroProfileAggregatePresets.size())
|
||||
if(nIndex < sizeof(g_MicroProfileAggregatePresets)/sizeof(g_MicroProfileAggregatePresets[0]))
|
||||
{
|
||||
uint32_t val = g_MicroProfileAggregatePresets[nIndex];
|
||||
*bSelected = S.nAggregateFlip == val;
|
||||
if (0 == val)
|
||||
{
|
||||
int val = g_MicroProfileAggregatePresets[nIndex];
|
||||
*bSelected = (int)S.nAggregateFlip == val;
|
||||
if(0 == val)
|
||||
return "Infinite";
|
||||
}
|
||||
else
|
||||
{
|
||||
static char buf[128];
|
||||
snprintf(buf, sizeof(buf)-1, "%7u", val);
|
||||
snprintf(buf, sizeof(buf)-1, "%7d", val);
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
@@ -2097,13 +2098,11 @@ inline const char* MicroProfileUIMenuPreset(int nIndex, bool* bSelected)
|
||||
{
|
||||
static char buf[128];
|
||||
*bSelected = false;
|
||||
int nNumPresets = static_cast<int>(g_MicroProfilePresetNames.size());
|
||||
int nNumPresets = sizeof(g_MicroProfilePresetNames) / sizeof(g_MicroProfilePresetNames[0]);
|
||||
int nIndexSave = nIndex - nNumPresets - 1;
|
||||
if (nIndex == nNumPresets)
|
||||
{
|
||||
if(nIndex == nNumPresets)
|
||||
return "--";
|
||||
}
|
||||
else if(nIndexSave >=0 && nIndexSave < nNumPresets)
|
||||
else if(nIndexSave >=0 && nIndexSave <nNumPresets)
|
||||
{
|
||||
snprintf(buf, sizeof(buf)-1, "Save '%s'", g_MicroProfilePresetNames[nIndexSave]);
|
||||
return buf;
|
||||
@@ -2121,13 +2120,13 @@ inline const char* MicroProfileUIMenuPreset(int nIndex, bool* bSelected)
|
||||
|
||||
inline const char* MicroProfileUIMenuCustom(int nIndex, bool* bSelected)
|
||||
{
|
||||
if(UINT32_MAX == UI.nCustomActive)
|
||||
if((uint32_t)-1 == UI.nCustomActive)
|
||||
{
|
||||
*bSelected = nIndex == 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
*bSelected = nIndex-2 == static_cast<int>(UI.nCustomActive);
|
||||
*bSelected = nIndex-2 == UI.nCustomActive;
|
||||
}
|
||||
switch(nIndex)
|
||||
{
|
||||
@@ -2203,7 +2202,7 @@ inline void MicroProfileUIClickGroups(int nIndex)
|
||||
else
|
||||
{
|
||||
MP_ASSERT(Item.nIndex < S.nGroupCount);
|
||||
S.nActiveGroupWanted ^= (1ULL << Item.nIndex);
|
||||
S.nActiveGroupWanted ^= (1ll << Item.nIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2274,7 +2273,7 @@ inline void MicroProfileUIClickOptions(int nIndex)
|
||||
|
||||
inline void MicroProfileUIClickPreset(int nIndex)
|
||||
{
|
||||
int nNumPresets = static_cast<int>(g_MicroProfilePresetNames.size());
|
||||
int nNumPresets = sizeof(g_MicroProfilePresetNames) / sizeof(g_MicroProfilePresetNames[0]);
|
||||
int nIndexSave = nIndex - nNumPresets - 1;
|
||||
if(nIndexSave >= 0 && nIndexSave < nNumPresets)
|
||||
{
|
||||
@@ -2311,7 +2310,7 @@ inline void MicroProfileDrawMenu(uint32_t nWidth, uint32_t nHeight)
|
||||
|
||||
uint32_t nX = 0;
|
||||
uint32_t nY = 0;
|
||||
|
||||
bool bMouseOver = UI.nMouseY < MICROPROFILE_TEXT_HEIGHT + 1;
|
||||
#define SBUF_SIZE 256
|
||||
char buffer[256];
|
||||
MicroProfileDrawBox(nX, nY, nX + nWidth, nY + (MICROPROFILE_TEXT_HEIGHT+1)+1, 0xff000000|g_nMicroProfileBackColors[1]);
|
||||
@@ -2322,7 +2321,7 @@ inline void MicroProfileDrawMenu(uint32_t nWidth, uint32_t nHeight)
|
||||
uint32_t nNumMenuItems = 0;
|
||||
|
||||
int nLen = snprintf(buffer, 127, "MicroProfile");
|
||||
MicroProfileDrawText(nX, nY, UINT32_MAX, buffer, nLen);
|
||||
MicroProfileDrawText(nX, nY, (uint32_t)-1, buffer, nLen);
|
||||
nX += (sizeof("MicroProfile")+2) * (MICROPROFILE_TEXT_WIDTH+1);
|
||||
pMenuText[nNumMenuItems++] = "Mode";
|
||||
pMenuText[nNumMenuItems++] = "Groups";
|
||||
@@ -2410,7 +2409,7 @@ inline void MicroProfileDrawMenu(uint32_t nWidth, uint32_t nHeight)
|
||||
};
|
||||
|
||||
|
||||
uint32_t nSelectMenu = UINT32_MAX;
|
||||
uint32_t nSelectMenu = (uint32_t)-1;
|
||||
for(uint32_t i = 0; i < nNumMenuItems; ++i)
|
||||
{
|
||||
nMenuX[i] = nX;
|
||||
@@ -2420,17 +2419,17 @@ inline void MicroProfileDrawMenu(uint32_t nWidth, uint32_t nHeight)
|
||||
{
|
||||
MicroProfileDrawBox(nX-1, nY, nX + nLen * (MICROPROFILE_TEXT_WIDTH+1), nY +(MICROPROFILE_TEXT_HEIGHT+1)+1, 0xff888888);
|
||||
nSelectMenu = i;
|
||||
if((UI.nMouseLeft || UI.nMouseRight) && i == (uint32_t)nPauseIndex)
|
||||
if((UI.nMouseLeft || UI.nMouseRight) && i == (int)nPauseIndex)
|
||||
{
|
||||
S.nToggleRunning = 1;
|
||||
}
|
||||
}
|
||||
MicroProfileDrawText(nX, nY, UINT32_MAX, pMenuText[i], (uint32_t)strlen(pMenuText[i]));
|
||||
MicroProfileDrawText(nX, nY, (uint32_t)-1, pMenuText[i], (uint32_t)strlen(pMenuText[i]));
|
||||
nX += (nLen+1) * (MICROPROFILE_TEXT_WIDTH+1);
|
||||
}
|
||||
uint32_t nMenu = nSelectMenu != UINT32_MAX ? nSelectMenu : UI.nActiveMenu;
|
||||
uint32_t nMenu = nSelectMenu != (uint32_t)-1 ? nSelectMenu : UI.nActiveMenu;
|
||||
UI.nActiveMenu = nMenu;
|
||||
if(UINT32_MAX != nMenu)
|
||||
if((uint32_t)-1 != nMenu)
|
||||
{
|
||||
nX = nMenuX[nMenu];
|
||||
nY += MICROPROFILE_TEXT_HEIGHT+1;
|
||||
@@ -2451,9 +2450,9 @@ inline void MicroProfileDrawMenu(uint32_t nWidth, uint32_t nHeight)
|
||||
{
|
||||
UI.nActiveMenu = nMenu;
|
||||
}
|
||||
else if(nSelectMenu == UINT32_MAX)
|
||||
else if(nSelectMenu == (uint32_t)-1)
|
||||
{
|
||||
UI.nActiveMenu = UINT32_MAX;
|
||||
UI.nActiveMenu = (uint32_t)-1;
|
||||
}
|
||||
MicroProfileDrawBox(nX, nY, nX + nWidth, nY + nHeight, 0xff000000|g_nMicroProfileBackColors[1]);
|
||||
for(int i = 0; i < nNumLines; ++i)
|
||||
@@ -2462,6 +2461,7 @@ inline void MicroProfileDrawMenu(uint32_t nWidth, uint32_t nHeight)
|
||||
const char* pString = CB(i, &bSelected);
|
||||
if(UI.nMouseY >= nY && UI.nMouseY < nY + MICROPROFILE_TEXT_HEIGHT + 1)
|
||||
{
|
||||
bMouseOver = true;
|
||||
if(UI.nMouseLeft || UI.nMouseRight)
|
||||
{
|
||||
CBClick[nMenu](i);
|
||||
@@ -2469,7 +2469,7 @@ inline void MicroProfileDrawMenu(uint32_t nWidth, uint32_t nHeight)
|
||||
MicroProfileDrawBox(nX, nY, nX + nWidth, nY + MICROPROFILE_TEXT_HEIGHT + 1, 0xff888888);
|
||||
}
|
||||
int nLen = snprintf(buffer, SBUF_SIZE-1, "%c %s", bSelected ? '*' : ' ' ,pString);
|
||||
MicroProfileDrawText(nX, nY, UINT32_MAX, buffer, nLen);
|
||||
MicroProfileDrawText(nX, nY, (uint32_t)-1, buffer, nLen);
|
||||
nY += MICROPROFILE_TEXT_HEIGHT+1;
|
||||
}
|
||||
}
|
||||
@@ -2484,7 +2484,7 @@ inline void MicroProfileDrawMenu(uint32_t nWidth, uint32_t nHeight)
|
||||
float fMaxMs = fToMs * S.nFlipMaxDisplay;
|
||||
int nLen = snprintf(FrameTimeMessage, sizeof(FrameTimeMessage)-1, "Time[%6.2f] Avg[%6.2f] Max[%6.2f]", fMs, fAverageMs, fMaxMs);
|
||||
pMenuText[nNumMenuItems++] = &FrameTimeMessage[0];
|
||||
MicroProfileDrawText(nWidth - nLen * (MICROPROFILE_TEXT_WIDTH+1), 0, UINT32_MAX, FrameTimeMessage, nLen);
|
||||
MicroProfileDrawText(nWidth - nLen * (MICROPROFILE_TEXT_WIDTH+1), 0, -1, FrameTimeMessage, nLen);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2538,7 +2538,7 @@ inline void MicroProfileMoveGraph()
|
||||
|
||||
inline void MicroProfileDrawCustom(uint32_t nWidth, uint32_t nHeight)
|
||||
{
|
||||
if(UINT32_MAX != UI.nCustomActive)
|
||||
if((uint32_t)-1 != UI.nCustomActive)
|
||||
{
|
||||
MicroProfile& S = *MicroProfileGet();
|
||||
MP_ASSERT(UI.nCustomActive < MICROPROFILE_CUSTOM_MAX);
|
||||
@@ -2571,8 +2571,8 @@ inline void MicroProfileDrawCustom(uint32_t nWidth, uint32_t nHeight)
|
||||
pColors[i] = S.TimerInfo[nTimerIndex].nColor;
|
||||
}
|
||||
|
||||
MicroProfileDrawText(MICROPROFILE_CUSTOM_PADDING + 3*MICROPROFILE_TEXT_WIDTH, nOffsetY, UINT32_MAX, "Avg", sizeof("Avg")-1);
|
||||
MicroProfileDrawText(MICROPROFILE_CUSTOM_PADDING + 13*MICROPROFILE_TEXT_WIDTH, nOffsetY, UINT32_MAX, "Max", sizeof("Max")-1);
|
||||
MicroProfileDrawText(MICROPROFILE_CUSTOM_PADDING + 3*MICROPROFILE_TEXT_WIDTH, nOffsetY, (uint32_t)-1, "Avg", sizeof("Avg")-1);
|
||||
MicroProfileDrawText(MICROPROFILE_CUSTOM_PADDING + 13*MICROPROFILE_TEXT_WIDTH, nOffsetY, (uint32_t)-1, "Max", sizeof("Max")-1);
|
||||
for(uint32_t i = 0; i < nCount; ++i)
|
||||
{
|
||||
nOffsetY += (1+MICROPROFILE_TEXT_HEIGHT);
|
||||
@@ -2582,10 +2582,10 @@ inline void MicroProfileDrawCustom(uint32_t nWidth, uint32_t nHeight)
|
||||
int nSize;
|
||||
uint32_t nOffsetX = MICROPROFILE_CUSTOM_PADDING;
|
||||
nSize = snprintf(Buffer, sizeof(Buffer)-1, "%6.2f", pTimeAvg[i]);
|
||||
MicroProfileDrawText(nOffsetX, nOffsetY, UINT32_MAX, Buffer, nSize);
|
||||
MicroProfileDrawText(nOffsetX, nOffsetY, (uint32_t)-1, Buffer, nSize);
|
||||
nOffsetX += (nSize+2) * (MICROPROFILE_TEXT_WIDTH+1);
|
||||
nSize = snprintf(Buffer, sizeof(Buffer)-1, "%6.2f", pTimeMax[i]);
|
||||
MicroProfileDrawText(nOffsetX, nOffsetY, UINT32_MAX, Buffer, nSize);
|
||||
MicroProfileDrawText(nOffsetX, nOffsetY, (uint32_t)-1, Buffer, nSize);
|
||||
nOffsetX += (nSize+2) * (MICROPROFILE_TEXT_WIDTH+1);
|
||||
nSize = snprintf(Buffer, sizeof(Buffer)-1, "%s:%s", S.GroupInfo[nGroupIndex].pName, pTimerInfo->pName);
|
||||
MicroProfileDrawText(nOffsetX, nOffsetY, pTimerInfo->nColor, Buffer, nSize);
|
||||
@@ -2599,9 +2599,9 @@ inline void MicroProfileDrawCustom(uint32_t nWidth, uint32_t nHeight)
|
||||
nOffsetY = nOffsetYBase;
|
||||
float* pMs = pCustom->nFlags & MICROPROFILE_CUSTOM_BAR_SOURCE_MAX ? pTimeMax : pTimeAvg;
|
||||
const char* pString = pCustom->nFlags & MICROPROFILE_CUSTOM_BAR_SOURCE_MAX ? "Max" : "Avg";
|
||||
MicroProfileDrawText(nMaxOffsetX, nOffsetY, UINT32_MAX, pString, static_cast<uint32_t>(strlen(pString)));
|
||||
MicroProfileDrawText(nMaxOffsetX, nOffsetY, (uint32_t)-1, pString, static_cast<uint32_t>(strlen(pString)));
|
||||
int nSize = snprintf(Buffer, sizeof(Buffer)-1, "%6.2fms", fReference);
|
||||
MicroProfileDrawText(nReducedWidth - (1+nSize) * (MICROPROFILE_TEXT_WIDTH+1), nOffsetY, UINT32_MAX, Buffer, nSize);
|
||||
MicroProfileDrawText(nReducedWidth - (1+nSize) * (MICROPROFILE_TEXT_WIDTH+1), nOffsetY, (uint32_t)-1, Buffer, nSize);
|
||||
for(uint32_t i = 0; i < nCount; ++i)
|
||||
{
|
||||
nOffsetY += (1+MICROPROFILE_TEXT_HEIGHT);
|
||||
@@ -2613,9 +2613,9 @@ inline void MicroProfileDrawCustom(uint32_t nWidth, uint32_t nHeight)
|
||||
{
|
||||
nOffsetY += 2*(1+MICROPROFILE_TEXT_HEIGHT);
|
||||
const char* pString = pCustom->nFlags & MICROPROFILE_CUSTOM_STACK_SOURCE_MAX ? "Max" : "Avg";
|
||||
MicroProfileDrawText(MICROPROFILE_CUSTOM_PADDING, nOffsetY, UINT32_MAX, pString, static_cast<uint32_t>(strlen(pString)));
|
||||
MicroProfileDrawText(MICROPROFILE_CUSTOM_PADDING, nOffsetY, (uint32_t)-1, pString, static_cast<uint32_t>(strlen(pString)));
|
||||
int nSize = snprintf(Buffer, sizeof(Buffer)-1, "%6.2fms", fReference);
|
||||
MicroProfileDrawText(nReducedWidth - (1+nSize) * (MICROPROFILE_TEXT_WIDTH+1), nOffsetY, UINT32_MAX, Buffer, nSize);
|
||||
MicroProfileDrawText(nReducedWidth - (1+nSize) * (MICROPROFILE_TEXT_WIDTH+1), nOffsetY, (uint32_t)-1, Buffer, nSize);
|
||||
nOffsetY += (1+MICROPROFILE_TEXT_HEIGHT);
|
||||
float fPosX = MICROPROFILE_CUSTOM_PADDING;
|
||||
float* pMs = pCustom->nFlags & MICROPROFILE_CUSTOM_STACK_SOURCE_MAX ? pTimeMax : pTimeAvg;
|
||||
@@ -2668,7 +2668,7 @@ inline void MicroProfileDraw(uint32_t nWidth, uint32_t nHeight)
|
||||
UI.nHoverTime = 0;
|
||||
UI.nHoverFrame = -1;
|
||||
if(S.nDisplay != MP_DRAW_DETAILED)
|
||||
S.nContextSwitchHoverThread = S.nContextSwitchHoverThreadAfter = S.nContextSwitchHoverThreadBefore = UINT32_MAX;
|
||||
S.nContextSwitchHoverThread = S.nContextSwitchHoverThreadAfter = S.nContextSwitchHoverThreadBefore = -1;
|
||||
MicroProfileMoveGraph();
|
||||
|
||||
|
||||
@@ -2798,13 +2798,13 @@ inline void MicroProfileDraw(uint32_t nWidth, uint32_t nHeight)
|
||||
|
||||
|
||||
|
||||
if(UI.nActiveMenu == UINT32_MAX && !bMouseOverGraph)
|
||||
if(UI.nActiveMenu == -1 && !bMouseOverGraph)
|
||||
{
|
||||
if(UI.nHoverToken != MICROPROFILE_INVALID_TOKEN)
|
||||
{
|
||||
MicroProfileDrawFloatTooltip(UI.nMouseX, UI.nMouseY, UI.nHoverToken, UI.nHoverTime);
|
||||
}
|
||||
else if(S.nContextSwitchHoverThreadAfter != UINT32_MAX && S.nContextSwitchHoverThreadBefore != UINT32_MAX)
|
||||
else if(S.nContextSwitchHoverThreadAfter != -1 && S.nContextSwitchHoverThreadBefore != -1)
|
||||
{
|
||||
float fToMs = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondCpu());
|
||||
MicroProfileStringArray ToolTip;
|
||||
@@ -2820,7 +2820,7 @@ inline void MicroProfileDraw(uint32_t nWidth, uint32_t nHeight)
|
||||
MicroProfileStringArrayFormat(&ToolTip, "%6.2fms", fToMs * nDifference );
|
||||
MicroProfileStringArrayAddLiteral(&ToolTip, "CPU");
|
||||
MicroProfileStringArrayFormat(&ToolTip, "%d", S.nContextSwitchHoverCpu);
|
||||
MicroProfileDrawFloatWindow(UI.nMouseX, UI.nMouseY+20, &ToolTip.ppStrings[0], ToolTip.nNumStrings, UINT32_MAX);
|
||||
MicroProfileDrawFloatWindow(UI.nMouseX, UI.nMouseY+20, &ToolTip.ppStrings[0], ToolTip.nNumStrings, -1);
|
||||
|
||||
|
||||
}
|
||||
@@ -2858,7 +2858,7 @@ inline void MicroProfileDraw(uint32_t nWidth, uint32_t nHeight)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
MicroProfileDrawFloatWindow(UI.nMouseX, UI.nMouseY+20, &ToolTip.ppStrings[0], ToolTip.nNumStrings, UINT32_MAX);
|
||||
MicroProfileDrawFloatWindow(UI.nMouseX, UI.nMouseY+20, &ToolTip.ppStrings[0], ToolTip.nNumStrings, -1);
|
||||
}
|
||||
if(UI.nMouseLeft)
|
||||
{
|
||||
@@ -2883,7 +2883,7 @@ inline void MicroProfileDraw(uint32_t nWidth, uint32_t nHeight)
|
||||
#endif
|
||||
m.unlock();
|
||||
}
|
||||
else if(UI.nCustomActive != UINT32_MAX)
|
||||
else if(UI.nCustomActive != (uint32_t)-1)
|
||||
{
|
||||
std::recursive_mutex& m = MicroProfileGetMutex();
|
||||
m.lock();
|
||||
@@ -3179,7 +3179,7 @@ void MicroProfileLoadPreset(const char* pSuffix)
|
||||
{
|
||||
if(0 == MP_STRCASECMP(pGroupName, S.GroupInfo[j].pName))
|
||||
{
|
||||
S.nActiveGroupWanted |= (1ULL << j);
|
||||
S.nActiveGroupWanted |= (1ll << j);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3212,7 +3212,7 @@ void MicroProfileLoadPreset(const char* pSuffix)
|
||||
uint64_t nGroupIndex = S.TimerInfo[j].nGroupIndex;
|
||||
if(0 == MP_STRCASECMP(pGraphName, S.TimerInfo[j].pName) && 0 == MP_STRCASECMP(pGraphGroupName, S.GroupInfo[nGroupIndex].pName))
|
||||
{
|
||||
MicroProfileToken nToken = MicroProfileMakeToken(1ULL << nGroupIndex, (uint16_t)j);
|
||||
MicroProfileToken nToken = MicroProfileMakeToken(1ll << nGroupIndex, (uint16_t)j);
|
||||
S.Graph[i].nToken = nToken; // note: group index is stored here but is checked without in MicroProfileToggleGraph()!
|
||||
S.TimerInfo[j].bGraph = true;
|
||||
if(nToken != nPrevToken)
|
||||
@@ -3235,7 +3235,7 @@ inline uint32_t MicroProfileCustomGroupFind(const char* pCustomName)
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return UINT32_MAX;
|
||||
return (uint32_t)-1;
|
||||
}
|
||||
|
||||
inline uint32_t MicroProfileCustomGroup(const char* pCustomName)
|
||||
@@ -3251,7 +3251,7 @@ inline uint32_t MicroProfileCustomGroup(const char* pCustomName)
|
||||
uint32_t nIndex = UI.nCustomCount;
|
||||
UI.nCustomCount++;
|
||||
memset(&UI.Custom[nIndex], 0, sizeof(UI.Custom[nIndex]));
|
||||
size_t nLen = strlen(pCustomName);
|
||||
uint32_t nLen = (uint32_t)strlen(pCustomName);
|
||||
if(nLen > MICROPROFILE_NAME_MAX_LEN-1)
|
||||
nLen = MICROPROFILE_NAME_MAX_LEN-1;
|
||||
memcpy(&UI.Custom[nIndex].pName[0], pCustomName, nLen);
|
||||
@@ -3309,7 +3309,7 @@ inline void MicroProfileCustomGroupEnable(uint32_t nIndex)
|
||||
void MicroProfileCustomGroupToggle(const char* pCustomName)
|
||||
{
|
||||
uint32_t nIndex = MicroProfileCustomGroupFind(pCustomName);
|
||||
if(nIndex == UINT32_MAX || nIndex == UI.nCustomActive)
|
||||
if(nIndex == (uint32_t)-1 || nIndex == UI.nCustomActive)
|
||||
{
|
||||
MicroProfileCustomGroupDisable();
|
||||
}
|
||||
@@ -3328,13 +3328,13 @@ void MicroProfileCustomGroupDisable()
|
||||
{
|
||||
MicroProfile& S = *MicroProfileGet();
|
||||
S.nForceGroupUI = 0;
|
||||
UI.nCustomActive = UINT32_MAX;
|
||||
UI.nCustomActive = (uint32_t)-1;
|
||||
}
|
||||
|
||||
void MicroProfileCustomGroupAddTimer(const char* pCustomName, const char* pGroup, const char* pTimer)
|
||||
{
|
||||
uint32_t nIndex = MicroProfileCustomGroupFind(pCustomName);
|
||||
if(UINT32_MAX == nIndex)
|
||||
if((uint32_t)-1 == nIndex)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -3344,7 +3344,7 @@ void MicroProfileCustomGroupAddTimer(const char* pCustomName, const char* pGroup
|
||||
MP_ASSERT(nToken != MICROPROFILE_INVALID_TOKEN); //Timer must be registered first.
|
||||
UI.Custom[nIndex].pTimers[nTimerIndex] = nToken;
|
||||
uint16_t nGroup = MicroProfileGetGroupIndex(nToken);
|
||||
UI.Custom[nIndex].nGroupMask |= (1ULL << nGroup);
|
||||
UI.Custom[nIndex].nGroupMask |= (1ll << nGroup);
|
||||
UI.Custom[nIndex].nNumTimers++;
|
||||
}
|
||||
|
||||
|
||||
@@ -62,12 +62,6 @@ else()
|
||||
-Wno-unused-parameter
|
||||
)
|
||||
|
||||
# TODO: Remove when we update to a GCC compiler that enables this
|
||||
# by default (i.e. GCC 10 or newer).
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL GNU)
|
||||
add_compile_options(-fconcepts)
|
||||
endif()
|
||||
|
||||
if (ARCHITECTURE_x86_64)
|
||||
add_compile_options("-mcx16")
|
||||
endif()
|
||||
|
||||
@@ -78,7 +78,7 @@ public:
|
||||
const s16 surround_left{samples[i + 4]};
|
||||
const s16 surround_right{samples[i + 5]};
|
||||
// Not used in the ATSC reference implementation
|
||||
[[maybe_unused]] const s16 low_frequency_effects{samples[i + 3]};
|
||||
[[maybe_unused]] const s16 low_frequency_effects { samples[i + 3] };
|
||||
|
||||
constexpr s32 clev{707}; // center mixing level coefficient
|
||||
constexpr s32 slev{707}; // surround mixing level coefficient
|
||||
|
||||
@@ -110,7 +110,6 @@ add_library(common STATIC
|
||||
common_funcs.h
|
||||
common_paths.h
|
||||
common_types.h
|
||||
concepts.h
|
||||
dynamic_library.cpp
|
||||
dynamic_library.h
|
||||
fiber.cpp
|
||||
@@ -172,6 +171,7 @@ add_library(common STATIC
|
||||
virtual_buffer.h
|
||||
wall_clock.cpp
|
||||
wall_clock.h
|
||||
web_result.h
|
||||
zstd_compression.cpp
|
||||
zstd_compression.h
|
||||
)
|
||||
|
||||
@@ -15,8 +15,7 @@
|
||||
namespace Common {
|
||||
|
||||
template <class ForwardIt, class T, class Compare = std::less<>>
|
||||
[[nodiscard]] ForwardIt BinaryFind(ForwardIt first, ForwardIt last, const T& value,
|
||||
Compare comp = {}) {
|
||||
ForwardIt BinaryFind(ForwardIt first, ForwardIt last, const T& value, Compare comp = {}) {
|
||||
// Note: BOTH type T and the type after ForwardIt is dereferenced
|
||||
// must be implicitly convertible to BOTH Type1 and Type2, used in Compare.
|
||||
// This is stricter than lower_bound requirement (see above)
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
namespace Common {
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]] constexpr T AlignUp(T value, std::size_t size) {
|
||||
constexpr T AlignUp(T value, std::size_t size) {
|
||||
static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");
|
||||
auto mod{static_cast<T>(value % size)};
|
||||
value -= mod;
|
||||
@@ -17,31 +17,31 @@ template <typename T>
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]] constexpr T AlignDown(T value, std::size_t size) {
|
||||
constexpr T AlignDown(T value, std::size_t size) {
|
||||
static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");
|
||||
return static_cast<T>(value - value % size);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]] constexpr T AlignBits(T value, std::size_t align) {
|
||||
constexpr T AlignBits(T value, std::size_t align) {
|
||||
static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");
|
||||
return static_cast<T>((value + ((1ULL << align) - 1)) >> align << align);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]] constexpr bool Is4KBAligned(T value) {
|
||||
constexpr bool Is4KBAligned(T value) {
|
||||
static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");
|
||||
return (value & 0xFFF) == 0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]] constexpr bool IsWordAligned(T value) {
|
||||
constexpr bool IsWordAligned(T value) {
|
||||
static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");
|
||||
return (value & 0b11) == 0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]] constexpr bool IsAligned(T value, std::size_t alignment) {
|
||||
constexpr bool IsAligned(T value, std::size_t alignment) {
|
||||
using U = typename std::make_unsigned<T>::type;
|
||||
const U mask = static_cast<U>(alignment - 1);
|
||||
return (value & mask) == 0;
|
||||
@@ -64,7 +64,7 @@ public:
|
||||
template <typename T2>
|
||||
constexpr AlignmentAllocator(const AlignmentAllocator<T2, Align>&) noexcept {}
|
||||
|
||||
[[nodiscard]] T* allocate(size_type n) {
|
||||
T* allocate(size_type n) {
|
||||
return static_cast<T*>(::operator new (n * sizeof(T), std::align_val_t{Align}));
|
||||
}
|
||||
|
||||
|
||||
@@ -14,55 +14,50 @@ namespace Common {
|
||||
|
||||
#if _MSC_VER
|
||||
|
||||
bool AtomicCompareAndSwap(volatile u8* pointer, u8 value, u8 expected) {
|
||||
const u8 result =
|
||||
_InterlockedCompareExchange8(reinterpret_cast<volatile char*>(pointer), value, expected);
|
||||
bool AtomicCompareAndSwap(u8 volatile* pointer, u8 value, u8 expected) {
|
||||
u8 result = _InterlockedCompareExchange8((char*)pointer, value, expected);
|
||||
return result == expected;
|
||||
}
|
||||
|
||||
bool AtomicCompareAndSwap(volatile u16* pointer, u16 value, u16 expected) {
|
||||
const u16 result =
|
||||
_InterlockedCompareExchange16(reinterpret_cast<volatile short*>(pointer), value, expected);
|
||||
bool AtomicCompareAndSwap(u16 volatile* pointer, u16 value, u16 expected) {
|
||||
u16 result = _InterlockedCompareExchange16((short*)pointer, value, expected);
|
||||
return result == expected;
|
||||
}
|
||||
|
||||
bool AtomicCompareAndSwap(volatile u32* pointer, u32 value, u32 expected) {
|
||||
const u32 result =
|
||||
_InterlockedCompareExchange(reinterpret_cast<volatile long*>(pointer), value, expected);
|
||||
bool AtomicCompareAndSwap(u32 volatile* pointer, u32 value, u32 expected) {
|
||||
u32 result = _InterlockedCompareExchange((long*)pointer, value, expected);
|
||||
return result == expected;
|
||||
}
|
||||
|
||||
bool AtomicCompareAndSwap(volatile u64* pointer, u64 value, u64 expected) {
|
||||
const u64 result = _InterlockedCompareExchange64(reinterpret_cast<volatile __int64*>(pointer),
|
||||
value, expected);
|
||||
bool AtomicCompareAndSwap(u64 volatile* pointer, u64 value, u64 expected) {
|
||||
u64 result = _InterlockedCompareExchange64((__int64*)pointer, value, expected);
|
||||
return result == expected;
|
||||
}
|
||||
|
||||
bool AtomicCompareAndSwap(volatile u64* pointer, u128 value, u128 expected) {
|
||||
return _InterlockedCompareExchange128(reinterpret_cast<volatile __int64*>(pointer), value[1],
|
||||
value[0],
|
||||
reinterpret_cast<__int64*>(expected.data())) != 0;
|
||||
bool AtomicCompareAndSwap(u64 volatile* pointer, u128 value, u128 expected) {
|
||||
return _InterlockedCompareExchange128((__int64*)pointer, value[1], value[0],
|
||||
(__int64*)expected.data()) != 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
bool AtomicCompareAndSwap(volatile u8* pointer, u8 value, u8 expected) {
|
||||
bool AtomicCompareAndSwap(u8 volatile* pointer, u8 value, u8 expected) {
|
||||
return __sync_bool_compare_and_swap(pointer, expected, value);
|
||||
}
|
||||
|
||||
bool AtomicCompareAndSwap(volatile u16* pointer, u16 value, u16 expected) {
|
||||
bool AtomicCompareAndSwap(u16 volatile* pointer, u16 value, u16 expected) {
|
||||
return __sync_bool_compare_and_swap(pointer, expected, value);
|
||||
}
|
||||
|
||||
bool AtomicCompareAndSwap(volatile u32* pointer, u32 value, u32 expected) {
|
||||
bool AtomicCompareAndSwap(u32 volatile* pointer, u32 value, u32 expected) {
|
||||
return __sync_bool_compare_and_swap(pointer, expected, value);
|
||||
}
|
||||
|
||||
bool AtomicCompareAndSwap(volatile u64* pointer, u64 value, u64 expected) {
|
||||
bool AtomicCompareAndSwap(u64 volatile* pointer, u64 value, u64 expected) {
|
||||
return __sync_bool_compare_and_swap(pointer, expected, value);
|
||||
}
|
||||
|
||||
bool AtomicCompareAndSwap(volatile u64* pointer, u128 value, u128 expected) {
|
||||
bool AtomicCompareAndSwap(u64 volatile* pointer, u128 value, u128 expected) {
|
||||
unsigned __int128 value_a;
|
||||
unsigned __int128 expected_a;
|
||||
std::memcpy(&value_a, value.data(), sizeof(u128));
|
||||
|
||||
@@ -8,10 +8,10 @@
|
||||
|
||||
namespace Common {
|
||||
|
||||
[[nodiscard]] bool AtomicCompareAndSwap(volatile u8* pointer, u8 value, u8 expected);
|
||||
[[nodiscard]] bool AtomicCompareAndSwap(volatile u16* pointer, u16 value, u16 expected);
|
||||
[[nodiscard]] bool AtomicCompareAndSwap(volatile u32* pointer, u32 value, u32 expected);
|
||||
[[nodiscard]] bool AtomicCompareAndSwap(volatile u64* pointer, u64 value, u64 expected);
|
||||
[[nodiscard]] bool AtomicCompareAndSwap(volatile u64* pointer, u128 value, u128 expected);
|
||||
bool AtomicCompareAndSwap(u8 volatile* pointer, u8 value, u8 expected);
|
||||
bool AtomicCompareAndSwap(u16 volatile* pointer, u16 value, u16 expected);
|
||||
bool AtomicCompareAndSwap(u32 volatile* pointer, u32 value, u32 expected);
|
||||
bool AtomicCompareAndSwap(u64 volatile* pointer, u64 value, u64 expected);
|
||||
bool AtomicCompareAndSwap(u64 volatile* pointer, u128 value, u128 expected);
|
||||
|
||||
} // namespace Common
|
||||
|
||||
@@ -36,6 +36,13 @@
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/swap.h"
|
||||
|
||||
// Inlining
|
||||
#ifdef _WIN32
|
||||
#define FORCE_INLINE __forceinline
|
||||
#else
|
||||
#define FORCE_INLINE inline __attribute__((always_inline))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Abstract bitfield class
|
||||
*
|
||||
@@ -135,8 +142,8 @@ public:
|
||||
* containing several bitfields can be assembled by formatting each of their values and ORing
|
||||
* the results together.
|
||||
*/
|
||||
[[nodiscard]] static constexpr StorageType FormatValue(const T& value) {
|
||||
return (static_cast<StorageType>(value) << position) & mask;
|
||||
static constexpr FORCE_INLINE StorageType FormatValue(const T& value) {
|
||||
return ((StorageType)value << position) & mask;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -144,7 +151,7 @@ public:
|
||||
* (such as Value() or operator T), but this can be used to extract a value from a bitfield
|
||||
* union in a constexpr context.
|
||||
*/
|
||||
[[nodiscard]] static constexpr T ExtractValue(const StorageType& storage) {
|
||||
static constexpr FORCE_INLINE T ExtractValue(const StorageType& storage) {
|
||||
if constexpr (std::numeric_limits<UnderlyingType>::is_signed) {
|
||||
std::size_t shift = 8 * sizeof(T) - bits;
|
||||
return static_cast<T>(static_cast<UnderlyingType>(storage << (shift - position)) >>
|
||||
@@ -168,7 +175,7 @@ public:
|
||||
constexpr BitField(BitField&&) noexcept = default;
|
||||
constexpr BitField& operator=(BitField&&) noexcept = default;
|
||||
|
||||
[[nodiscard]] constexpr operator T() const {
|
||||
constexpr operator T() const {
|
||||
return Value();
|
||||
}
|
||||
|
||||
@@ -176,11 +183,11 @@ public:
|
||||
storage = static_cast<StorageType>((storage & ~mask) | FormatValue(value));
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr T Value() const {
|
||||
constexpr T Value() const {
|
||||
return ExtractValue(storage);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr explicit operator bool() const {
|
||||
constexpr explicit operator bool() const {
|
||||
return Value() != 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,12 +17,12 @@ namespace Common {
|
||||
|
||||
/// Gets the size of a specified type T in bits.
|
||||
template <typename T>
|
||||
[[nodiscard]] constexpr std::size_t BitSize() {
|
||||
constexpr std::size_t BitSize() {
|
||||
return sizeof(T) * CHAR_BIT;
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
[[nodiscard]] inline u32 CountLeadingZeroes32(u32 value) {
|
||||
inline u32 CountLeadingZeroes32(u32 value) {
|
||||
unsigned long leading_zero = 0;
|
||||
|
||||
if (_BitScanReverse(&leading_zero, value) != 0) {
|
||||
@@ -32,7 +32,7 @@ template <typename T>
|
||||
return 32;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline u32 CountLeadingZeroes64(u64 value) {
|
||||
inline u32 CountLeadingZeroes64(u64 value) {
|
||||
unsigned long leading_zero = 0;
|
||||
|
||||
if (_BitScanReverse64(&leading_zero, value) != 0) {
|
||||
@@ -42,7 +42,7 @@ template <typename T>
|
||||
return 64;
|
||||
}
|
||||
#else
|
||||
[[nodiscard]] inline u32 CountLeadingZeroes32(u32 value) {
|
||||
inline u32 CountLeadingZeroes32(u32 value) {
|
||||
if (value == 0) {
|
||||
return 32;
|
||||
}
|
||||
@@ -50,7 +50,7 @@ template <typename T>
|
||||
return static_cast<u32>(__builtin_clz(value));
|
||||
}
|
||||
|
||||
[[nodiscard]] inline u32 CountLeadingZeroes64(u64 value) {
|
||||
inline u32 CountLeadingZeroes64(u64 value) {
|
||||
if (value == 0) {
|
||||
return 64;
|
||||
}
|
||||
@@ -60,7 +60,7 @@ template <typename T>
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
[[nodiscard]] inline u32 CountTrailingZeroes32(u32 value) {
|
||||
inline u32 CountTrailingZeroes32(u32 value) {
|
||||
unsigned long trailing_zero = 0;
|
||||
|
||||
if (_BitScanForward(&trailing_zero, value) != 0) {
|
||||
@@ -70,7 +70,7 @@ template <typename T>
|
||||
return 32;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline u32 CountTrailingZeroes64(u64 value) {
|
||||
inline u32 CountTrailingZeroes64(u64 value) {
|
||||
unsigned long trailing_zero = 0;
|
||||
|
||||
if (_BitScanForward64(&trailing_zero, value) != 0) {
|
||||
@@ -80,7 +80,7 @@ template <typename T>
|
||||
return 64;
|
||||
}
|
||||
#else
|
||||
[[nodiscard]] inline u32 CountTrailingZeroes32(u32 value) {
|
||||
inline u32 CountTrailingZeroes32(u32 value) {
|
||||
if (value == 0) {
|
||||
return 32;
|
||||
}
|
||||
@@ -88,7 +88,7 @@ template <typename T>
|
||||
return static_cast<u32>(__builtin_ctz(value));
|
||||
}
|
||||
|
||||
[[nodiscard]] inline u32 CountTrailingZeroes64(u64 value) {
|
||||
inline u32 CountTrailingZeroes64(u64 value) {
|
||||
if (value == 0) {
|
||||
return 64;
|
||||
}
|
||||
@@ -99,13 +99,13 @@ template <typename T>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
[[nodiscard]] inline u32 MostSignificantBit32(const u32 value) {
|
||||
inline u32 MostSignificantBit32(const u32 value) {
|
||||
unsigned long result;
|
||||
_BitScanReverse(&result, value);
|
||||
return static_cast<u32>(result);
|
||||
}
|
||||
|
||||
[[nodiscard]] inline u32 MostSignificantBit64(const u64 value) {
|
||||
inline u32 MostSignificantBit64(const u64 value) {
|
||||
unsigned long result;
|
||||
_BitScanReverse64(&result, value);
|
||||
return static_cast<u32>(result);
|
||||
@@ -113,30 +113,30 @@ template <typename T>
|
||||
|
||||
#else
|
||||
|
||||
[[nodiscard]] inline u32 MostSignificantBit32(const u32 value) {
|
||||
inline u32 MostSignificantBit32(const u32 value) {
|
||||
return 31U - static_cast<u32>(__builtin_clz(value));
|
||||
}
|
||||
|
||||
[[nodiscard]] inline u32 MostSignificantBit64(const u64 value) {
|
||||
inline u32 MostSignificantBit64(const u64 value) {
|
||||
return 63U - static_cast<u32>(__builtin_clzll(value));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
[[nodiscard]] inline u32 Log2Floor32(const u32 value) {
|
||||
inline u32 Log2Floor32(const u32 value) {
|
||||
return MostSignificantBit32(value);
|
||||
}
|
||||
|
||||
[[nodiscard]] inline u32 Log2Ceil32(const u32 value) {
|
||||
inline u32 Log2Ceil32(const u32 value) {
|
||||
const u32 log2_f = Log2Floor32(value);
|
||||
return log2_f + ((value ^ (1U << log2_f)) != 0U);
|
||||
}
|
||||
|
||||
[[nodiscard]] inline u32 Log2Floor64(const u64 value) {
|
||||
inline u32 Log2Floor64(const u64 value) {
|
||||
return MostSignificantBit64(value);
|
||||
}
|
||||
|
||||
[[nodiscard]] inline u32 Log2Ceil64(const u64 value) {
|
||||
inline u32 Log2Ceil64(const u64 value) {
|
||||
const u64 log2_f = static_cast<u64>(Log2Floor64(value));
|
||||
return static_cast<u32>(log2_f + ((value ^ (1ULL << log2_f)) != 0ULL));
|
||||
}
|
||||
|
||||
@@ -61,43 +61,42 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <utility>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h> // for std::size_t.
|
||||
|
||||
namespace Common {
|
||||
|
||||
using uint128 = std::pair<uint64_t, uint64_t>;
|
||||
typedef std::pair<uint64_t, uint64_t> uint128;
|
||||
|
||||
[[nodiscard]] inline uint64_t Uint128Low64(const uint128& x) {
|
||||
inline uint64_t Uint128Low64(const uint128& x) {
|
||||
return x.first;
|
||||
}
|
||||
[[nodiscard]] inline uint64_t Uint128High64(const uint128& x) {
|
||||
inline uint64_t Uint128High64(const uint128& x) {
|
||||
return x.second;
|
||||
}
|
||||
|
||||
// Hash function for a byte array.
|
||||
[[nodiscard]] uint64_t CityHash64(const char* buf, std::size_t len);
|
||||
uint64_t CityHash64(const char* buf, std::size_t len);
|
||||
|
||||
// Hash function for a byte array. For convenience, a 64-bit seed is also
|
||||
// hashed into the result.
|
||||
[[nodiscard]] uint64_t CityHash64WithSeed(const char* buf, std::size_t len, uint64_t seed);
|
||||
uint64_t CityHash64WithSeed(const char* buf, std::size_t len, uint64_t seed);
|
||||
|
||||
// Hash function for a byte array. For convenience, two seeds are also
|
||||
// hashed into the result.
|
||||
[[nodiscard]] uint64_t CityHash64WithSeeds(const char* buf, std::size_t len, uint64_t seed0,
|
||||
uint64_t seed1);
|
||||
uint64_t CityHash64WithSeeds(const char* buf, std::size_t len, uint64_t seed0, uint64_t seed1);
|
||||
|
||||
// Hash function for a byte array.
|
||||
[[nodiscard]] uint128 CityHash128(const char* s, std::size_t len);
|
||||
uint128 CityHash128(const char* s, std::size_t len);
|
||||
|
||||
// Hash function for a byte array. For convenience, a 128-bit seed is also
|
||||
// hashed into the result.
|
||||
[[nodiscard]] uint128 CityHash128WithSeed(const char* s, std::size_t len, uint128 seed);
|
||||
uint128 CityHash128WithSeed(const char* s, std::size_t len, uint128 seed);
|
||||
|
||||
// Hash 128 input bits down to 64 bits of output.
|
||||
// This is intended to be a reasonably good hash function.
|
||||
[[nodiscard]] inline uint64_t Hash128to64(const uint128& x) {
|
||||
inline uint64_t Hash128to64(const uint128& x) {
|
||||
// Murmur-inspired hashing.
|
||||
const uint64_t kMul = 0x9ddfea08eb382d69ULL;
|
||||
uint64_t a = (Uint128Low64(x) ^ Uint128High64(x)) * kMul;
|
||||
|
||||
@@ -13,42 +13,42 @@
|
||||
namespace Color {
|
||||
|
||||
/// Convert a 1-bit color component to 8 bit
|
||||
[[nodiscard]] constexpr u8 Convert1To8(u8 value) {
|
||||
constexpr u8 Convert1To8(u8 value) {
|
||||
return value * 255;
|
||||
}
|
||||
|
||||
/// Convert a 4-bit color component to 8 bit
|
||||
[[nodiscard]] constexpr u8 Convert4To8(u8 value) {
|
||||
constexpr u8 Convert4To8(u8 value) {
|
||||
return (value << 4) | value;
|
||||
}
|
||||
|
||||
/// Convert a 5-bit color component to 8 bit
|
||||
[[nodiscard]] constexpr u8 Convert5To8(u8 value) {
|
||||
constexpr u8 Convert5To8(u8 value) {
|
||||
return (value << 3) | (value >> 2);
|
||||
}
|
||||
|
||||
/// Convert a 6-bit color component to 8 bit
|
||||
[[nodiscard]] constexpr u8 Convert6To8(u8 value) {
|
||||
constexpr u8 Convert6To8(u8 value) {
|
||||
return (value << 2) | (value >> 4);
|
||||
}
|
||||
|
||||
/// Convert a 8-bit color component to 1 bit
|
||||
[[nodiscard]] constexpr u8 Convert8To1(u8 value) {
|
||||
constexpr u8 Convert8To1(u8 value) {
|
||||
return value >> 7;
|
||||
}
|
||||
|
||||
/// Convert a 8-bit color component to 4 bit
|
||||
[[nodiscard]] constexpr u8 Convert8To4(u8 value) {
|
||||
constexpr u8 Convert8To4(u8 value) {
|
||||
return value >> 4;
|
||||
}
|
||||
|
||||
/// Convert a 8-bit color component to 5 bit
|
||||
[[nodiscard]] constexpr u8 Convert8To5(u8 value) {
|
||||
constexpr u8 Convert8To5(u8 value) {
|
||||
return value >> 3;
|
||||
}
|
||||
|
||||
/// Convert a 8-bit color component to 6 bit
|
||||
[[nodiscard]] constexpr u8 Convert8To6(u8 value) {
|
||||
constexpr u8 Convert8To6(u8 value) {
|
||||
return value >> 2;
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ namespace Color {
|
||||
* @param bytes Pointer to encoded source color
|
||||
* @return Result color decoded as Common::Vec4<u8>
|
||||
*/
|
||||
[[nodiscard]] inline Common::Vec4<u8> DecodeRGBA8(const u8* bytes) {
|
||||
inline Common::Vec4<u8> DecodeRGBA8(const u8* bytes) {
|
||||
return {bytes[3], bytes[2], bytes[1], bytes[0]};
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ namespace Color {
|
||||
* @param bytes Pointer to encoded source color
|
||||
* @return Result color decoded as Common::Vec4<u8>
|
||||
*/
|
||||
[[nodiscard]] inline Common::Vec4<u8> DecodeRGB8(const u8* bytes) {
|
||||
inline Common::Vec4<u8> DecodeRGB8(const u8* bytes) {
|
||||
return {bytes[2], bytes[1], bytes[0], 255};
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ namespace Color {
|
||||
* @param bytes Pointer to encoded source color
|
||||
* @return Result color decoded as Common::Vec4<u8>
|
||||
*/
|
||||
[[nodiscard]] inline Common::Vec4<u8> DecodeRG8(const u8* bytes) {
|
||||
inline Common::Vec4<u8> DecodeRG8(const u8* bytes) {
|
||||
return {bytes[1], bytes[0], 0, 255};
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ namespace Color {
|
||||
* @param bytes Pointer to encoded source color
|
||||
* @return Result color decoded as Common::Vec4<u8>
|
||||
*/
|
||||
[[nodiscard]] inline Common::Vec4<u8> DecodeRGB565(const u8* bytes) {
|
||||
inline Common::Vec4<u8> DecodeRGB565(const u8* bytes) {
|
||||
u16_le pixel;
|
||||
std::memcpy(&pixel, bytes, sizeof(pixel));
|
||||
return {Convert5To8((pixel >> 11) & 0x1F), Convert6To8((pixel >> 5) & 0x3F),
|
||||
@@ -96,7 +96,7 @@ namespace Color {
|
||||
* @param bytes Pointer to encoded source color
|
||||
* @return Result color decoded as Common::Vec4<u8>
|
||||
*/
|
||||
[[nodiscard]] inline Common::Vec4<u8> DecodeRGB5A1(const u8* bytes) {
|
||||
inline Common::Vec4<u8> DecodeRGB5A1(const u8* bytes) {
|
||||
u16_le pixel;
|
||||
std::memcpy(&pixel, bytes, sizeof(pixel));
|
||||
return {Convert5To8((pixel >> 11) & 0x1F), Convert5To8((pixel >> 6) & 0x1F),
|
||||
@@ -108,7 +108,7 @@ namespace Color {
|
||||
* @param bytes Pointer to encoded source color
|
||||
* @return Result color decoded as Common::Vec4<u8>
|
||||
*/
|
||||
[[nodiscard]] inline Common::Vec4<u8> DecodeRGBA4(const u8* bytes) {
|
||||
inline Common::Vec4<u8> DecodeRGBA4(const u8* bytes) {
|
||||
u16_le pixel;
|
||||
std::memcpy(&pixel, bytes, sizeof(pixel));
|
||||
return {Convert4To8((pixel >> 12) & 0xF), Convert4To8((pixel >> 8) & 0xF),
|
||||
@@ -120,7 +120,7 @@ namespace Color {
|
||||
* @param bytes Pointer to encoded source value
|
||||
* @return Depth value as an u32
|
||||
*/
|
||||
[[nodiscard]] inline u32 DecodeD16(const u8* bytes) {
|
||||
inline u32 DecodeD16(const u8* bytes) {
|
||||
u16_le data;
|
||||
std::memcpy(&data, bytes, sizeof(data));
|
||||
return data;
|
||||
@@ -131,7 +131,7 @@ namespace Color {
|
||||
* @param bytes Pointer to encoded source value
|
||||
* @return Depth value as an u32
|
||||
*/
|
||||
[[nodiscard]] inline u32 DecodeD24(const u8* bytes) {
|
||||
inline u32 DecodeD24(const u8* bytes) {
|
||||
return (bytes[2] << 16) | (bytes[1] << 8) | bytes[0];
|
||||
}
|
||||
|
||||
@@ -140,7 +140,7 @@ namespace Color {
|
||||
* @param bytes Pointer to encoded source values
|
||||
* @return Resulting values stored as a Common::Vec2
|
||||
*/
|
||||
[[nodiscard]] inline Common::Vec2<u32> DecodeD24S8(const u8* bytes) {
|
||||
inline Common::Vec2<u32> DecodeD24S8(const u8* bytes) {
|
||||
return {static_cast<u32>((bytes[2] << 16) | (bytes[1] << 8) | bytes[0]), bytes[3]};
|
||||
}
|
||||
|
||||
|
||||
@@ -53,14 +53,14 @@ __declspec(dllimport) void __stdcall DebugBreak(void);
|
||||
// Call directly after the command or use the error num.
|
||||
// This function might change the error code.
|
||||
// Defined in Misc.cpp.
|
||||
[[nodiscard]] std::string GetLastErrorMsg();
|
||||
std::string GetLastErrorMsg();
|
||||
|
||||
#define DECLARE_ENUM_FLAG_OPERATORS(type) \
|
||||
[[nodiscard]] constexpr type operator|(type a, type b) noexcept { \
|
||||
constexpr type operator|(type a, type b) noexcept { \
|
||||
using T = std::underlying_type_t<type>; \
|
||||
return static_cast<type>(static_cast<T>(a) | static_cast<T>(b)); \
|
||||
} \
|
||||
[[nodiscard]] constexpr type operator&(type a, type b) noexcept { \
|
||||
constexpr type operator&(type a, type b) noexcept { \
|
||||
using T = std::underlying_type_t<type>; \
|
||||
return static_cast<type>(static_cast<T>(a) & static_cast<T>(b)); \
|
||||
} \
|
||||
@@ -74,22 +74,22 @@ __declspec(dllimport) void __stdcall DebugBreak(void);
|
||||
a = static_cast<type>(static_cast<T>(a) & static_cast<T>(b)); \
|
||||
return a; \
|
||||
} \
|
||||
[[nodiscard]] constexpr type operator~(type key) noexcept { \
|
||||
constexpr type operator~(type key) noexcept { \
|
||||
using T = std::underlying_type_t<type>; \
|
||||
return static_cast<type>(~static_cast<T>(key)); \
|
||||
} \
|
||||
[[nodiscard]] constexpr bool True(type key) noexcept { \
|
||||
constexpr bool True(type key) noexcept { \
|
||||
using T = std::underlying_type_t<type>; \
|
||||
return static_cast<T>(key) != 0; \
|
||||
} \
|
||||
[[nodiscard]] constexpr bool False(type key) noexcept { \
|
||||
constexpr bool False(type key) noexcept { \
|
||||
using T = std::underlying_type_t<type>; \
|
||||
return static_cast<T>(key) == 0; \
|
||||
}
|
||||
|
||||
namespace Common {
|
||||
|
||||
[[nodiscard]] constexpr u32 MakeMagic(char a, char b, char c, char d) {
|
||||
constexpr u32 MakeMagic(char a, char b, char c, char d) {
|
||||
return u32(a) | u32(b) << 8 | u32(c) << 16 | u32(d) << 24;
|
||||
}
|
||||
|
||||
|
||||
@@ -35,7 +35,6 @@
|
||||
#define KEYS_DIR "keys"
|
||||
#define LOAD_DIR "load"
|
||||
#define DUMP_DIR "dump"
|
||||
#define SCREENSHOTS_DIR "screenshots"
|
||||
#define SHADER_DIR "shader"
|
||||
#define LOG_DIR "log"
|
||||
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
// Copyright 2020 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace Common {
|
||||
|
||||
// Check if type is like an STL container
|
||||
template <typename T>
|
||||
concept IsSTLContainer = requires(T t) {
|
||||
typename T::value_type;
|
||||
typename T::iterator;
|
||||
typename T::const_iterator;
|
||||
// TODO(ogniK): Replace below is std::same_as<void> when MSVC supports it.
|
||||
t.begin();
|
||||
t.end();
|
||||
t.cbegin();
|
||||
t.cend();
|
||||
t.data();
|
||||
t.size();
|
||||
};
|
||||
|
||||
// TODO: Replace with std::derived_from when the <concepts> header
|
||||
// is available on all supported platforms.
|
||||
template <typename Derived, typename Base>
|
||||
concept DerivedFrom = requires {
|
||||
std::is_base_of_v<Base, Derived>;
|
||||
std::is_convertible_v<const volatile Derived*, const volatile Base*>;
|
||||
};
|
||||
|
||||
} // namespace Common
|
||||
@@ -34,7 +34,8 @@ void DetachedTasks::AddTask(std::function<void()> task) {
|
||||
std::unique_lock lock{instance->mutex};
|
||||
--instance->count;
|
||||
std::notify_all_at_thread_exit(instance->cv, std::move(lock));
|
||||
}).detach();
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
|
||||
} // namespace Common
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace Common {
|
||||
DynamicLibrary::DynamicLibrary() = default;
|
||||
|
||||
DynamicLibrary::DynamicLibrary(const char* filename) {
|
||||
void(Open(filename));
|
||||
Open(filename);
|
||||
}
|
||||
|
||||
DynamicLibrary::DynamicLibrary(DynamicLibrary&& rhs) noexcept
|
||||
|
||||
@@ -33,7 +33,7 @@ public:
|
||||
~DynamicLibrary();
|
||||
|
||||
/// Returns the specified library name with the platform-specific suffix added.
|
||||
[[nodiscard]] static std::string GetUnprefixedFilename(const char* filename);
|
||||
static std::string GetUnprefixedFilename(const char* filename);
|
||||
|
||||
/// Returns the specified library name in platform-specific format.
|
||||
/// Major/minor versions will not be included if set to -1.
|
||||
@@ -41,29 +41,28 @@ public:
|
||||
/// Windows: LIBNAME-MAJOR-MINOR.dll
|
||||
/// Linux: libLIBNAME.so.MAJOR.MINOR
|
||||
/// Mac: libLIBNAME.MAJOR.MINOR.dylib
|
||||
[[nodiscard]] static std::string GetVersionedFilename(const char* libname, int major = -1,
|
||||
int minor = -1);
|
||||
static std::string GetVersionedFilename(const char* libname, int major = -1, int minor = -1);
|
||||
|
||||
/// Returns true if a module is loaded, otherwise false.
|
||||
[[nodiscard]] bool IsOpen() const {
|
||||
bool IsOpen() const {
|
||||
return handle != nullptr;
|
||||
}
|
||||
|
||||
/// Loads (or replaces) the handle with the specified library file name.
|
||||
/// Returns true if the library was loaded and can be used.
|
||||
[[nodiscard]] bool Open(const char* filename);
|
||||
bool Open(const char* filename);
|
||||
|
||||
/// Unloads the library, any function pointers from this library are no longer valid.
|
||||
void Close();
|
||||
|
||||
/// Returns the address of the specified symbol (function or variable) as an untyped pointer.
|
||||
/// If the specified symbol does not exist in this library, nullptr is returned.
|
||||
[[nodiscard]] void* GetSymbolAddress(const char* name) const;
|
||||
void* GetSymbolAddress(const char* name) const;
|
||||
|
||||
/// Obtains the address of the specified symbol, automatically casting to the correct type.
|
||||
/// Returns true if the symbol was found and assigned, otherwise false.
|
||||
template <typename T>
|
||||
[[nodiscard]] bool GetSymbol(const char* name, T* ptr) const {
|
||||
bool GetSymbol(const char* name, T* ptr) const {
|
||||
*ptr = reinterpret_cast<T>(GetSymbolAddress(name));
|
||||
return *ptr != nullptr;
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ public:
|
||||
/// Yields control from Fiber 'from' to Fiber 'to'
|
||||
/// Fiber 'from' must be the currently running fiber.
|
||||
static void YieldTo(std::shared_ptr<Fiber>& from, std::shared_ptr<Fiber>& to);
|
||||
[[nodiscard]] static std::shared_ptr<Fiber> ThreadToFiber();
|
||||
static std::shared_ptr<Fiber> ThreadToFiber();
|
||||
|
||||
void SetRewindPoint(std::function<void(void*)>&& rewind_func, void* start_parameter);
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
// This namespace has various generic functions related to files and paths.
|
||||
// The code still needs a ton of cleanup.
|
||||
// REMEMBER: strdup considered harmful!
|
||||
namespace Common::FS {
|
||||
namespace FileUtil {
|
||||
|
||||
// Remove any ending forward slashes from directory paths
|
||||
// Modifies argument.
|
||||
@@ -196,7 +196,7 @@ bool CreateFullPath(const std::string& fullPath) {
|
||||
int panicCounter = 100;
|
||||
LOG_TRACE(Common_Filesystem, "path {}", fullPath);
|
||||
|
||||
if (Exists(fullPath)) {
|
||||
if (FileUtil::Exists(fullPath)) {
|
||||
LOG_DEBUG(Common_Filesystem, "path exists {}", fullPath);
|
||||
return true;
|
||||
}
|
||||
@@ -212,7 +212,7 @@ bool CreateFullPath(const std::string& fullPath) {
|
||||
|
||||
// Include the '/' so the first call is CreateDir("/") rather than CreateDir("")
|
||||
std::string const subPath(fullPath.substr(0, position + 1));
|
||||
if (!IsDirectory(subPath) && !CreateDir(subPath)) {
|
||||
if (!FileUtil::IsDirectory(subPath) && !FileUtil::CreateDir(subPath)) {
|
||||
LOG_ERROR(Common, "CreateFullPath: directory creation failed");
|
||||
return false;
|
||||
}
|
||||
@@ -231,7 +231,7 @@ bool DeleteDir(const std::string& filename) {
|
||||
LOG_TRACE(Common_Filesystem, "directory {}", filename);
|
||||
|
||||
// check if a directory
|
||||
if (!IsDirectory(filename)) {
|
||||
if (!FileUtil::IsDirectory(filename)) {
|
||||
LOG_ERROR(Common_Filesystem, "Not a directory {}", filename);
|
||||
return false;
|
||||
}
|
||||
@@ -371,7 +371,7 @@ u64 GetSize(FILE* f) {
|
||||
bool CreateEmptyFile(const std::string& filename) {
|
||||
LOG_TRACE(Common_Filesystem, "{}", filename);
|
||||
|
||||
if (!IOFile(filename, "wb").IsOpen()) {
|
||||
if (!FileUtil::IOFile(filename, "wb").IsOpen()) {
|
||||
LOG_ERROR(Common_Filesystem, "failed {}: {}", filename, GetLastErrorMsg());
|
||||
return false;
|
||||
}
|
||||
@@ -488,34 +488,29 @@ bool DeleteDirRecursively(const std::string& directory, unsigned int recursion)
|
||||
return false;
|
||||
|
||||
// Delete the outermost directory
|
||||
DeleteDir(directory);
|
||||
FileUtil::DeleteDir(directory);
|
||||
return true;
|
||||
}
|
||||
|
||||
void CopyDir(const std::string& source_path, const std::string& dest_path) {
|
||||
#ifndef _WIN32
|
||||
if (source_path == dest_path) {
|
||||
if (source_path == dest_path)
|
||||
return;
|
||||
}
|
||||
if (!Exists(source_path)) {
|
||||
if (!FileUtil::Exists(source_path))
|
||||
return;
|
||||
}
|
||||
if (!Exists(dest_path)) {
|
||||
CreateFullPath(dest_path);
|
||||
}
|
||||
if (!FileUtil::Exists(dest_path))
|
||||
FileUtil::CreateFullPath(dest_path);
|
||||
|
||||
DIR* dirp = opendir(source_path.c_str());
|
||||
if (!dirp) {
|
||||
if (!dirp)
|
||||
return;
|
||||
}
|
||||
|
||||
while (struct dirent* result = readdir(dirp)) {
|
||||
const std::string virtualName(result->d_name);
|
||||
// check for "." and ".."
|
||||
if (((virtualName[0] == '.') && (virtualName[1] == '\0')) ||
|
||||
((virtualName[0] == '.') && (virtualName[1] == '.') && (virtualName[2] == '\0'))) {
|
||||
((virtualName[0] == '.') && (virtualName[1] == '.') && (virtualName[2] == '\0')))
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string source, dest;
|
||||
source = source_path + virtualName;
|
||||
@@ -523,13 +518,11 @@ void CopyDir(const std::string& source_path, const std::string& dest_path) {
|
||||
if (IsDirectory(source)) {
|
||||
source += '/';
|
||||
dest += '/';
|
||||
if (!Exists(dest)) {
|
||||
CreateFullPath(dest);
|
||||
}
|
||||
if (!FileUtil::Exists(dest))
|
||||
FileUtil::CreateFullPath(dest);
|
||||
CopyDir(source, dest);
|
||||
} else if (!Exists(dest)) {
|
||||
Copy(source, dest);
|
||||
}
|
||||
} else if (!FileUtil::Exists(dest))
|
||||
FileUtil::Copy(source, dest);
|
||||
}
|
||||
closedir(dirp);
|
||||
#endif
|
||||
@@ -545,7 +538,7 @@ std::optional<std::string> GetCurrentDir() {
|
||||
if (!dir) {
|
||||
#endif
|
||||
LOG_ERROR(Common_Filesystem, "GetCurrentDirectory failed: {}", GetLastErrorMsg());
|
||||
return std::nullopt;
|
||||
return {};
|
||||
}
|
||||
#ifdef _WIN32
|
||||
std::string strDir = Common::UTF16ToUTF8(dir);
|
||||
@@ -553,7 +546,7 @@ std::optional<std::string> GetCurrentDir() {
|
||||
std::string strDir = dir;
|
||||
#endif
|
||||
free(dir);
|
||||
return std::move(strDir);
|
||||
return strDir;
|
||||
}
|
||||
|
||||
bool SetCurrentDir(const std::string& directory) {
|
||||
@@ -675,7 +668,7 @@ const std::string& GetUserPath(UserPath path, const std::string& new_path) {
|
||||
if (user_path.empty()) {
|
||||
#ifdef _WIN32
|
||||
user_path = GetExeDirectory() + DIR_SEP USERDATA_DIR DIR_SEP;
|
||||
if (!IsDirectory(user_path)) {
|
||||
if (!FileUtil::IsDirectory(user_path)) {
|
||||
user_path = AppDataRoamingDirectory() + DIR_SEP EMU_DATA_DIR DIR_SEP;
|
||||
} else {
|
||||
LOG_INFO(Common_Filesystem, "Using the local user directory");
|
||||
@@ -684,7 +677,7 @@ const std::string& GetUserPath(UserPath path, const std::string& new_path) {
|
||||
paths.emplace(UserPath::ConfigDir, user_path + CONFIG_DIR DIR_SEP);
|
||||
paths.emplace(UserPath::CacheDir, user_path + CACHE_DIR DIR_SEP);
|
||||
#else
|
||||
if (Exists(ROOT_DIR DIR_SEP USERDATA_DIR)) {
|
||||
if (FileUtil::Exists(ROOT_DIR DIR_SEP USERDATA_DIR)) {
|
||||
user_path = ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP;
|
||||
paths.emplace(UserPath::ConfigDir, user_path + CONFIG_DIR DIR_SEP);
|
||||
paths.emplace(UserPath::CacheDir, user_path + CACHE_DIR DIR_SEP);
|
||||
@@ -702,7 +695,6 @@ const std::string& GetUserPath(UserPath path, const std::string& new_path) {
|
||||
paths.emplace(UserPath::NANDDir, user_path + NAND_DIR DIR_SEP);
|
||||
paths.emplace(UserPath::LoadDir, user_path + LOAD_DIR DIR_SEP);
|
||||
paths.emplace(UserPath::DumpDir, user_path + DUMP_DIR DIR_SEP);
|
||||
paths.emplace(UserPath::ScreenshotsDir, user_path + SCREENSHOTS_DIR DIR_SEP);
|
||||
paths.emplace(UserPath::ShaderDir, user_path + SHADER_DIR DIR_SEP);
|
||||
paths.emplace(UserPath::SysDataDir, user_path + SYSDATA_DIR DIR_SEP);
|
||||
paths.emplace(UserPath::KeysDir, user_path + KEYS_DIR DIR_SEP);
|
||||
@@ -711,7 +703,7 @@ const std::string& GetUserPath(UserPath path, const std::string& new_path) {
|
||||
}
|
||||
|
||||
if (!new_path.empty()) {
|
||||
if (!IsDirectory(new_path)) {
|
||||
if (!FileUtil::IsDirectory(new_path)) {
|
||||
LOG_ERROR(Common_Filesystem, "Invalid path specified {}", new_path);
|
||||
return paths[path];
|
||||
} else {
|
||||
@@ -909,10 +901,10 @@ std::string SanitizePath(std::string_view path_, DirectorySeparator directory_se
|
||||
return std::string(RemoveTrailingSlash(path));
|
||||
}
|
||||
|
||||
IOFile::IOFile() = default;
|
||||
IOFile::IOFile() {}
|
||||
|
||||
IOFile::IOFile(const std::string& filename, const char openmode[], int flags) {
|
||||
void(Open(filename, openmode, flags));
|
||||
Open(filename, openmode, flags);
|
||||
}
|
||||
|
||||
IOFile::~IOFile() {
|
||||
@@ -953,18 +945,17 @@ bool IOFile::Open(const std::string& filename, const char openmode[], int flags)
|
||||
}
|
||||
|
||||
bool IOFile::Close() {
|
||||
if (!IsOpen() || 0 != std::fclose(m_file)) {
|
||||
if (!IsOpen() || 0 != std::fclose(m_file))
|
||||
return false;
|
||||
}
|
||||
|
||||
m_file = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
u64 IOFile::GetSize() const {
|
||||
if (IsOpen()) {
|
||||
return FS::GetSize(m_file);
|
||||
}
|
||||
if (IsOpen())
|
||||
return FileUtil::GetSize(m_file);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -973,9 +964,9 @@ bool IOFile::Seek(s64 off, int origin) const {
|
||||
}
|
||||
|
||||
u64 IOFile::Tell() const {
|
||||
if (IsOpen()) {
|
||||
if (IsOpen())
|
||||
return ftello(m_file);
|
||||
}
|
||||
|
||||
return std::numeric_limits<u64>::max();
|
||||
}
|
||||
|
||||
@@ -1024,4 +1015,4 @@ bool IOFile::Resize(u64 size) {
|
||||
;
|
||||
}
|
||||
|
||||
} // namespace Common::FS
|
||||
} // namespace FileUtil
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
#include "common/string_util.h"
|
||||
#endif
|
||||
|
||||
namespace Common::FS {
|
||||
namespace FileUtil {
|
||||
|
||||
// User paths for GetUserPath
|
||||
enum class UserPath {
|
||||
@@ -32,7 +32,6 @@ enum class UserPath {
|
||||
SDMCDir,
|
||||
LoadDir,
|
||||
DumpDir,
|
||||
ScreenshotsDir,
|
||||
ShaderDir,
|
||||
SysDataDir,
|
||||
UserDir,
|
||||
@@ -48,19 +47,19 @@ struct FSTEntry {
|
||||
};
|
||||
|
||||
// Returns true if file filename exists
|
||||
[[nodiscard]] bool Exists(const std::string& filename);
|
||||
bool Exists(const std::string& filename);
|
||||
|
||||
// Returns true if filename is a directory
|
||||
[[nodiscard]] bool IsDirectory(const std::string& filename);
|
||||
bool IsDirectory(const std::string& filename);
|
||||
|
||||
// Returns the size of filename (64bit)
|
||||
[[nodiscard]] u64 GetSize(const std::string& filename);
|
||||
u64 GetSize(const std::string& filename);
|
||||
|
||||
// Overloaded GetSize, accepts file descriptor
|
||||
[[nodiscard]] u64 GetSize(int fd);
|
||||
u64 GetSize(const int fd);
|
||||
|
||||
// Overloaded GetSize, accepts FILE*
|
||||
[[nodiscard]] u64 GetSize(FILE* f);
|
||||
u64 GetSize(FILE* f);
|
||||
|
||||
// Returns true if successful, or path already exists.
|
||||
bool CreateDir(const std::string& filename);
|
||||
@@ -120,7 +119,7 @@ u64 ScanDirectoryTree(const std::string& directory, FSTEntry& parent_entry,
|
||||
bool DeleteDirRecursively(const std::string& directory, unsigned int recursion = 256);
|
||||
|
||||
// Returns the current directory
|
||||
[[nodiscard]] std::optional<std::string> GetCurrentDir();
|
||||
std::optional<std::string> GetCurrentDir();
|
||||
|
||||
// Create directory and copy contents (does not overwrite existing files)
|
||||
void CopyDir(const std::string& source_path, const std::string& dest_path);
|
||||
@@ -132,20 +131,20 @@ bool SetCurrentDir(const std::string& directory);
|
||||
// directory. To be used in "multi-user" mode (that is, installed).
|
||||
const std::string& GetUserPath(UserPath path, const std::string& new_path = "");
|
||||
|
||||
[[nodiscard]] std::string GetHactoolConfigurationPath();
|
||||
std::string GetHactoolConfigurationPath();
|
||||
|
||||
[[nodiscard]] std::string GetNANDRegistrationDir(bool system = false);
|
||||
std::string GetNANDRegistrationDir(bool system = false);
|
||||
|
||||
// Returns the path to where the sys file are
|
||||
[[nodiscard]] std::string GetSysDirectory();
|
||||
std::string GetSysDirectory();
|
||||
|
||||
#ifdef __APPLE__
|
||||
[[nodiscard]] std::string GetBundleDirectory();
|
||||
std::string GetBundleDirectory();
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
[[nodiscard]] const std::string& GetExeDirectory();
|
||||
[[nodiscard]] std::string AppDataRoamingDirectory();
|
||||
const std::string& GetExeDirectory();
|
||||
std::string AppDataRoamingDirectory();
|
||||
#endif
|
||||
|
||||
std::size_t WriteStringToFile(bool text_file, const std::string& filename, std::string_view str);
|
||||
@@ -164,55 +163,38 @@ void SplitFilename83(const std::string& filename, std::array<char, 9>& short_nam
|
||||
|
||||
// Splits the path on '/' or '\' and put the components into a vector
|
||||
// i.e. "C:\Users\Yuzu\Documents\save.bin" becomes {"C:", "Users", "Yuzu", "Documents", "save.bin" }
|
||||
[[nodiscard]] std::vector<std::string> SplitPathComponents(std::string_view filename);
|
||||
std::vector<std::string> SplitPathComponents(std::string_view filename);
|
||||
|
||||
// Gets all of the text up to the last '/' or '\' in the path.
|
||||
[[nodiscard]] std::string_view GetParentPath(std::string_view path);
|
||||
std::string_view GetParentPath(std::string_view path);
|
||||
|
||||
// Gets all of the text after the first '/' or '\' in the path.
|
||||
[[nodiscard]] std::string_view GetPathWithoutTop(std::string_view path);
|
||||
std::string_view GetPathWithoutTop(std::string_view path);
|
||||
|
||||
// Gets the filename of the path
|
||||
[[nodiscard]] std::string_view GetFilename(std::string_view path);
|
||||
std::string_view GetFilename(std::string_view path);
|
||||
|
||||
// Gets the extension of the filename
|
||||
[[nodiscard]] std::string_view GetExtensionFromFilename(std::string_view name);
|
||||
std::string_view GetExtensionFromFilename(std::string_view name);
|
||||
|
||||
// Removes the final '/' or '\' if one exists
|
||||
[[nodiscard]] std::string_view RemoveTrailingSlash(std::string_view path);
|
||||
std::string_view RemoveTrailingSlash(std::string_view path);
|
||||
|
||||
// Creates a new vector containing indices [first, last) from the original.
|
||||
template <typename T>
|
||||
[[nodiscard]] std::vector<T> SliceVector(const std::vector<T>& vector, std::size_t first,
|
||||
std::size_t last) {
|
||||
if (first >= last) {
|
||||
std::vector<T> SliceVector(const std::vector<T>& vector, std::size_t first, std::size_t last) {
|
||||
if (first >= last)
|
||||
return {};
|
||||
}
|
||||
last = std::min<std::size_t>(last, vector.size());
|
||||
return std::vector<T>(vector.begin() + first, vector.begin() + first + last);
|
||||
}
|
||||
|
||||
enum class DirectorySeparator {
|
||||
ForwardSlash,
|
||||
BackwardSlash,
|
||||
PlatformDefault,
|
||||
};
|
||||
enum class DirectorySeparator { ForwardSlash, BackwardSlash, PlatformDefault };
|
||||
|
||||
// Removes trailing slash, makes all '\\' into '/', and removes duplicate '/'. Makes '/' into '\\'
|
||||
// depending if directory_separator is BackwardSlash or PlatformDefault and running on windows
|
||||
[[nodiscard]] std::string SanitizePath(
|
||||
std::string_view path,
|
||||
DirectorySeparator directory_separator = DirectorySeparator::ForwardSlash);
|
||||
|
||||
// To deal with Windows being dumb at Unicode
|
||||
template <typename T>
|
||||
void OpenFStream(T& fstream, const std::string& filename, std::ios_base::openmode openmode) {
|
||||
#ifdef _MSC_VER
|
||||
fstream.open(Common::UTF8ToUTF16W(filename), openmode);
|
||||
#else
|
||||
fstream.open(filename, openmode);
|
||||
#endif
|
||||
}
|
||||
std::string SanitizePath(std::string_view path,
|
||||
DirectorySeparator directory_separator = DirectorySeparator::ForwardSlash);
|
||||
|
||||
// simple wrapper for cstdlib file functions to
|
||||
// hopefully will make error checking easier
|
||||
@@ -232,7 +214,7 @@ public:
|
||||
|
||||
void Swap(IOFile& other) noexcept;
|
||||
|
||||
[[nodiscard]] bool Open(const std::string& filename, const char openmode[], int flags = 0);
|
||||
bool Open(const std::string& filename, const char openmode[], int flags = 0);
|
||||
bool Close();
|
||||
|
||||
template <typename T>
|
||||
@@ -273,13 +255,13 @@ public:
|
||||
return WriteArray(str.data(), str.length());
|
||||
}
|
||||
|
||||
[[nodiscard]] bool IsOpen() const {
|
||||
bool IsOpen() const {
|
||||
return nullptr != m_file;
|
||||
}
|
||||
|
||||
bool Seek(s64 off, int origin) const;
|
||||
[[nodiscard]] u64 Tell() const;
|
||||
[[nodiscard]] u64 GetSize() const;
|
||||
u64 Tell() const;
|
||||
u64 GetSize() const;
|
||||
bool Resize(u64 size);
|
||||
bool Flush();
|
||||
|
||||
@@ -295,4 +277,14 @@ private:
|
||||
std::FILE* m_file = nullptr;
|
||||
};
|
||||
|
||||
} // namespace Common::FS
|
||||
} // namespace FileUtil
|
||||
|
||||
// To deal with Windows being dumb at unicode:
|
||||
template <typename T>
|
||||
void OpenFStream(T& fstream, const std::string& filename, std::ios_base::openmode openmode) {
|
||||
#ifdef _MSC_VER
|
||||
fstream.open(Common::UTF8ToUTF16W(filename), openmode);
|
||||
#else
|
||||
fstream.open(filename, openmode);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -5,11 +5,36 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <utility>
|
||||
#include <boost/functional/hash.hpp>
|
||||
#include "common/cityhash.h"
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Common {
|
||||
|
||||
/**
|
||||
* Computes a 64-bit hash over the specified block of data
|
||||
* @param data Block of data to compute hash over
|
||||
* @param len Length of data (in bytes) to compute hash over
|
||||
* @returns 64-bit hash value that was computed over the data block
|
||||
*/
|
||||
static inline u64 ComputeHash64(const void* data, std::size_t len) {
|
||||
return CityHash64(static_cast<const char*>(data), len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes a 64-bit hash of a struct. In addition to being trivially copyable, it is also critical
|
||||
* that either the struct includes no padding, or that any padding is initialized to a known value
|
||||
* by memsetting the struct to 0 before filling it in.
|
||||
*/
|
||||
template <typename T>
|
||||
static inline u64 ComputeStructHash64(const T& data) {
|
||||
static_assert(std::is_trivially_copyable_v<T>,
|
||||
"Type passed to ComputeStructHash64 must be trivially copyable");
|
||||
return ComputeHash64(&data, sizeof(data));
|
||||
}
|
||||
|
||||
struct PairHash {
|
||||
template <class T1, class T2>
|
||||
std::size_t operator()(const std::pair<T1, T2>& pair) const noexcept {
|
||||
|
||||
@@ -3,9 +3,21 @@
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "common/hex_util.h"
|
||||
#include "common/logging/log.h"
|
||||
|
||||
namespace Common {
|
||||
|
||||
u8 ToHexNibble(char c1) {
|
||||
if (c1 >= 65 && c1 <= 70)
|
||||
return c1 - 55;
|
||||
if (c1 >= 97 && c1 <= 102)
|
||||
return c1 - 87;
|
||||
if (c1 >= 48 && c1 <= 57)
|
||||
return c1 - 48;
|
||||
LOG_ERROR(Common, "Invalid hex digit: 0x{:02X}", c1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::vector<u8> HexStringToVector(std::string_view str, bool little_endian) {
|
||||
std::vector<u8> out(str.size() / 2);
|
||||
if (little_endian) {
|
||||
@@ -18,4 +30,26 @@ std::vector<u8> HexStringToVector(std::string_view str, bool little_endian) {
|
||||
return out;
|
||||
}
|
||||
|
||||
std::array<u8, 16> operator""_array16(const char* str, std::size_t len) {
|
||||
if (len != 32) {
|
||||
LOG_ERROR(Common,
|
||||
"Attempting to parse string to array that is not of correct size (expected=32, "
|
||||
"actual={}).",
|
||||
len);
|
||||
return {};
|
||||
}
|
||||
return HexStringToArray<16>(str);
|
||||
}
|
||||
|
||||
std::array<u8, 32> operator""_array32(const char* str, std::size_t len) {
|
||||
if (len != 64) {
|
||||
LOG_ERROR(Common,
|
||||
"Attempting to parse string to array that is not of correct size (expected=64, "
|
||||
"actual={}).",
|
||||
len);
|
||||
return {};
|
||||
}
|
||||
return HexStringToArray<32>(str);
|
||||
}
|
||||
|
||||
} // namespace Common
|
||||
|
||||
@@ -14,37 +14,25 @@
|
||||
|
||||
namespace Common {
|
||||
|
||||
[[nodiscard]] constexpr u8 ToHexNibble(char c) {
|
||||
if (c >= 65 && c <= 70) {
|
||||
return c - 55;
|
||||
}
|
||||
u8 ToHexNibble(char c1);
|
||||
|
||||
if (c >= 97 && c <= 102) {
|
||||
return c - 87;
|
||||
}
|
||||
|
||||
return c - 48;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::vector<u8> HexStringToVector(std::string_view str, bool little_endian);
|
||||
std::vector<u8> HexStringToVector(std::string_view str, bool little_endian);
|
||||
|
||||
template <std::size_t Size, bool le = false>
|
||||
[[nodiscard]] constexpr std::array<u8, Size> HexStringToArray(std::string_view str) {
|
||||
std::array<u8, Size> HexStringToArray(std::string_view str) {
|
||||
std::array<u8, Size> out{};
|
||||
if constexpr (le) {
|
||||
for (std::size_t i = 2 * Size - 2; i <= 2 * Size; i -= 2) {
|
||||
for (std::size_t i = 2 * Size - 2; i <= 2 * Size; i -= 2)
|
||||
out[i / 2] = (ToHexNibble(str[i]) << 4) | ToHexNibble(str[i + 1]);
|
||||
}
|
||||
} else {
|
||||
for (std::size_t i = 0; i < 2 * Size; i += 2) {
|
||||
for (std::size_t i = 0; i < 2 * Size; i += 2)
|
||||
out[i / 2] = (ToHexNibble(str[i]) << 4) | ToHexNibble(str[i + 1]);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
template <typename ContiguousContainer>
|
||||
[[nodiscard]] std::string HexToString(const ContiguousContainer& data, bool upper = true) {
|
||||
std::string HexToString(const ContiguousContainer& data, bool upper = true) {
|
||||
static_assert(std::is_same_v<typename ContiguousContainer::value_type, u8>,
|
||||
"Underlying type within the contiguous container must be u8.");
|
||||
|
||||
@@ -60,12 +48,7 @@ template <typename ContiguousContainer>
|
||||
return out;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr std::array<u8, 16> AsArray(const char (&data)[17]) {
|
||||
return HexStringToArray<16>(data);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr std::array<u8, 32> AsArray(const char (&data)[65]) {
|
||||
return HexStringToArray<32>(data);
|
||||
}
|
||||
std::array<u8, 0x10> operator"" _array16(const char* str, std::size_t len);
|
||||
std::array<u8, 0x20> operator"" _array32(const char* str, std::size_t len);
|
||||
|
||||
} // namespace Common
|
||||
|
||||
@@ -113,19 +113,19 @@ private:
|
||||
Entry CreateEntry(Class log_class, Level log_level, const char* filename, unsigned int line_nr,
|
||||
const char* function, std::string message) const {
|
||||
using std::chrono::duration_cast;
|
||||
using std::chrono::microseconds;
|
||||
using std::chrono::steady_clock;
|
||||
|
||||
return {
|
||||
.timestamp = duration_cast<microseconds>(steady_clock::now() - time_origin),
|
||||
.log_class = log_class,
|
||||
.log_level = log_level,
|
||||
.filename = filename,
|
||||
.line_num = line_nr,
|
||||
.function = function,
|
||||
.message = std::move(message),
|
||||
.final_entry = false,
|
||||
};
|
||||
Entry entry;
|
||||
entry.timestamp =
|
||||
duration_cast<std::chrono::microseconds>(steady_clock::now() - time_origin);
|
||||
entry.log_class = log_class;
|
||||
entry.log_level = log_level;
|
||||
entry.filename = filename;
|
||||
entry.line_num = line_nr;
|
||||
entry.function = function;
|
||||
entry.message = std::move(message);
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
std::mutex writing_mutex;
|
||||
|
||||
@@ -21,13 +21,19 @@ class Filter;
|
||||
*/
|
||||
struct Entry {
|
||||
std::chrono::microseconds timestamp;
|
||||
Class log_class{};
|
||||
Level log_level{};
|
||||
const char* filename = nullptr;
|
||||
unsigned int line_num = 0;
|
||||
Class log_class;
|
||||
Level log_level;
|
||||
const char* filename;
|
||||
unsigned int line_num;
|
||||
std::string function;
|
||||
std::string message;
|
||||
bool final_entry = false;
|
||||
|
||||
Entry() = default;
|
||||
Entry(Entry&& o) = default;
|
||||
|
||||
Entry& operator=(Entry&& o) = default;
|
||||
Entry& operator=(const Entry& o) = default;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -94,7 +100,7 @@ public:
|
||||
void Write(const Entry& entry) override;
|
||||
|
||||
private:
|
||||
Common::FS::IOFile file;
|
||||
FileUtil::IOFile file;
|
||||
std::size_t bytes_written;
|
||||
};
|
||||
|
||||
|
||||
@@ -14,19 +14,19 @@ std::vector<u8> CompressDataLZ4(const u8* source, std::size_t source_size) {
|
||||
ASSERT_MSG(source_size <= LZ4_MAX_INPUT_SIZE, "Source size exceeds LZ4 maximum input size");
|
||||
|
||||
const auto source_size_int = static_cast<int>(source_size);
|
||||
const auto max_compressed_size = static_cast<std::size_t>(LZ4_compressBound(source_size_int));
|
||||
const int max_compressed_size = LZ4_compressBound(source_size_int);
|
||||
std::vector<u8> compressed(max_compressed_size);
|
||||
|
||||
const int compressed_size = LZ4_compress_default(
|
||||
reinterpret_cast<const char*>(source), reinterpret_cast<char*>(compressed.data()),
|
||||
source_size_int, static_cast<int>(max_compressed_size));
|
||||
const int compressed_size = LZ4_compress_default(reinterpret_cast<const char*>(source),
|
||||
reinterpret_cast<char*>(compressed.data()),
|
||||
source_size_int, max_compressed_size);
|
||||
|
||||
if (compressed_size <= 0) {
|
||||
// Compression failed
|
||||
return {};
|
||||
}
|
||||
|
||||
compressed.resize(static_cast<std::size_t>(compressed_size));
|
||||
compressed.resize(compressed_size);
|
||||
|
||||
return compressed;
|
||||
}
|
||||
@@ -38,19 +38,19 @@ std::vector<u8> CompressDataLZ4HC(const u8* source, std::size_t source_size,
|
||||
compression_level = std::clamp(compression_level, LZ4HC_CLEVEL_MIN, LZ4HC_CLEVEL_MAX);
|
||||
|
||||
const auto source_size_int = static_cast<int>(source_size);
|
||||
const auto max_compressed_size = static_cast<std::size_t>(LZ4_compressBound(source_size_int));
|
||||
const int max_compressed_size = LZ4_compressBound(source_size_int);
|
||||
std::vector<u8> compressed(max_compressed_size);
|
||||
|
||||
const int compressed_size = LZ4_compress_HC(
|
||||
reinterpret_cast<const char*>(source), reinterpret_cast<char*>(compressed.data()),
|
||||
source_size_int, static_cast<int>(max_compressed_size), compression_level);
|
||||
source_size_int, max_compressed_size, compression_level);
|
||||
|
||||
if (compressed_size <= 0) {
|
||||
// Compression failed
|
||||
return {};
|
||||
}
|
||||
|
||||
compressed.resize(static_cast<std::size_t>(compressed_size));
|
||||
compressed.resize(compressed_size);
|
||||
|
||||
return compressed;
|
||||
}
|
||||
|
||||
@@ -13,12 +13,12 @@ namespace Common::Compression {
|
||||
/**
|
||||
* Compresses a source memory region with LZ4 and returns the compressed data in a vector.
|
||||
*
|
||||
* @param source The uncompressed source memory region.
|
||||
* @param source_size The size of the uncompressed source memory region.
|
||||
* @param source the uncompressed source memory region.
|
||||
* @param source_size the size in bytes of the uncompressed source memory region.
|
||||
*
|
||||
* @return the compressed data.
|
||||
*/
|
||||
[[nodiscard]] std::vector<u8> CompressDataLZ4(const u8* source, std::size_t source_size);
|
||||
std::vector<u8> CompressDataLZ4(const u8* source, std::size_t source_size);
|
||||
|
||||
/**
|
||||
* Utilizes the LZ4 subalgorithm LZ4HC with the specified compression level. Higher compression
|
||||
@@ -26,24 +26,23 @@ namespace Common::Compression {
|
||||
* compression level has almost no impact on decompression speed. Data compressed with LZ4HC can
|
||||
* also be decompressed with the default LZ4 decompression.
|
||||
*
|
||||
* @param source The uncompressed source memory region.
|
||||
* @param source_size The size of the uncompressed source memory region.
|
||||
* @param compression_level The used compression level. Should be between 3 and 12.
|
||||
* @param source the uncompressed source memory region.
|
||||
* @param source_size the size in bytes of the uncompressed source memory region.
|
||||
* @param compression_level the used compression level. Should be between 3 and 12.
|
||||
*
|
||||
* @return the compressed data.
|
||||
*/
|
||||
[[nodiscard]] std::vector<u8> CompressDataLZ4HC(const u8* source, std::size_t source_size,
|
||||
s32 compression_level);
|
||||
std::vector<u8> CompressDataLZ4HC(const u8* source, std::size_t source_size, s32 compression_level);
|
||||
|
||||
/**
|
||||
* Utilizes the LZ4 subalgorithm LZ4HC with the highest possible compression level.
|
||||
*
|
||||
* @param source The uncompressed source memory region.
|
||||
* @param source_size The size of the uncompressed source memory region
|
||||
* @param source the uncompressed source memory region.
|
||||
* @param source_size the size in bytes of the uncompressed source memory region.
|
||||
*
|
||||
* @return the compressed data.
|
||||
*/
|
||||
[[nodiscard]] std::vector<u8> CompressDataLZ4HCMax(const u8* source, std::size_t source_size);
|
||||
std::vector<u8> CompressDataLZ4HCMax(const u8* source, std::size_t source_size);
|
||||
|
||||
/**
|
||||
* Decompresses a source memory region with LZ4 and returns the uncompressed data in a vector.
|
||||
@@ -53,7 +52,6 @@ namespace Common::Compression {
|
||||
*
|
||||
* @return the decompressed data.
|
||||
*/
|
||||
[[nodiscard]] std::vector<u8> DecompressDataLZ4(const std::vector<u8>& compressed,
|
||||
std::size_t uncompressed_size);
|
||||
std::vector<u8> DecompressDataLZ4(const std::vector<u8>& compressed, std::size_t uncompressed_size);
|
||||
|
||||
} // namespace Common::Compression
|
||||
@@ -23,7 +23,7 @@ struct Rectangle {
|
||||
constexpr Rectangle(T left, T top, T right, T bottom)
|
||||
: left(left), top(top), right(right), bottom(bottom) {}
|
||||
|
||||
[[nodiscard]] T GetWidth() const {
|
||||
T GetWidth() const {
|
||||
if constexpr (std::is_floating_point_v<T>) {
|
||||
return std::abs(right - left);
|
||||
} else {
|
||||
@@ -31,7 +31,7 @@ struct Rectangle {
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] T GetHeight() const {
|
||||
T GetHeight() const {
|
||||
if constexpr (std::is_floating_point_v<T>) {
|
||||
return std::abs(bottom - top);
|
||||
} else {
|
||||
@@ -39,21 +39,21 @@ struct Rectangle {
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] Rectangle<T> TranslateX(const T x) const {
|
||||
Rectangle<T> TranslateX(const T x) const {
|
||||
return Rectangle{left + x, top, right + x, bottom};
|
||||
}
|
||||
|
||||
[[nodiscard]] Rectangle<T> TranslateY(const T y) const {
|
||||
Rectangle<T> TranslateY(const T y) const {
|
||||
return Rectangle{left, top + y, right, bottom + y};
|
||||
}
|
||||
|
||||
[[nodiscard]] Rectangle<T> Scale(const float s) const {
|
||||
Rectangle<T> Scale(const float s) const {
|
||||
return Rectangle{left, top, static_cast<T>(left + GetWidth() * s),
|
||||
static_cast<T>(top + GetHeight() * s)};
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
Rectangle(T, T, T, T) -> Rectangle<T>;
|
||||
Rectangle(T, T, T, T)->Rectangle<T>;
|
||||
|
||||
} // namespace Common
|
||||
|
||||
@@ -17,6 +17,6 @@ struct MemoryInfo {
|
||||
* Gets the memory info of the host system
|
||||
* @return Reference to a MemoryInfo struct with the physical and swap memory sizes in bytes
|
||||
*/
|
||||
[[nodiscard]] const MemoryInfo& GetMemInfo();
|
||||
const MemoryInfo& GetMemInfo();
|
||||
|
||||
} // namespace Common
|
||||
@@ -223,15 +223,15 @@ public:
|
||||
ListShiftForward(levels[priority], n);
|
||||
}
|
||||
|
||||
[[nodiscard]] std::size_t depth() const {
|
||||
std::size_t depth() const {
|
||||
return Depth;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::size_t size(u32 priority) const {
|
||||
std::size_t size(u32 priority) const {
|
||||
return levels[priority].size();
|
||||
}
|
||||
|
||||
[[nodiscard]] std::size_t size() const {
|
||||
std::size_t size() const {
|
||||
u64 priorities = used_priorities;
|
||||
std::size_t size = 0;
|
||||
while (priorities != 0) {
|
||||
@@ -242,64 +242,64 @@ public:
|
||||
return size;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool empty() const {
|
||||
bool empty() const {
|
||||
return used_priorities == 0;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool empty(u32 priority) const {
|
||||
bool empty(u32 priority) const {
|
||||
return (used_priorities & (1ULL << priority)) == 0;
|
||||
}
|
||||
|
||||
[[nodiscard]] u32 highest_priority_set(u32 max_priority = 0) const {
|
||||
u32 highest_priority_set(u32 max_priority = 0) const {
|
||||
const u64 priorities =
|
||||
max_priority == 0 ? used_priorities : (used_priorities & ~((1ULL << max_priority) - 1));
|
||||
return priorities == 0 ? Depth : static_cast<u32>(CountTrailingZeroes64(priorities));
|
||||
}
|
||||
|
||||
[[nodiscard]] u32 lowest_priority_set(u32 min_priority = Depth - 1) const {
|
||||
u32 lowest_priority_set(u32 min_priority = Depth - 1) const {
|
||||
const u64 priorities = min_priority >= Depth - 1
|
||||
? used_priorities
|
||||
: (used_priorities & ((1ULL << (min_priority + 1)) - 1));
|
||||
return priorities == 0 ? Depth : 63 - CountLeadingZeroes64(priorities);
|
||||
}
|
||||
|
||||
[[nodiscard]] const_iterator cbegin(u32 max_prio = 0) const {
|
||||
const_iterator cbegin(u32 max_prio = 0) const {
|
||||
const u32 priority = highest_priority_set(max_prio);
|
||||
return priority == Depth ? cend()
|
||||
: const_iterator{*this, levels[priority].cbegin(), priority};
|
||||
}
|
||||
[[nodiscard]] const_iterator begin(u32 max_prio = 0) const {
|
||||
const_iterator begin(u32 max_prio = 0) const {
|
||||
return cbegin(max_prio);
|
||||
}
|
||||
[[nodiscard]] iterator begin(u32 max_prio = 0) {
|
||||
iterator begin(u32 max_prio = 0) {
|
||||
const u32 priority = highest_priority_set(max_prio);
|
||||
return priority == Depth ? end() : iterator{*this, levels[priority].begin(), priority};
|
||||
}
|
||||
|
||||
[[nodiscard]] const_iterator cend(u32 min_prio = Depth - 1) const {
|
||||
const_iterator cend(u32 min_prio = Depth - 1) const {
|
||||
return min_prio == Depth - 1 ? const_iterator{*this, Depth} : cbegin(min_prio + 1);
|
||||
}
|
||||
[[nodiscard]] const_iterator end(u32 min_prio = Depth - 1) const {
|
||||
const_iterator end(u32 min_prio = Depth - 1) const {
|
||||
return cend(min_prio);
|
||||
}
|
||||
[[nodiscard]] iterator end(u32 min_prio = Depth - 1) {
|
||||
iterator end(u32 min_prio = Depth - 1) {
|
||||
return min_prio == Depth - 1 ? iterator{*this, Depth} : begin(min_prio + 1);
|
||||
}
|
||||
|
||||
[[nodiscard]] T& front(u32 max_priority = 0) {
|
||||
T& front(u32 max_priority = 0) {
|
||||
const u32 priority = highest_priority_set(max_priority);
|
||||
return levels[priority == Depth ? 0 : priority].front();
|
||||
}
|
||||
[[nodiscard]] const T& front(u32 max_priority = 0) const {
|
||||
const T& front(u32 max_priority = 0) const {
|
||||
const u32 priority = highest_priority_set(max_priority);
|
||||
return levels[priority == Depth ? 0 : priority].front();
|
||||
}
|
||||
|
||||
[[nodiscard]] T& back(u32 min_priority = Depth - 1) {
|
||||
T back(u32 min_priority = Depth - 1) {
|
||||
const u32 priority = lowest_priority_set(min_priority); // intended
|
||||
return levels[priority == Depth ? 63 : priority].back();
|
||||
}
|
||||
[[nodiscard]] const T& back(u32 min_priority = Depth - 1) const {
|
||||
const T& back(u32 min_priority = Depth - 1) const {
|
||||
const u32 priority = lowest_priority_set(min_priority); // intended
|
||||
return levels[priority == Depth ? 63 : priority].back();
|
||||
}
|
||||
@@ -329,8 +329,7 @@ private:
|
||||
in_list.splice(position, out_list, element);
|
||||
}
|
||||
|
||||
[[nodiscard]] static const_list_iterator ListIterateTo(const std::list<T>& list,
|
||||
const T& element) {
|
||||
static const_list_iterator ListIterateTo(const std::list<T>& list, const T& element) {
|
||||
auto it = list.cbegin();
|
||||
while (it != list.cend() && *it != element) {
|
||||
++it;
|
||||
|
||||
@@ -36,11 +36,11 @@ struct SpecialRegion {
|
||||
|
||||
MemoryHookPointer handler;
|
||||
|
||||
[[nodiscard]] bool operator<(const SpecialRegion& other) const {
|
||||
bool operator<(const SpecialRegion& other) const {
|
||||
return std::tie(type, handler) < std::tie(other.type, other.handler);
|
||||
}
|
||||
|
||||
[[nodiscard]] bool operator==(const SpecialRegion& other) const {
|
||||
bool operator==(const SpecialRegion& other) const {
|
||||
return std::tie(type, handler) == std::tie(other.type, other.handler);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -24,14 +24,14 @@ public:
|
||||
ParamPackage& operator=(const ParamPackage& other) = default;
|
||||
ParamPackage& operator=(ParamPackage&& other) = default;
|
||||
|
||||
[[nodiscard]] std::string Serialize() const;
|
||||
[[nodiscard]] std::string Get(const std::string& key, const std::string& default_value) const;
|
||||
[[nodiscard]] int Get(const std::string& key, int default_value) const;
|
||||
[[nodiscard]] float Get(const std::string& key, float default_value) const;
|
||||
std::string Serialize() const;
|
||||
std::string Get(const std::string& key, const std::string& default_value) const;
|
||||
int Get(const std::string& key, int default_value) const;
|
||||
float Get(const std::string& key, float default_value) const;
|
||||
void Set(const std::string& key, std::string value);
|
||||
void Set(const std::string& key, int value);
|
||||
void Set(const std::string& key, float value);
|
||||
[[nodiscard]] bool Has(const std::string& key) const;
|
||||
bool Has(const std::string& key) const;
|
||||
void Erase(const std::string& key);
|
||||
void Clear();
|
||||
|
||||
|
||||
@@ -14,36 +14,35 @@ public:
|
||||
Vec3<T> xyz;
|
||||
T w{};
|
||||
|
||||
[[nodiscard]] Quaternion<decltype(-T{})> Inverse() const {
|
||||
Quaternion<decltype(-T{})> Inverse() const {
|
||||
return {-xyz, w};
|
||||
}
|
||||
|
||||
[[nodiscard]] Quaternion<decltype(T{} + T{})> operator+(const Quaternion& other) const {
|
||||
Quaternion<decltype(T{} + T{})> operator+(const Quaternion& other) const {
|
||||
return {xyz + other.xyz, w + other.w};
|
||||
}
|
||||
|
||||
[[nodiscard]] Quaternion<decltype(T{} - T{})> operator-(const Quaternion& other) const {
|
||||
Quaternion<decltype(T{} - T{})> operator-(const Quaternion& other) const {
|
||||
return {xyz - other.xyz, w - other.w};
|
||||
}
|
||||
|
||||
[[nodiscard]] Quaternion<decltype(T{} * T{} - T{} * T{})> operator*(
|
||||
const Quaternion& other) const {
|
||||
Quaternion<decltype(T{} * T{} - T{} * T{})> operator*(const Quaternion& other) const {
|
||||
return {xyz * other.w + other.xyz * w + Cross(xyz, other.xyz),
|
||||
w * other.w - Dot(xyz, other.xyz)};
|
||||
}
|
||||
|
||||
[[nodiscard]] Quaternion<T> Normalized() const {
|
||||
Quaternion<T> Normalized() const {
|
||||
T length = std::sqrt(xyz.Length2() + w * w);
|
||||
return {xyz / length, w / length};
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]] auto QuaternionRotate(const Quaternion<T>& q, const Vec3<T>& v) {
|
||||
auto QuaternionRotate(const Quaternion<T>& q, const Vec3<T>& v) {
|
||||
return v + 2 * Cross(q.xyz, Cross(q.xyz, v) + v * q.w);
|
||||
}
|
||||
|
||||
[[nodiscard]] inline Quaternion<float> MakeQuaternion(const Vec3<float>& axis, float angle) {
|
||||
inline Quaternion<float> MakeQuaternion(const Vec3<float>& axis, float angle) {
|
||||
return {axis * std::sin(angle / 2), std::cos(angle / 2)};
|
||||
}
|
||||
|
||||
|
||||
@@ -91,12 +91,12 @@ public:
|
||||
}
|
||||
|
||||
/// @returns Number of slots used
|
||||
[[nodiscard]] std::size_t Size() const {
|
||||
std::size_t Size() const {
|
||||
return m_write_index.load() - m_read_index.load();
|
||||
}
|
||||
|
||||
/// @returns Maximum size of ring buffer
|
||||
[[nodiscard]] constexpr std::size_t Capacity() const {
|
||||
constexpr std::size_t Capacity() const {
|
||||
return capacity;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ class SpinLock {
|
||||
public:
|
||||
void lock();
|
||||
void unlock();
|
||||
[[nodiscard]] bool try_lock();
|
||||
bool try_lock();
|
||||
|
||||
private:
|
||||
std::atomic_flag lck = ATOMIC_FLAG_INIT;
|
||||
|
||||
@@ -12,19 +12,19 @@
|
||||
namespace Common {
|
||||
|
||||
/// Make a string lowercase
|
||||
[[nodiscard]] std::string ToLower(std::string str);
|
||||
std::string ToLower(std::string str);
|
||||
|
||||
/// Make a string uppercase
|
||||
[[nodiscard]] std::string ToUpper(std::string str);
|
||||
std::string ToUpper(std::string str);
|
||||
|
||||
[[nodiscard]] std::string StringFromBuffer(const std::vector<u8>& data);
|
||||
std::string StringFromBuffer(const std::vector<u8>& data);
|
||||
|
||||
[[nodiscard]] std::string StripSpaces(const std::string& s);
|
||||
[[nodiscard]] std::string StripQuotes(const std::string& s);
|
||||
std::string StripSpaces(const std::string& s);
|
||||
std::string StripQuotes(const std::string& s);
|
||||
|
||||
[[nodiscard]] std::string StringFromBool(bool value);
|
||||
std::string StringFromBool(bool value);
|
||||
|
||||
[[nodiscard]] std::string TabsToSpaces(int tab_size, std::string in);
|
||||
std::string TabsToSpaces(int tab_size, std::string in);
|
||||
|
||||
void SplitString(const std::string& str, char delim, std::vector<std::string>& output);
|
||||
|
||||
@@ -34,15 +34,14 @@ bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _
|
||||
|
||||
void BuildCompleteFilename(std::string& _CompleteFilename, const std::string& _Path,
|
||||
const std::string& _Filename);
|
||||
[[nodiscard]] std::string ReplaceAll(std::string result, const std::string& src,
|
||||
const std::string& dest);
|
||||
std::string ReplaceAll(std::string result, const std::string& src, const std::string& dest);
|
||||
|
||||
[[nodiscard]] std::string UTF16ToUTF8(const std::u16string& input);
|
||||
[[nodiscard]] std::u16string UTF8ToUTF16(const std::string& input);
|
||||
std::string UTF16ToUTF8(const std::u16string& input);
|
||||
std::u16string UTF8ToUTF16(const std::string& input);
|
||||
|
||||
#ifdef _WIN32
|
||||
[[nodiscard]] std::string UTF16ToUTF8(const std::wstring& input);
|
||||
[[nodiscard]] std::wstring UTF8ToUTF16W(const std::string& str);
|
||||
std::string UTF16ToUTF8(const std::wstring& input);
|
||||
std::wstring UTF8ToUTF16W(const std::string& str);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -51,7 +50,7 @@ void BuildCompleteFilename(std::string& _CompleteFilename, const std::string& _P
|
||||
* `other` for equality.
|
||||
*/
|
||||
template <typename InIt>
|
||||
[[nodiscard]] bool ComparePartialString(InIt begin, InIt end, const char* other) {
|
||||
bool ComparePartialString(InIt begin, InIt end, const char* other) {
|
||||
for (; begin != end && *other != '\0'; ++begin, ++other) {
|
||||
if (*begin != *other) {
|
||||
return false;
|
||||
@@ -65,15 +64,14 @@ template <typename InIt>
|
||||
* Creates a std::string from a fixed-size NUL-terminated char buffer. If the buffer isn't
|
||||
* NUL-terminated then the string ends at max_len characters.
|
||||
*/
|
||||
[[nodiscard]] std::string StringFromFixedZeroTerminatedBuffer(const char* buffer,
|
||||
std::size_t max_len);
|
||||
std::string StringFromFixedZeroTerminatedBuffer(const char* buffer, std::size_t max_len);
|
||||
|
||||
/**
|
||||
* Creates a UTF-16 std::u16string from a fixed-size NUL-terminated char buffer. If the buffer isn't
|
||||
* null-terminated, then the string ends at the greatest multiple of two less then or equal to
|
||||
* max_len_bytes.
|
||||
*/
|
||||
[[nodiscard]] std::u16string UTF16StringFromFixedZeroTerminatedBuffer(std::u16string_view buffer,
|
||||
std::size_t max_len);
|
||||
std::u16string UTF16StringFromFixedZeroTerminatedBuffer(std::u16string_view buffer,
|
||||
std::size_t max_len);
|
||||
|
||||
} // namespace Common
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#include "common/x64/cpu_detect.h"
|
||||
#endif
|
||||
|
||||
namespace Common::Telemetry {
|
||||
namespace Telemetry {
|
||||
|
||||
void FieldCollection::Accept(VisitorInterface& visitor) const {
|
||||
for (const auto& field : fields) {
|
||||
@@ -88,4 +88,4 @@ void AppendOSInfo(FieldCollection& fc) {
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace Common::Telemetry
|
||||
} // namespace Telemetry
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#include <string>
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Common::Telemetry {
|
||||
namespace Telemetry {
|
||||
|
||||
/// Field type, used for grouping fields together in the final submitted telemetry log
|
||||
enum class FieldType : u8 {
|
||||
@@ -63,30 +63,30 @@ public:
|
||||
|
||||
void Accept(VisitorInterface& visitor) const override;
|
||||
|
||||
[[nodiscard]] const std::string& GetName() const override {
|
||||
const std::string& GetName() const override {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type of the field.
|
||||
*/
|
||||
[[nodiscard]] FieldType GetType() const {
|
||||
FieldType GetType() const {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the field.
|
||||
*/
|
||||
[[nodiscard]] const T& GetValue() const {
|
||||
const T& GetValue() const {
|
||||
return value;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool operator==(const Field& other) const {
|
||||
bool operator==(const Field& other) const {
|
||||
return (type == other.type) && (name == other.name) && (value == other.value);
|
||||
}
|
||||
|
||||
[[nodiscard]] bool operator!=(const Field& other) const {
|
||||
return !operator==(other);
|
||||
bool operator!=(const Field& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -196,4 +196,4 @@ void AppendCPUInfo(FieldCollection& fc);
|
||||
/// such as platform name, etc.
|
||||
void AppendOSInfo(FieldCollection& fc);
|
||||
|
||||
} // namespace Common::Telemetry
|
||||
} // namespace Telemetry
|
||||
|
||||
@@ -18,14 +18,14 @@ struct ThreadQueueList {
|
||||
using Priority = unsigned int;
|
||||
|
||||
// Number of priority levels. (Valid levels are [0..NUM_QUEUES).)
|
||||
static constexpr Priority NUM_QUEUES = N;
|
||||
static const Priority NUM_QUEUES = N;
|
||||
|
||||
ThreadQueueList() {
|
||||
first = nullptr;
|
||||
}
|
||||
|
||||
// Only for debugging, returns priority level.
|
||||
[[nodiscard]] Priority contains(const T& uid) const {
|
||||
Priority contains(const T& uid) const {
|
||||
for (Priority i = 0; i < NUM_QUEUES; ++i) {
|
||||
const Queue& cur = queues[i];
|
||||
if (std::find(cur.data.cbegin(), cur.data.cend(), uid) != cur.data.cend()) {
|
||||
@@ -36,7 +36,7 @@ struct ThreadQueueList {
|
||||
return -1;
|
||||
}
|
||||
|
||||
[[nodiscard]] T get_first() const {
|
||||
T get_first() const {
|
||||
const Queue* cur = first;
|
||||
while (cur != nullptr) {
|
||||
if (!cur->data.empty()) {
|
||||
@@ -49,7 +49,7 @@ struct ThreadQueueList {
|
||||
}
|
||||
|
||||
template <typename UnaryPredicate>
|
||||
[[nodiscard]] T get_first_filter(UnaryPredicate filter) const {
|
||||
T get_first_filter(UnaryPredicate filter) const {
|
||||
const Queue* cur = first;
|
||||
while (cur != nullptr) {
|
||||
if (!cur->data.empty()) {
|
||||
@@ -129,7 +129,7 @@ struct ThreadQueueList {
|
||||
first = nullptr;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool empty(Priority priority) const {
|
||||
bool empty(Priority priority) const {
|
||||
const Queue* cur = &queues[priority];
|
||||
return cur->data.empty();
|
||||
}
|
||||
|
||||
@@ -25,15 +25,15 @@ public:
|
||||
delete read_ptr;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::size_t Size() const {
|
||||
std::size_t Size() const {
|
||||
return size.load();
|
||||
}
|
||||
|
||||
[[nodiscard]] bool Empty() const {
|
||||
bool Empty() const {
|
||||
return Size() == 0;
|
||||
}
|
||||
|
||||
[[nodiscard]] T& Front() const {
|
||||
T& Front() const {
|
||||
return read_ptr->current;
|
||||
}
|
||||
|
||||
@@ -130,15 +130,15 @@ private:
|
||||
template <typename T>
|
||||
class MPSCQueue {
|
||||
public:
|
||||
[[nodiscard]] std::size_t Size() const {
|
||||
std::size_t Size() const {
|
||||
return spsc_queue.Size();
|
||||
}
|
||||
|
||||
[[nodiscard]] bool Empty() const {
|
||||
bool Empty() const {
|
||||
return spsc_queue.Empty();
|
||||
}
|
||||
|
||||
[[nodiscard]] T& Front() const {
|
||||
T& Front() const {
|
||||
return spsc_queue.Front();
|
||||
}
|
||||
|
||||
|
||||
@@ -10,9 +10,9 @@
|
||||
namespace Common::TimeZone {
|
||||
|
||||
/// Gets the default timezone, i.e. "GMT"
|
||||
[[nodiscard]] std::string GetDefaultTimeZone();
|
||||
std::string GetDefaultTimeZone();
|
||||
|
||||
/// Gets the offset of the current timezone (from the default), in seconds
|
||||
[[nodiscard]] std::chrono::seconds GetCurrentOffsetSeconds();
|
||||
std::chrono::seconds GetCurrentOffsetSeconds();
|
||||
|
||||
} // namespace Common::TimeZone
|
||||
|
||||
@@ -19,18 +19,18 @@ public:
|
||||
|
||||
// The time difference is always returned in milliseconds, regardless of alternative internal
|
||||
// representation
|
||||
[[nodiscard]] std::chrono::milliseconds GetTimeDifference();
|
||||
std::chrono::milliseconds GetTimeDifference();
|
||||
void AddTimeDifference();
|
||||
|
||||
[[nodiscard]] static std::chrono::seconds GetTimeSinceJan1970();
|
||||
[[nodiscard]] static std::chrono::seconds GetLocalTimeSinceJan1970();
|
||||
[[nodiscard]] static double GetDoubleTime();
|
||||
static std::chrono::seconds GetTimeSinceJan1970();
|
||||
static std::chrono::seconds GetLocalTimeSinceJan1970();
|
||||
static double GetDoubleTime();
|
||||
|
||||
[[nodiscard]] static std::string GetTimeFormatted();
|
||||
[[nodiscard]] std::string GetTimeElapsedFormatted() const;
|
||||
[[nodiscard]] std::chrono::milliseconds GetTimeElapsed();
|
||||
static std::string GetTimeFormatted();
|
||||
std::string GetTimeElapsedFormatted() const;
|
||||
std::chrono::milliseconds GetTimeElapsed();
|
||||
|
||||
[[nodiscard]] static std::chrono::milliseconds GetTimeMs();
|
||||
static std::chrono::milliseconds GetTimeMs();
|
||||
|
||||
private:
|
||||
std::chrono::milliseconds m_LastTime;
|
||||
|
||||
@@ -10,13 +10,13 @@
|
||||
namespace Common {
|
||||
|
||||
// This function multiplies 2 u64 values and divides it by a u64 value.
|
||||
[[nodiscard]] u64 MultiplyAndDivide64(u64 a, u64 b, u64 d);
|
||||
u64 MultiplyAndDivide64(u64 a, u64 b, u64 d);
|
||||
|
||||
// This function multiplies 2 u64 values and produces a u128 value;
|
||||
[[nodiscard]] u128 Multiply64Into128(u64 a, u64 b);
|
||||
u128 Multiply64Into128(u64 a, u64 b);
|
||||
|
||||
// This function divides a u128 by a u32 value and produces two u64 values:
|
||||
// the result of division and the remainder
|
||||
[[nodiscard]] std::pair<u64, u64> Divide128On32(u128 dividend, u32 divisor);
|
||||
std::pair<u64, u64> Divide128On32(u128 dividend, u32 divisor);
|
||||
|
||||
} // namespace Common
|
||||
|
||||
@@ -19,21 +19,21 @@ struct UUID {
|
||||
constexpr explicit UUID(const u128& id) : uuid{id} {}
|
||||
constexpr explicit UUID(const u64 lo, const u64 hi) : uuid{{lo, hi}} {}
|
||||
|
||||
[[nodiscard]] constexpr explicit operator bool() const {
|
||||
constexpr explicit operator bool() const {
|
||||
return uuid[0] != INVALID_UUID[0] && uuid[1] != INVALID_UUID[1];
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool operator==(const UUID& rhs) const {
|
||||
constexpr bool operator==(const UUID& rhs) const {
|
||||
// TODO(DarkLordZach): Replace with uuid == rhs.uuid with C++20
|
||||
return uuid[0] == rhs.uuid[0] && uuid[1] == rhs.uuid[1];
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool operator!=(const UUID& rhs) const {
|
||||
constexpr bool operator!=(const UUID& rhs) const {
|
||||
return !operator==(rhs);
|
||||
}
|
||||
|
||||
// TODO(ogniK): Properly generate uuids based on RFC-4122
|
||||
[[nodiscard]] static UUID Generate();
|
||||
static UUID Generate();
|
||||
|
||||
// Set the UUID to {0,0} to be considered an invalid user
|
||||
constexpr void Invalidate() {
|
||||
@@ -41,12 +41,12 @@ struct UUID {
|
||||
}
|
||||
|
||||
// TODO(ogniK): Properly generate a Nintendo ID
|
||||
[[nodiscard]] constexpr u64 GetNintendoID() const {
|
||||
constexpr u64 GetNintendoID() const {
|
||||
return uuid[0];
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string Format() const;
|
||||
[[nodiscard]] std::string FormatSwitch() const;
|
||||
std::string Format() const;
|
||||
std::string FormatSwitch() const;
|
||||
};
|
||||
static_assert(sizeof(UUID) == 16, "UUID is an invalid size!");
|
||||
|
||||
|
||||
@@ -52,15 +52,15 @@ public:
|
||||
constexpr Vec2(const T& x_, const T& y_) : x(x_), y(y_) {}
|
||||
|
||||
template <typename T2>
|
||||
[[nodiscard]] constexpr Vec2<T2> Cast() const {
|
||||
constexpr Vec2<T2> Cast() const {
|
||||
return Vec2<T2>(static_cast<T2>(x), static_cast<T2>(y));
|
||||
}
|
||||
|
||||
[[nodiscard]] static constexpr Vec2 AssignToAll(const T& f) {
|
||||
static constexpr Vec2 AssignToAll(const T& f) {
|
||||
return Vec2{f, f};
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr Vec2<decltype(T{} + T{})> operator+(const Vec2& other) const {
|
||||
constexpr Vec2<decltype(T{} + T{})> operator+(const Vec2& other) const {
|
||||
return {x + other.x, y + other.y};
|
||||
}
|
||||
constexpr Vec2& operator+=(const Vec2& other) {
|
||||
@@ -68,7 +68,7 @@ public:
|
||||
y += other.y;
|
||||
return *this;
|
||||
}
|
||||
[[nodiscard]] constexpr Vec2<decltype(T{} - T{})> operator-(const Vec2& other) const {
|
||||
constexpr Vec2<decltype(T{} - T{})> operator-(const Vec2& other) const {
|
||||
return {x - other.x, y - other.y};
|
||||
}
|
||||
constexpr Vec2& operator-=(const Vec2& other) {
|
||||
@@ -78,15 +78,15 @@ public:
|
||||
}
|
||||
|
||||
template <typename U = T>
|
||||
[[nodiscard]] constexpr Vec2<std::enable_if_t<std::is_signed_v<U>, U>> operator-() const {
|
||||
constexpr Vec2<std::enable_if_t<std::is_signed_v<U>, U>> operator-() const {
|
||||
return {-x, -y};
|
||||
}
|
||||
[[nodiscard]] constexpr Vec2<decltype(T{} * T{})> operator*(const Vec2& other) const {
|
||||
constexpr Vec2<decltype(T{} * T{})> operator*(const Vec2& other) const {
|
||||
return {x * other.x, y * other.y};
|
||||
}
|
||||
|
||||
template <typename V>
|
||||
[[nodiscard]] constexpr Vec2<decltype(T{} * V{})> operator*(const V& f) const {
|
||||
constexpr Vec2<decltype(T{} * V{})> operator*(const V& f) const {
|
||||
return {x * f, y * f};
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ public:
|
||||
}
|
||||
|
||||
template <typename V>
|
||||
[[nodiscard]] constexpr Vec2<decltype(T{} / V{})> operator/(const V& f) const {
|
||||
constexpr Vec2<decltype(T{} / V{})> operator/(const V& f) const {
|
||||
return {x / f, y / f};
|
||||
}
|
||||
|
||||
@@ -107,18 +107,18 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr T Length2() const {
|
||||
constexpr T Length2() const {
|
||||
return x * x + y * y;
|
||||
}
|
||||
|
||||
// Only implemented for T=float
|
||||
[[nodiscard]] float Length() const;
|
||||
[[nodiscard]] float Normalize(); // returns the previous length, which is often useful
|
||||
float Length() const;
|
||||
float Normalize(); // returns the previous length, which is often useful
|
||||
|
||||
[[nodiscard]] constexpr T& operator[](std::size_t i) {
|
||||
constexpr T& operator[](std::size_t i) {
|
||||
return *((&x) + i);
|
||||
}
|
||||
[[nodiscard]] constexpr const T& operator[](std::size_t i) const {
|
||||
constexpr const T& operator[](std::size_t i) const {
|
||||
return *((&x) + i);
|
||||
}
|
||||
|
||||
@@ -128,46 +128,46 @@ public:
|
||||
}
|
||||
|
||||
// Common aliases: UV (texel coordinates), ST (texture coordinates)
|
||||
[[nodiscard]] constexpr T& u() {
|
||||
constexpr T& u() {
|
||||
return x;
|
||||
}
|
||||
[[nodiscard]] constexpr T& v() {
|
||||
constexpr T& v() {
|
||||
return y;
|
||||
}
|
||||
[[nodiscard]] constexpr T& s() {
|
||||
constexpr T& s() {
|
||||
return x;
|
||||
}
|
||||
[[nodiscard]] constexpr T& t() {
|
||||
constexpr T& t() {
|
||||
return y;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr const T& u() const {
|
||||
constexpr const T& u() const {
|
||||
return x;
|
||||
}
|
||||
[[nodiscard]] constexpr const T& v() const {
|
||||
constexpr const T& v() const {
|
||||
return y;
|
||||
}
|
||||
[[nodiscard]] constexpr const T& s() const {
|
||||
constexpr const T& s() const {
|
||||
return x;
|
||||
}
|
||||
[[nodiscard]] constexpr const T& t() const {
|
||||
constexpr const T& t() const {
|
||||
return y;
|
||||
}
|
||||
|
||||
// swizzlers - create a subvector of specific components
|
||||
[[nodiscard]] constexpr Vec2 yx() const {
|
||||
constexpr Vec2 yx() const {
|
||||
return Vec2(y, x);
|
||||
}
|
||||
[[nodiscard]] constexpr Vec2 vu() const {
|
||||
constexpr Vec2 vu() const {
|
||||
return Vec2(y, x);
|
||||
}
|
||||
[[nodiscard]] constexpr Vec2 ts() const {
|
||||
constexpr Vec2 ts() const {
|
||||
return Vec2(y, x);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename V>
|
||||
[[nodiscard]] constexpr Vec2<T> operator*(const V& f, const Vec2<T>& vec) {
|
||||
constexpr Vec2<T> operator*(const V& f, const Vec2<T>& vec) {
|
||||
return Vec2<T>(f * vec.x, f * vec.y);
|
||||
}
|
||||
|
||||
@@ -196,15 +196,15 @@ public:
|
||||
constexpr Vec3(const T& x_, const T& y_, const T& z_) : x(x_), y(y_), z(z_) {}
|
||||
|
||||
template <typename T2>
|
||||
[[nodiscard]] constexpr Vec3<T2> Cast() const {
|
||||
constexpr Vec3<T2> Cast() const {
|
||||
return Vec3<T2>(static_cast<T2>(x), static_cast<T2>(y), static_cast<T2>(z));
|
||||
}
|
||||
|
||||
[[nodiscard]] static constexpr Vec3 AssignToAll(const T& f) {
|
||||
static constexpr Vec3 AssignToAll(const T& f) {
|
||||
return Vec3(f, f, f);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr Vec3<decltype(T{} + T{})> operator+(const Vec3& other) const {
|
||||
constexpr Vec3<decltype(T{} + T{})> operator+(const Vec3& other) const {
|
||||
return {x + other.x, y + other.y, z + other.z};
|
||||
}
|
||||
|
||||
@@ -215,7 +215,7 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr Vec3<decltype(T{} - T{})> operator-(const Vec3& other) const {
|
||||
constexpr Vec3<decltype(T{} - T{})> operator-(const Vec3& other) const {
|
||||
return {x - other.x, y - other.y, z - other.z};
|
||||
}
|
||||
|
||||
@@ -227,16 +227,16 @@ public:
|
||||
}
|
||||
|
||||
template <typename U = T>
|
||||
[[nodiscard]] constexpr Vec3<std::enable_if_t<std::is_signed_v<U>, U>> operator-() const {
|
||||
constexpr Vec3<std::enable_if_t<std::is_signed_v<U>, U>> operator-() const {
|
||||
return {-x, -y, -z};
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr Vec3<decltype(T{} * T{})> operator*(const Vec3& other) const {
|
||||
constexpr Vec3<decltype(T{} * T{})> operator*(const Vec3& other) const {
|
||||
return {x * other.x, y * other.y, z * other.z};
|
||||
}
|
||||
|
||||
template <typename V>
|
||||
[[nodiscard]] constexpr Vec3<decltype(T{} * V{})> operator*(const V& f) const {
|
||||
constexpr Vec3<decltype(T{} * V{})> operator*(const V& f) const {
|
||||
return {x * f, y * f, z * f};
|
||||
}
|
||||
|
||||
@@ -246,7 +246,7 @@ public:
|
||||
return *this;
|
||||
}
|
||||
template <typename V>
|
||||
[[nodiscard]] constexpr Vec3<decltype(T{} / V{})> operator/(const V& f) const {
|
||||
constexpr Vec3<decltype(T{} / V{})> operator/(const V& f) const {
|
||||
return {x / f, y / f, z / f};
|
||||
}
|
||||
|
||||
@@ -256,20 +256,20 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr T Length2() const {
|
||||
constexpr T Length2() const {
|
||||
return x * x + y * y + z * z;
|
||||
}
|
||||
|
||||
// Only implemented for T=float
|
||||
[[nodiscard]] float Length() const;
|
||||
[[nodiscard]] Vec3 Normalized() const;
|
||||
[[nodiscard]] float Normalize(); // returns the previous length, which is often useful
|
||||
float Length() const;
|
||||
Vec3 Normalized() const;
|
||||
float Normalize(); // returns the previous length, which is often useful
|
||||
|
||||
[[nodiscard]] constexpr T& operator[](std::size_t i) {
|
||||
constexpr T& operator[](std::size_t i) {
|
||||
return *((&x) + i);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr const T& operator[](std::size_t i) const {
|
||||
constexpr const T& operator[](std::size_t i) const {
|
||||
return *((&x) + i);
|
||||
}
|
||||
|
||||
@@ -280,63 +280,63 @@ public:
|
||||
}
|
||||
|
||||
// Common aliases: UVW (texel coordinates), RGB (colors), STQ (texture coordinates)
|
||||
[[nodiscard]] constexpr T& u() {
|
||||
constexpr T& u() {
|
||||
return x;
|
||||
}
|
||||
[[nodiscard]] constexpr T& v() {
|
||||
constexpr T& v() {
|
||||
return y;
|
||||
}
|
||||
[[nodiscard]] constexpr T& w() {
|
||||
constexpr T& w() {
|
||||
return z;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr T& r() {
|
||||
constexpr T& r() {
|
||||
return x;
|
||||
}
|
||||
[[nodiscard]] constexpr T& g() {
|
||||
constexpr T& g() {
|
||||
return y;
|
||||
}
|
||||
[[nodiscard]] constexpr T& b() {
|
||||
constexpr T& b() {
|
||||
return z;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr T& s() {
|
||||
constexpr T& s() {
|
||||
return x;
|
||||
}
|
||||
[[nodiscard]] constexpr T& t() {
|
||||
constexpr T& t() {
|
||||
return y;
|
||||
}
|
||||
[[nodiscard]] constexpr T& q() {
|
||||
constexpr T& q() {
|
||||
return z;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr const T& u() const {
|
||||
constexpr const T& u() const {
|
||||
return x;
|
||||
}
|
||||
[[nodiscard]] constexpr const T& v() const {
|
||||
constexpr const T& v() const {
|
||||
return y;
|
||||
}
|
||||
[[nodiscard]] constexpr const T& w() const {
|
||||
constexpr const T& w() const {
|
||||
return z;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr const T& r() const {
|
||||
constexpr const T& r() const {
|
||||
return x;
|
||||
}
|
||||
[[nodiscard]] constexpr const T& g() const {
|
||||
constexpr const T& g() const {
|
||||
return y;
|
||||
}
|
||||
[[nodiscard]] constexpr const T& b() const {
|
||||
constexpr const T& b() const {
|
||||
return z;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr const T& s() const {
|
||||
constexpr const T& s() const {
|
||||
return x;
|
||||
}
|
||||
[[nodiscard]] constexpr const T& t() const {
|
||||
constexpr const T& t() const {
|
||||
return y;
|
||||
}
|
||||
[[nodiscard]] constexpr const T& q() const {
|
||||
constexpr const T& q() const {
|
||||
return z;
|
||||
}
|
||||
|
||||
@@ -345,7 +345,7 @@ public:
|
||||
// _DEFINE_SWIZZLER2 defines a single such function, DEFINE_SWIZZLER2 defines all of them for all
|
||||
// component names (x<->r) and permutations (xy<->yx)
|
||||
#define _DEFINE_SWIZZLER2(a, b, name) \
|
||||
[[nodiscard]] constexpr Vec2<T> name() const { \
|
||||
constexpr Vec2<T> name() const { \
|
||||
return Vec2<T>(a, b); \
|
||||
}
|
||||
#define DEFINE_SWIZZLER2(a, b, a2, b2, a3, b3, a4, b4) \
|
||||
@@ -366,7 +366,7 @@ public:
|
||||
};
|
||||
|
||||
template <typename T, typename V>
|
||||
[[nodiscard]] constexpr Vec3<T> operator*(const V& f, const Vec3<T>& vec) {
|
||||
constexpr Vec3<T> operator*(const V& f, const Vec3<T>& vec) {
|
||||
return Vec3<T>(f * vec.x, f * vec.y, f * vec.z);
|
||||
}
|
||||
|
||||
@@ -402,16 +402,16 @@ public:
|
||||
: x(x_), y(y_), z(z_), w(w_) {}
|
||||
|
||||
template <typename T2>
|
||||
[[nodiscard]] constexpr Vec4<T2> Cast() const {
|
||||
constexpr Vec4<T2> Cast() const {
|
||||
return Vec4<T2>(static_cast<T2>(x), static_cast<T2>(y), static_cast<T2>(z),
|
||||
static_cast<T2>(w));
|
||||
}
|
||||
|
||||
[[nodiscard]] static constexpr Vec4 AssignToAll(const T& f) {
|
||||
static constexpr Vec4 AssignToAll(const T& f) {
|
||||
return Vec4(f, f, f, f);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr Vec4<decltype(T{} + T{})> operator+(const Vec4& other) const {
|
||||
constexpr Vec4<decltype(T{} + T{})> operator+(const Vec4& other) const {
|
||||
return {x + other.x, y + other.y, z + other.z, w + other.w};
|
||||
}
|
||||
|
||||
@@ -423,7 +423,7 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr Vec4<decltype(T{} - T{})> operator-(const Vec4& other) const {
|
||||
constexpr Vec4<decltype(T{} - T{})> operator-(const Vec4& other) const {
|
||||
return {x - other.x, y - other.y, z - other.z, w - other.w};
|
||||
}
|
||||
|
||||
@@ -436,16 +436,16 @@ public:
|
||||
}
|
||||
|
||||
template <typename U = T>
|
||||
[[nodiscard]] constexpr Vec4<std::enable_if_t<std::is_signed_v<U>, U>> operator-() const {
|
||||
constexpr Vec4<std::enable_if_t<std::is_signed_v<U>, U>> operator-() const {
|
||||
return {-x, -y, -z, -w};
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr Vec4<decltype(T{} * T{})> operator*(const Vec4& other) const {
|
||||
constexpr Vec4<decltype(T{} * T{})> operator*(const Vec4& other) const {
|
||||
return {x * other.x, y * other.y, z * other.z, w * other.w};
|
||||
}
|
||||
|
||||
template <typename V>
|
||||
[[nodiscard]] constexpr Vec4<decltype(T{} * V{})> operator*(const V& f) const {
|
||||
constexpr Vec4<decltype(T{} * V{})> operator*(const V& f) const {
|
||||
return {x * f, y * f, z * f, w * f};
|
||||
}
|
||||
|
||||
@@ -456,7 +456,7 @@ public:
|
||||
}
|
||||
|
||||
template <typename V>
|
||||
[[nodiscard]] constexpr Vec4<decltype(T{} / V{})> operator/(const V& f) const {
|
||||
constexpr Vec4<decltype(T{} / V{})> operator/(const V& f) const {
|
||||
return {x / f, y / f, z / f, w / f};
|
||||
}
|
||||
|
||||
@@ -466,15 +466,15 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr T Length2() const {
|
||||
constexpr T Length2() const {
|
||||
return x * x + y * y + z * z + w * w;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr T& operator[](std::size_t i) {
|
||||
constexpr T& operator[](std::size_t i) {
|
||||
return *((&x) + i);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr const T& operator[](std::size_t i) const {
|
||||
constexpr const T& operator[](std::size_t i) const {
|
||||
return *((&x) + i);
|
||||
}
|
||||
|
||||
@@ -486,29 +486,29 @@ public:
|
||||
}
|
||||
|
||||
// Common alias: RGBA (colors)
|
||||
[[nodiscard]] constexpr T& r() {
|
||||
constexpr T& r() {
|
||||
return x;
|
||||
}
|
||||
[[nodiscard]] constexpr T& g() {
|
||||
constexpr T& g() {
|
||||
return y;
|
||||
}
|
||||
[[nodiscard]] constexpr T& b() {
|
||||
constexpr T& b() {
|
||||
return z;
|
||||
}
|
||||
[[nodiscard]] constexpr T& a() {
|
||||
constexpr T& a() {
|
||||
return w;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr const T& r() const {
|
||||
constexpr const T& r() const {
|
||||
return x;
|
||||
}
|
||||
[[nodiscard]] constexpr const T& g() const {
|
||||
constexpr const T& g() const {
|
||||
return y;
|
||||
}
|
||||
[[nodiscard]] constexpr const T& b() const {
|
||||
constexpr const T& b() const {
|
||||
return z;
|
||||
}
|
||||
[[nodiscard]] constexpr const T& a() const {
|
||||
constexpr const T& a() const {
|
||||
return w;
|
||||
}
|
||||
|
||||
@@ -520,7 +520,7 @@ public:
|
||||
// DEFINE_SWIZZLER2_COMP2 defines two component functions for all component names (x<->r) and
|
||||
// permutations (xy<->yx)
|
||||
#define _DEFINE_SWIZZLER2(a, b, name) \
|
||||
[[nodiscard]] constexpr Vec2<T> name() const { \
|
||||
constexpr Vec2<T> name() const { \
|
||||
return Vec2<T>(a, b); \
|
||||
}
|
||||
#define DEFINE_SWIZZLER2_COMP1(a, a2) \
|
||||
@@ -547,7 +547,7 @@ public:
|
||||
#undef _DEFINE_SWIZZLER2
|
||||
|
||||
#define _DEFINE_SWIZZLER3(a, b, c, name) \
|
||||
[[nodiscard]] constexpr Vec3<T> name() const { \
|
||||
constexpr Vec3<T> name() const { \
|
||||
return Vec3<T>(a, b, c); \
|
||||
}
|
||||
#define DEFINE_SWIZZLER3_COMP1(a, a2) \
|
||||
@@ -581,7 +581,7 @@ public:
|
||||
};
|
||||
|
||||
template <typename T, typename V>
|
||||
[[nodiscard]] constexpr Vec4<decltype(V{} * T{})> operator*(const V& f, const Vec4<T>& vec) {
|
||||
constexpr Vec4<decltype(V{} * T{})> operator*(const V& f, const Vec4<T>& vec) {
|
||||
return {f * vec.x, f * vec.y, f * vec.z, f * vec.w};
|
||||
}
|
||||
|
||||
@@ -593,41 +593,39 @@ constexpr decltype(T{} * T{} + T{} * T{}) Dot(const Vec2<T>& a, const Vec2<T>& b
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]] constexpr decltype(T{} * T{} + T{} * T{}) Dot(const Vec3<T>& a, const Vec3<T>& b) {
|
||||
constexpr decltype(T{} * T{} + T{} * T{}) Dot(const Vec3<T>& a, const Vec3<T>& b) {
|
||||
return a.x * b.x + a.y * b.y + a.z * b.z;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]] constexpr decltype(T{} * T{} + T{} * T{}) Dot(const Vec4<T>& a, const Vec4<T>& b) {
|
||||
constexpr decltype(T{} * T{} + T{} * T{}) Dot(const Vec4<T>& a, const Vec4<T>& b) {
|
||||
return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]] constexpr Vec3<decltype(T{} * T{} - T{} * T{})> Cross(const Vec3<T>& a,
|
||||
const Vec3<T>& b) {
|
||||
constexpr Vec3<decltype(T{} * T{} - T{} * T{})> Cross(const Vec3<T>& a, const Vec3<T>& b) {
|
||||
return {a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x};
|
||||
}
|
||||
|
||||
// linear interpolation via float: 0.0=begin, 1.0=end
|
||||
template <typename X>
|
||||
[[nodiscard]] constexpr decltype(X{} * float{} + X{} * float{}) Lerp(const X& begin, const X& end,
|
||||
const float t) {
|
||||
constexpr decltype(X{} * float{} + X{} * float{}) Lerp(const X& begin, const X& end,
|
||||
const float t) {
|
||||
return begin * (1.f - t) + end * t;
|
||||
}
|
||||
|
||||
// linear interpolation via int: 0=begin, base=end
|
||||
template <typename X, int base>
|
||||
[[nodiscard]] constexpr decltype((X{} * int{} + X{} * int{}) / base) LerpInt(const X& begin,
|
||||
const X& end,
|
||||
const int t) {
|
||||
constexpr decltype((X{} * int{} + X{} * int{}) / base) LerpInt(const X& begin, const X& end,
|
||||
const int t) {
|
||||
return (begin * (base - t) + end * t) / base;
|
||||
}
|
||||
|
||||
// bilinear interpolation. s is for interpolating x00-x01 and x10-x11, and t is for the second
|
||||
// interpolation.
|
||||
template <typename X>
|
||||
[[nodiscard]] constexpr auto BilinearInterp(const X& x00, const X& x01, const X& x10, const X& x11,
|
||||
const float s, const float t) {
|
||||
constexpr auto BilinearInterp(const X& x00, const X& x01, const X& x10, const X& x11, const float s,
|
||||
const float t) {
|
||||
auto y0 = Lerp(x00, x01, s);
|
||||
auto y1 = Lerp(x10, x11, s);
|
||||
return Lerp(y0, y1, t);
|
||||
@@ -635,42 +633,42 @@ template <typename X>
|
||||
|
||||
// Utility vector factories
|
||||
template <typename T>
|
||||
[[nodiscard]] constexpr Vec2<T> MakeVec(const T& x, const T& y) {
|
||||
constexpr Vec2<T> MakeVec(const T& x, const T& y) {
|
||||
return Vec2<T>{x, y};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]] constexpr Vec3<T> MakeVec(const T& x, const T& y, const T& z) {
|
||||
constexpr Vec3<T> MakeVec(const T& x, const T& y, const T& z) {
|
||||
return Vec3<T>{x, y, z};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]] constexpr Vec4<T> MakeVec(const T& x, const T& y, const Vec2<T>& zw) {
|
||||
constexpr Vec4<T> MakeVec(const T& x, const T& y, const Vec2<T>& zw) {
|
||||
return MakeVec(x, y, zw[0], zw[1]);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]] constexpr Vec3<T> MakeVec(const Vec2<T>& xy, const T& z) {
|
||||
constexpr Vec3<T> MakeVec(const Vec2<T>& xy, const T& z) {
|
||||
return MakeVec(xy[0], xy[1], z);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]] constexpr Vec3<T> MakeVec(const T& x, const Vec2<T>& yz) {
|
||||
constexpr Vec3<T> MakeVec(const T& x, const Vec2<T>& yz) {
|
||||
return MakeVec(x, yz[0], yz[1]);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]] constexpr Vec4<T> MakeVec(const T& x, const T& y, const T& z, const T& w) {
|
||||
constexpr Vec4<T> MakeVec(const T& x, const T& y, const T& z, const T& w) {
|
||||
return Vec4<T>{x, y, z, w};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]] constexpr Vec4<T> MakeVec(const Vec2<T>& xy, const T& z, const T& w) {
|
||||
constexpr Vec4<T> MakeVec(const Vec2<T>& xy, const T& z, const T& w) {
|
||||
return MakeVec(xy[0], xy[1], z, w);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]] constexpr Vec4<T> MakeVec(const T& x, const Vec2<T>& yz, const T& w) {
|
||||
constexpr Vec4<T> MakeVec(const T& x, const Vec2<T>& yz, const T& w) {
|
||||
return MakeVec(x, yz[0], yz[1], w);
|
||||
}
|
||||
|
||||
@@ -678,17 +676,17 @@ template <typename T>
|
||||
// Even if someone wanted to use an odd object like Vec2<Vec2<T>>, the compiler would error
|
||||
// out soon enough due to misuse of the returned structure.
|
||||
template <typename T>
|
||||
[[nodiscard]] constexpr Vec4<T> MakeVec(const Vec2<T>& xy, const Vec2<T>& zw) {
|
||||
constexpr Vec4<T> MakeVec(const Vec2<T>& xy, const Vec2<T>& zw) {
|
||||
return MakeVec(xy[0], xy[1], zw[0], zw[1]);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]] constexpr Vec4<T> MakeVec(const Vec3<T>& xyz, const T& w) {
|
||||
constexpr Vec4<T> MakeVec(const Vec3<T>& xyz, const T& w) {
|
||||
return MakeVec(xyz[0], xyz[1], xyz[2], w);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]] constexpr Vec4<T> MakeVec(const T& x, const Vec3<T>& yzw) {
|
||||
constexpr Vec4<T> MakeVec(const T& x, const Vec3<T>& yzw) {
|
||||
return MakeVec(x, yzw[0], yzw[1], yzw[2]);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,16 @@
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <stdio.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/types.h>
|
||||
#if defined __APPLE__ || defined __FreeBSD__ || defined __OpenBSD__
|
||||
#include <sys/sysctl.h>
|
||||
#elif defined __HAIKU__
|
||||
#include <OS.h>
|
||||
#else
|
||||
#include <sys/sysinfo.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "common/assert.h"
|
||||
|
||||
@@ -30,23 +30,23 @@ public:
|
||||
base_ptr = reinterpret_cast<T*>(AllocateMemoryPages(alloc_size));
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr const T& operator[](std::size_t index) const {
|
||||
constexpr const T& operator[](std::size_t index) const {
|
||||
return base_ptr[index];
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr T& operator[](std::size_t index) {
|
||||
constexpr T& operator[](std::size_t index) {
|
||||
return base_ptr[index];
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr T* data() {
|
||||
constexpr T* data() {
|
||||
return base_ptr;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr const T* data() const {
|
||||
constexpr const T* data() const {
|
||||
return base_ptr;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr std::size_t size() const {
|
||||
constexpr std::size_t size() const {
|
||||
return alloc_size / sizeof(T);
|
||||
}
|
||||
|
||||
|
||||
@@ -14,24 +14,24 @@ namespace Common {
|
||||
class WallClock {
|
||||
public:
|
||||
/// Returns current wall time in nanoseconds
|
||||
[[nodiscard]] virtual std::chrono::nanoseconds GetTimeNS() = 0;
|
||||
virtual std::chrono::nanoseconds GetTimeNS() = 0;
|
||||
|
||||
/// Returns current wall time in microseconds
|
||||
[[nodiscard]] virtual std::chrono::microseconds GetTimeUS() = 0;
|
||||
virtual std::chrono::microseconds GetTimeUS() = 0;
|
||||
|
||||
/// Returns current wall time in milliseconds
|
||||
[[nodiscard]] virtual std::chrono::milliseconds GetTimeMS() = 0;
|
||||
virtual std::chrono::milliseconds GetTimeMS() = 0;
|
||||
|
||||
/// Returns current wall time in emulated clock cycles
|
||||
[[nodiscard]] virtual u64 GetClockCycles() = 0;
|
||||
virtual u64 GetClockCycles() = 0;
|
||||
|
||||
/// Returns current wall time in emulated cpu cycles
|
||||
[[nodiscard]] virtual u64 GetCPUCycles() = 0;
|
||||
virtual u64 GetCPUCycles() = 0;
|
||||
|
||||
virtual void Pause(bool is_paused) = 0;
|
||||
|
||||
/// Tells if the wall clock, uses the host CPU's hardware clock
|
||||
[[nodiscard]] bool IsNative() const {
|
||||
bool IsNative() const {
|
||||
return is_native;
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ private:
|
||||
bool is_native;
|
||||
};
|
||||
|
||||
[[nodiscard]] std::unique_ptr<WallClock> CreateBestMatchingClock(u32 emulated_cpu_frequency,
|
||||
u32 emulated_clock_frequency);
|
||||
std::unique_ptr<WallClock> CreateBestMatchingClock(u32 emulated_cpu_frequency,
|
||||
u32 emulated_clock_frequency);
|
||||
|
||||
} // namespace Common
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include <string>
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace WebService {
|
||||
namespace Common {
|
||||
struct WebResult {
|
||||
enum class Code : u32 {
|
||||
Success,
|
||||
@@ -22,4 +22,4 @@ struct WebResult {
|
||||
std::string result_string;
|
||||
std::string returned_data;
|
||||
};
|
||||
} // namespace WebService
|
||||
} // namespace Common
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <algorithm>
|
||||
#include <zstd.h>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/zstd_compression.h"
|
||||
|
||||
namespace Common::Compression {
|
||||
|
||||
@@ -13,25 +13,24 @@ namespace Common::Compression {
|
||||
/**
|
||||
* Compresses a source memory region with Zstandard and returns the compressed data in a vector.
|
||||
*
|
||||
* @param source The uncompressed source memory region.
|
||||
* @param source_size The size of the uncompressed source memory region.
|
||||
* @param compression_level The used compression level. Should be between 1 and 22.
|
||||
* @param source the uncompressed source memory region.
|
||||
* @param source_size the size in bytes of the uncompressed source memory region.
|
||||
* @param compression_level the used compression level. Should be between 1 and 22.
|
||||
*
|
||||
* @return the compressed data.
|
||||
*/
|
||||
[[nodiscard]] std::vector<u8> CompressDataZSTD(const u8* source, std::size_t source_size,
|
||||
s32 compression_level);
|
||||
std::vector<u8> CompressDataZSTD(const u8* source, std::size_t source_size, s32 compression_level);
|
||||
|
||||
/**
|
||||
* Compresses a source memory region with Zstandard with the default compression level and returns
|
||||
* the compressed data in a vector.
|
||||
*
|
||||
* @param source The uncompressed source memory region.
|
||||
* @param source_size The size of the uncompressed source memory region.
|
||||
* @param source the uncompressed source memory region.
|
||||
* @param source_size the size in bytes of the uncompressed source memory region.
|
||||
*
|
||||
* @return the compressed data.
|
||||
*/
|
||||
[[nodiscard]] std::vector<u8> CompressDataZSTDDefault(const u8* source, std::size_t source_size);
|
||||
std::vector<u8> CompressDataZSTDDefault(const u8* source, std::size_t source_size);
|
||||
|
||||
/**
|
||||
* Decompresses a source memory region with Zstandard and returns the uncompressed data in a vector.
|
||||
@@ -40,6 +39,6 @@ namespace Common::Compression {
|
||||
*
|
||||
* @return the decompressed data.
|
||||
*/
|
||||
[[nodiscard]] std::vector<u8> DecompressDataZSTD(const std::vector<u8>& compressed);
|
||||
std::vector<u8> DecompressDataZSTD(const std::vector<u8>& compressed);
|
||||
|
||||
} // namespace Common::Compression
|
||||
@@ -491,6 +491,7 @@ add_library(core STATIC
|
||||
hle/service/sm/controller.h
|
||||
hle/service/sm/sm.cpp
|
||||
hle/service/sm/sm.h
|
||||
hle/service/sockets/blocking_worker.h
|
||||
hle/service/sockets/bsd.cpp
|
||||
hle/service/sockets/bsd.h
|
||||
hle/service/sockets/ethc.cpp
|
||||
@@ -501,6 +502,8 @@ add_library(core STATIC
|
||||
hle/service/sockets/sfdnsres.h
|
||||
hle/service/sockets/sockets.cpp
|
||||
hle/service/sockets/sockets.h
|
||||
hle/service/sockets/sockets_translate.cpp
|
||||
hle/service/sockets/sockets_translate.h
|
||||
hle/service/spl/csrng.cpp
|
||||
hle/service/spl/csrng.h
|
||||
hle/service/spl/module.cpp
|
||||
|
||||
@@ -143,7 +143,7 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable&
|
||||
config.wall_clock_cntpct = uses_wall_clock;
|
||||
|
||||
// Safe optimizations
|
||||
if (Settings::values.cpu_accuracy == Settings::CPUAccuracy::DebugMode) {
|
||||
if (Settings::values.cpu_accuracy != Settings::CPUAccuracy::Accurate) {
|
||||
if (!Settings::values.cpuopt_page_tables) {
|
||||
config.page_table = nullptr;
|
||||
}
|
||||
@@ -170,17 +170,6 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable&
|
||||
}
|
||||
}
|
||||
|
||||
// Unsafe optimizations
|
||||
if (Settings::values.cpu_accuracy == Settings::CPUAccuracy::Unsafe) {
|
||||
config.unsafe_optimizations = true;
|
||||
if (Settings::values.cpuopt_unsafe_unfuse_fma) {
|
||||
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA;
|
||||
}
|
||||
if (Settings::values.cpuopt_unsafe_reduce_fp_error) {
|
||||
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_ReducedErrorFP;
|
||||
}
|
||||
}
|
||||
|
||||
return std::make_unique<Dynarmic::A32::Jit>(config);
|
||||
}
|
||||
|
||||
|
||||
@@ -195,7 +195,7 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable&
|
||||
config.wall_clock_cntpct = uses_wall_clock;
|
||||
|
||||
// Safe optimizations
|
||||
if (Settings::values.cpu_accuracy == Settings::CPUAccuracy::DebugMode) {
|
||||
if (Settings::values.cpu_accuracy != Settings::CPUAccuracy::Accurate) {
|
||||
if (!Settings::values.cpuopt_page_tables) {
|
||||
config.page_table = nullptr;
|
||||
}
|
||||
@@ -222,17 +222,6 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable&
|
||||
}
|
||||
}
|
||||
|
||||
// Unsafe optimizations
|
||||
if (Settings::values.cpu_accuracy == Settings::CPUAccuracy::Unsafe) {
|
||||
config.unsafe_optimizations = true;
|
||||
if (Settings::values.cpuopt_unsafe_unfuse_fma) {
|
||||
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA;
|
||||
}
|
||||
if (Settings::values.cpuopt_unsafe_reduce_fp_error) {
|
||||
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_ReducedErrorFP;
|
||||
}
|
||||
}
|
||||
|
||||
return std::make_shared<Dynarmic::A64::Jit>(config);
|
||||
}
|
||||
|
||||
|
||||
@@ -113,7 +113,7 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
|
||||
return FileSys::ConcatenatedVfsFile::MakeConcatenatedFile(concat, dir->GetName());
|
||||
}
|
||||
|
||||
if (Common::FS::IsDirectory(path))
|
||||
if (FileUtil::IsDirectory(path))
|
||||
return vfs->OpenFile(path + "/" + "main", FileSys::Mode::Read);
|
||||
|
||||
return vfs->OpenFile(path, FileSys::Mode::Read);
|
||||
@@ -146,7 +146,7 @@ struct System::Impl {
|
||||
ResultStatus Init(System& system, Frontend::EmuWindow& emu_window) {
|
||||
LOG_DEBUG(HW_Memory, "initialized OK");
|
||||
|
||||
device_memory = std::make_unique<Core::DeviceMemory>();
|
||||
device_memory = std::make_unique<Core::DeviceMemory>(system);
|
||||
|
||||
is_multicore = Settings::values.use_multi_core.GetValue();
|
||||
is_async_gpu = is_multicore || Settings::values.use_asynchronous_gpu_emulation.GetValue();
|
||||
@@ -269,14 +269,14 @@ struct System::Impl {
|
||||
// Log last frame performance stats if game was loded
|
||||
if (perf_stats) {
|
||||
const auto perf_results = GetAndResetPerfStats();
|
||||
constexpr auto performance = Common::Telemetry::FieldType::Performance;
|
||||
|
||||
telemetry_session->AddField(performance, "Shutdown_EmulationSpeed",
|
||||
telemetry_session->AddField(Telemetry::FieldType::Performance,
|
||||
"Shutdown_EmulationSpeed",
|
||||
perf_results.emulation_speed * 100.0);
|
||||
telemetry_session->AddField(performance, "Shutdown_Framerate", perf_results.game_fps);
|
||||
telemetry_session->AddField(performance, "Shutdown_Frametime",
|
||||
telemetry_session->AddField(Telemetry::FieldType::Performance, "Shutdown_Framerate",
|
||||
perf_results.game_fps);
|
||||
telemetry_session->AddField(Telemetry::FieldType::Performance, "Shutdown_Frametime",
|
||||
perf_results.frametime * 1000.0);
|
||||
telemetry_session->AddField(performance, "Mean_Frametime_MS",
|
||||
telemetry_session->AddField(Telemetry::FieldType::Performance, "Mean_Frametime_MS",
|
||||
perf_stats->GetMeanFrametime());
|
||||
}
|
||||
|
||||
|
||||
@@ -7,14 +7,14 @@
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/microprofile.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/core_timing_util.h"
|
||||
#include "core/hardware_properties.h"
|
||||
|
||||
namespace Core::Timing {
|
||||
|
||||
constexpr s64 MAX_SLICE_LENGTH = 4000;
|
||||
constexpr u64 MAX_SLICE_LENGTH = 4000;
|
||||
|
||||
std::shared_ptr<EventType> CreateEvent(std::string name, TimedCallback&& callback) {
|
||||
return std::make_shared<EventType>(std::move(callback), std::move(name));
|
||||
@@ -37,8 +37,10 @@ struct CoreTiming::Event {
|
||||
}
|
||||
};
|
||||
|
||||
CoreTiming::CoreTiming()
|
||||
: clock{Common::CreateBestMatchingClock(Hardware::BASE_CLOCK_RATE, Hardware::CNTFREQ)} {}
|
||||
CoreTiming::CoreTiming() {
|
||||
clock =
|
||||
Common::CreateBestMatchingClock(Core::Hardware::BASE_CLOCK_RATE, Core::Hardware::CNTFREQ);
|
||||
}
|
||||
|
||||
CoreTiming::~CoreTiming() = default;
|
||||
|
||||
@@ -134,7 +136,7 @@ void CoreTiming::UnscheduleEvent(const std::shared_ptr<EventType>& event_type,
|
||||
|
||||
void CoreTiming::AddTicks(u64 ticks) {
|
||||
this->ticks += ticks;
|
||||
downcount -= static_cast<s64>(ticks);
|
||||
downcount -= ticks;
|
||||
}
|
||||
|
||||
void CoreTiming::Idle() {
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
#include <limits>
|
||||
#include "common/logging/log.h"
|
||||
#include "common/uint128.h"
|
||||
#include "core/hardware_properties.h"
|
||||
|
||||
namespace Core::Timing {
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <chrono>
|
||||
#include "common/common_types.h"
|
||||
#include "core/hardware_properties.h"
|
||||
|
||||
namespace Core::Timing {
|
||||
|
||||
|
||||
@@ -52,15 +52,15 @@ void CpuManager::Shutdown() {
|
||||
}
|
||||
|
||||
std::function<void(void*)> CpuManager::GetGuestThreadStartFunc() {
|
||||
return GuestThreadFunction;
|
||||
return std::function<void(void*)>(GuestThreadFunction);
|
||||
}
|
||||
|
||||
std::function<void(void*)> CpuManager::GetIdleThreadStartFunc() {
|
||||
return IdleThreadFunction;
|
||||
return std::function<void(void*)>(IdleThreadFunction);
|
||||
}
|
||||
|
||||
std::function<void(void*)> CpuManager::GetSuspendThreadStartFunc() {
|
||||
return SuspendThreadFunction;
|
||||
return std::function<void(void*)>(SuspendThreadFunction);
|
||||
}
|
||||
|
||||
void CpuManager::GuestThreadFunction(void* cpu_manager_) {
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <array>
|
||||
#include <mbedtls/cipher.h>
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
@@ -11,10 +10,8 @@
|
||||
|
||||
namespace Core::Crypto {
|
||||
namespace {
|
||||
using NintendoTweak = std::array<u8, 16>;
|
||||
|
||||
NintendoTweak CalculateNintendoTweak(std::size_t sector_id) {
|
||||
NintendoTweak out{};
|
||||
std::vector<u8> CalculateNintendoTweak(std::size_t sector_id) {
|
||||
std::vector<u8> out(0x10);
|
||||
for (std::size_t i = 0xF; i <= 0xF; --i) {
|
||||
out[i] = sector_id & 0xFF;
|
||||
sector_id >>= 8;
|
||||
@@ -66,6 +63,13 @@ AESCipher<Key, KeySize>::~AESCipher() {
|
||||
mbedtls_cipher_free(&ctx->decryption_context);
|
||||
}
|
||||
|
||||
template <typename Key, std::size_t KeySize>
|
||||
void AESCipher<Key, KeySize>::SetIV(std::vector<u8> iv) {
|
||||
ASSERT_MSG((mbedtls_cipher_set_iv(&ctx->encryption_context, iv.data(), iv.size()) ||
|
||||
mbedtls_cipher_set_iv(&ctx->decryption_context, iv.data(), iv.size())) == 0,
|
||||
"Failed to set IV on mbedtls ciphers.");
|
||||
}
|
||||
|
||||
template <typename Key, std::size_t KeySize>
|
||||
void AESCipher<Key, KeySize>::Transcode(const u8* src, std::size_t size, u8* dest, Op op) const {
|
||||
auto* const context = op == Op::Encrypt ? &ctx->encryption_context : &ctx->decryption_context;
|
||||
@@ -116,17 +120,10 @@ void AESCipher<Key, KeySize>::XTSTranscode(const u8* src, std::size_t size, u8*
|
||||
|
||||
for (std::size_t i = 0; i < size; i += sector_size) {
|
||||
SetIV(CalculateNintendoTweak(sector_id++));
|
||||
Transcode(src + i, sector_size, dest + i, op);
|
||||
Transcode<u8, u8>(src + i, sector_size, dest + i, op);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Key, std::size_t KeySize>
|
||||
void AESCipher<Key, KeySize>::SetIVImpl(const u8* data, std::size_t size) {
|
||||
ASSERT_MSG((mbedtls_cipher_set_iv(&ctx->encryption_context, data, size) ||
|
||||
mbedtls_cipher_set_iv(&ctx->decryption_context, data, size)) == 0,
|
||||
"Failed to set IV on mbedtls ciphers.");
|
||||
}
|
||||
|
||||
template class AESCipher<Key128>;
|
||||
template class AESCipher<Key256>;
|
||||
} // namespace Core::Crypto
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
#include "common/common_types.h"
|
||||
#include "core/file_sys/vfs.h"
|
||||
|
||||
@@ -31,12 +32,10 @@ class AESCipher {
|
||||
|
||||
public:
|
||||
AESCipher(Key key, Mode mode);
|
||||
|
||||
~AESCipher();
|
||||
|
||||
template <typename ContiguousContainer>
|
||||
void SetIV(const ContiguousContainer& container) {
|
||||
SetIVImpl(std::data(container), std::size(container));
|
||||
}
|
||||
void SetIV(std::vector<u8> iv);
|
||||
|
||||
template <typename Source, typename Dest>
|
||||
void Transcode(const Source* src, std::size_t size, Dest* dest, Op op) const {
|
||||
@@ -60,8 +59,6 @@ public:
|
||||
std::size_t sector_size, Op op);
|
||||
|
||||
private:
|
||||
void SetIVImpl(const u8* data, std::size_t size);
|
||||
|
||||
std::unique_ptr<CipherContext> ctx;
|
||||
};
|
||||
} // namespace Core::Crypto
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include "common/assert.h"
|
||||
#include "core/crypto/ctr_encryption_layer.h"
|
||||
@@ -11,7 +10,8 @@ namespace Core::Crypto {
|
||||
|
||||
CTREncryptionLayer::CTREncryptionLayer(FileSys::VirtualFile base_, Key128 key_,
|
||||
std::size_t base_offset)
|
||||
: EncryptionLayer(std::move(base_)), base_offset(base_offset), cipher(key_, Mode::CTR) {}
|
||||
: EncryptionLayer(std::move(base_)), base_offset(base_offset), cipher(key_, Mode::CTR),
|
||||
iv(16, 0) {}
|
||||
|
||||
std::size_t CTREncryptionLayer::Read(u8* data, std::size_t length, std::size_t offset) const {
|
||||
if (length == 0)
|
||||
@@ -39,8 +39,9 @@ std::size_t CTREncryptionLayer::Read(u8* data, std::size_t length, std::size_t o
|
||||
return read + Read(data + read, length - read, offset + read);
|
||||
}
|
||||
|
||||
void CTREncryptionLayer::SetIV(const IVData& iv_) {
|
||||
iv = iv_;
|
||||
void CTREncryptionLayer::SetIV(const std::vector<u8>& iv_) {
|
||||
const auto length = std::min(iv_.size(), iv.size());
|
||||
iv.assign(iv_.cbegin(), iv_.cbegin() + length);
|
||||
}
|
||||
|
||||
void CTREncryptionLayer::UpdateIV(std::size_t offset) const {
|
||||
|
||||
@@ -4,8 +4,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
|
||||
#include <vector>
|
||||
#include "core/crypto/aes_util.h"
|
||||
#include "core/crypto/encryption_layer.h"
|
||||
#include "core/crypto/key_manager.h"
|
||||
@@ -15,20 +14,18 @@ namespace Core::Crypto {
|
||||
// Sits on top of a VirtualFile and provides CTR-mode AES decription.
|
||||
class CTREncryptionLayer : public EncryptionLayer {
|
||||
public:
|
||||
using IVData = std::array<u8, 16>;
|
||||
|
||||
CTREncryptionLayer(FileSys::VirtualFile base, Key128 key, std::size_t base_offset);
|
||||
|
||||
std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override;
|
||||
|
||||
void SetIV(const IVData& iv);
|
||||
void SetIV(const std::vector<u8>& iv);
|
||||
|
||||
private:
|
||||
std::size_t base_offset;
|
||||
|
||||
// Must be mutable as operations modify cipher contexts.
|
||||
mutable AESCipher<Key128> cipher;
|
||||
mutable IVData iv{};
|
||||
mutable std::vector<u8> iv;
|
||||
|
||||
void UpdateIV(std::size_t offset) const;
|
||||
};
|
||||
|
||||
@@ -36,86 +36,18 @@
|
||||
#include "core/settings.h"
|
||||
|
||||
namespace Core::Crypto {
|
||||
namespace {
|
||||
|
||||
constexpr u64 CURRENT_CRYPTO_REVISION = 0x5;
|
||||
constexpr u64 FULL_TICKET_SIZE = 0x400;
|
||||
|
||||
using Common::AsArray;
|
||||
using namespace Common;
|
||||
|
||||
// clang-format off
|
||||
constexpr std::array eticket_source_hashes{
|
||||
AsArray("B71DB271DC338DF380AA2C4335EF8873B1AFD408E80B3582D8719FC81C5E511C"), // eticket_rsa_kek_source
|
||||
AsArray("E8965A187D30E57869F562D04383C996DE487BBA5761363D2D4D32391866A85C"), // eticket_rsa_kekek_source
|
||||
const std::array<SHA256Hash, 2> eticket_source_hashes{
|
||||
"B71DB271DC338DF380AA2C4335EF8873B1AFD408E80B3582D8719FC81C5E511C"_array32, // eticket_rsa_kek_source
|
||||
"E8965A187D30E57869F562D04383C996DE487BBA5761363D2D4D32391866A85C"_array32, // eticket_rsa_kekek_source
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
constexpr std::array<std::pair<std::string_view, KeyIndex<S128KeyType>>, 30> s128_file_id{{
|
||||
{"eticket_rsa_kek", {S128KeyType::ETicketRSAKek, 0, 0}},
|
||||
{"eticket_rsa_kek_source",
|
||||
{S128KeyType::Source, static_cast<u64>(SourceKeyType::ETicketKek), 0}},
|
||||
{"eticket_rsa_kekek_source",
|
||||
{S128KeyType::Source, static_cast<u64>(SourceKeyType::ETicketKekek), 0}},
|
||||
{"rsa_kek_mask_0", {S128KeyType::RSAKek, static_cast<u64>(RSAKekType::Mask0), 0}},
|
||||
{"rsa_kek_seed_3", {S128KeyType::RSAKek, static_cast<u64>(RSAKekType::Seed3), 0}},
|
||||
{"rsa_oaep_kek_generation_source",
|
||||
{S128KeyType::Source, static_cast<u64>(SourceKeyType::RSAOaepKekGeneration), 0}},
|
||||
{"sd_card_kek_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::SDKek), 0}},
|
||||
{"aes_kek_generation_source",
|
||||
{S128KeyType::Source, static_cast<u64>(SourceKeyType::AESKekGeneration), 0}},
|
||||
{"aes_key_generation_source",
|
||||
{S128KeyType::Source, static_cast<u64>(SourceKeyType::AESKeyGeneration), 0}},
|
||||
{"package2_key_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::Package2), 0}},
|
||||
{"master_key_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::Master), 0}},
|
||||
{"header_kek_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::HeaderKek), 0}},
|
||||
{"key_area_key_application_source",
|
||||
{S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyAreaKey),
|
||||
static_cast<u64>(KeyAreaKeyType::Application)}},
|
||||
{"key_area_key_ocean_source",
|
||||
{S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyAreaKey),
|
||||
static_cast<u64>(KeyAreaKeyType::Ocean)}},
|
||||
{"key_area_key_system_source",
|
||||
{S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyAreaKey),
|
||||
static_cast<u64>(KeyAreaKeyType::System)}},
|
||||
{"titlekek_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::Titlekek), 0}},
|
||||
{"keyblob_mac_key_source",
|
||||
{S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyblobMAC), 0}},
|
||||
{"tsec_key", {S128KeyType::TSEC, 0, 0}},
|
||||
{"secure_boot_key", {S128KeyType::SecureBoot, 0, 0}},
|
||||
{"sd_seed", {S128KeyType::SDSeed, 0, 0}},
|
||||
{"bis_key_0_crypt", {S128KeyType::BIS, 0, static_cast<u64>(BISKeyType::Crypto)}},
|
||||
{"bis_key_0_tweak", {S128KeyType::BIS, 0, static_cast<u64>(BISKeyType::Tweak)}},
|
||||
{"bis_key_1_crypt", {S128KeyType::BIS, 1, static_cast<u64>(BISKeyType::Crypto)}},
|
||||
{"bis_key_1_tweak", {S128KeyType::BIS, 1, static_cast<u64>(BISKeyType::Tweak)}},
|
||||
{"bis_key_2_crypt", {S128KeyType::BIS, 2, static_cast<u64>(BISKeyType::Crypto)}},
|
||||
{"bis_key_2_tweak", {S128KeyType::BIS, 2, static_cast<u64>(BISKeyType::Tweak)}},
|
||||
{"bis_key_3_crypt", {S128KeyType::BIS, 3, static_cast<u64>(BISKeyType::Crypto)}},
|
||||
{"bis_key_3_tweak", {S128KeyType::BIS, 3, static_cast<u64>(BISKeyType::Tweak)}},
|
||||
{"header_kek", {S128KeyType::HeaderKek, 0, 0}},
|
||||
{"sd_card_kek", {S128KeyType::SDKek, 0, 0}},
|
||||
}};
|
||||
|
||||
auto Find128ByName(std::string_view name) {
|
||||
return std::find_if(s128_file_id.begin(), s128_file_id.end(),
|
||||
[&name](const auto& pair) { return pair.first == name; });
|
||||
}
|
||||
|
||||
constexpr std::array<std::pair<std::string_view, KeyIndex<S256KeyType>>, 6> s256_file_id{{
|
||||
{"header_key", {S256KeyType::Header, 0, 0}},
|
||||
{"sd_card_save_key_source", {S256KeyType::SDKeySource, static_cast<u64>(SDKeyType::Save), 0}},
|
||||
{"sd_card_nca_key_source", {S256KeyType::SDKeySource, static_cast<u64>(SDKeyType::NCA), 0}},
|
||||
{"header_key_source", {S256KeyType::HeaderSource, 0, 0}},
|
||||
{"sd_card_save_key", {S256KeyType::SDKey, static_cast<u64>(SDKeyType::Save), 0}},
|
||||
{"sd_card_nca_key", {S256KeyType::SDKey, static_cast<u64>(SDKeyType::NCA), 0}},
|
||||
}};
|
||||
|
||||
auto Find256ByName(std::string_view name) {
|
||||
return std::find_if(s256_file_id.begin(), s256_file_id.end(),
|
||||
[&name](const auto& pair) { return pair.first == name; });
|
||||
}
|
||||
|
||||
using KeyArray = std::array<std::pair<std::pair<S128KeyType, u64>, std::string_view>, 7>;
|
||||
constexpr KeyArray KEYS_VARIABLE_LENGTH{{
|
||||
const std::map<std::pair<S128KeyType, u64>, std::string> KEYS_VARIABLE_LENGTH{
|
||||
{{S128KeyType::Master, 0}, "master_key_"},
|
||||
{{S128KeyType::Package1, 0}, "package1_key_"},
|
||||
{{S128KeyType::Package2, 0}, "package2_key_"},
|
||||
@@ -123,13 +55,14 @@ constexpr KeyArray KEYS_VARIABLE_LENGTH{{
|
||||
{{S128KeyType::Source, static_cast<u64>(SourceKeyType::Keyblob)}, "keyblob_key_source_"},
|
||||
{{S128KeyType::Keyblob, 0}, "keyblob_key_"},
|
||||
{{S128KeyType::KeyblobMAC, 0}, "keyblob_mac_key_"},
|
||||
}};
|
||||
};
|
||||
|
||||
namespace {
|
||||
template <std::size_t Size>
|
||||
bool IsAllZeroArray(const std::array<u8, Size>& array) {
|
||||
return std::all_of(array.begin(), array.end(), [](const auto& elem) { return elem == 0; });
|
||||
}
|
||||
} // Anonymous namespace
|
||||
} // namespace
|
||||
|
||||
u64 GetSignatureTypeDataSize(SignatureType type) {
|
||||
switch (type) {
|
||||
@@ -161,13 +94,13 @@ u64 GetSignatureTypePaddingSize(SignatureType type) {
|
||||
}
|
||||
|
||||
SignatureType Ticket::GetSignatureType() const {
|
||||
if (const auto* ticket = std::get_if<RSA4096Ticket>(&data)) {
|
||||
if (auto ticket = std::get_if<RSA4096Ticket>(&data)) {
|
||||
return ticket->sig_type;
|
||||
}
|
||||
if (const auto* ticket = std::get_if<RSA2048Ticket>(&data)) {
|
||||
if (auto ticket = std::get_if<RSA2048Ticket>(&data)) {
|
||||
return ticket->sig_type;
|
||||
}
|
||||
if (const auto* ticket = std::get_if<ECDSATicket>(&data)) {
|
||||
if (auto ticket = std::get_if<ECDSATicket>(&data)) {
|
||||
return ticket->sig_type;
|
||||
}
|
||||
|
||||
@@ -175,13 +108,13 @@ SignatureType Ticket::GetSignatureType() const {
|
||||
}
|
||||
|
||||
TicketData& Ticket::GetData() {
|
||||
if (auto* ticket = std::get_if<RSA4096Ticket>(&data)) {
|
||||
if (auto ticket = std::get_if<RSA4096Ticket>(&data)) {
|
||||
return ticket->data;
|
||||
}
|
||||
if (auto* ticket = std::get_if<RSA2048Ticket>(&data)) {
|
||||
if (auto ticket = std::get_if<RSA2048Ticket>(&data)) {
|
||||
return ticket->data;
|
||||
}
|
||||
if (auto* ticket = std::get_if<ECDSATicket>(&data)) {
|
||||
if (auto ticket = std::get_if<ECDSATicket>(&data)) {
|
||||
return ticket->data;
|
||||
}
|
||||
|
||||
@@ -189,13 +122,13 @@ TicketData& Ticket::GetData() {
|
||||
}
|
||||
|
||||
const TicketData& Ticket::GetData() const {
|
||||
if (const auto* ticket = std::get_if<RSA4096Ticket>(&data)) {
|
||||
if (auto ticket = std::get_if<RSA4096Ticket>(&data)) {
|
||||
return ticket->data;
|
||||
}
|
||||
if (const auto* ticket = std::get_if<RSA2048Ticket>(&data)) {
|
||||
if (auto ticket = std::get_if<RSA2048Ticket>(&data)) {
|
||||
return ticket->data;
|
||||
}
|
||||
if (const auto* ticket = std::get_if<ECDSATicket>(&data)) {
|
||||
if (auto ticket = std::get_if<ECDSATicket>(&data)) {
|
||||
return ticket->data;
|
||||
}
|
||||
|
||||
@@ -298,9 +231,8 @@ void KeyManager::DeriveGeneralPurposeKeys(std::size_t crypto_revision) {
|
||||
}
|
||||
|
||||
RSAKeyPair<2048> KeyManager::GetETicketRSAKey() const {
|
||||
if (IsAllZeroArray(eticket_extended_kek) || !HasKey(S128KeyType::ETicketRSAKek)) {
|
||||
if (IsAllZeroArray(eticket_extended_kek) || !HasKey(S128KeyType::ETicketRSAKek))
|
||||
return {};
|
||||
}
|
||||
|
||||
const auto eticket_final = GetKey(S128KeyType::ETicketRSAKek);
|
||||
|
||||
@@ -327,30 +259,27 @@ Key128 DeriveKeyblobMACKey(const Key128& keyblob_key, const Key128& mac_source)
|
||||
}
|
||||
|
||||
std::optional<Key128> DeriveSDSeed() {
|
||||
const Common::FS::IOFile save_43(Common::FS::GetUserPath(Common::FS::UserPath::NANDDir) +
|
||||
"/system/save/8000000000000043",
|
||||
"rb+");
|
||||
if (!save_43.IsOpen()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
const FileUtil::IOFile save_43(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) +
|
||||
"/system/save/8000000000000043",
|
||||
"rb+");
|
||||
if (!save_43.IsOpen())
|
||||
return {};
|
||||
|
||||
const Common::FS::IOFile sd_private(Common::FS::GetUserPath(Common::FS::UserPath::SDMCDir) +
|
||||
"/Nintendo/Contents/private",
|
||||
"rb+");
|
||||
if (!sd_private.IsOpen()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
const FileUtil::IOFile sd_private(
|
||||
FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir) + "/Nintendo/Contents/private", "rb+");
|
||||
if (!sd_private.IsOpen())
|
||||
return {};
|
||||
|
||||
std::array<u8, 0x10> private_seed{};
|
||||
if (sd_private.ReadBytes(private_seed.data(), private_seed.size()) != private_seed.size()) {
|
||||
return std::nullopt;
|
||||
return {};
|
||||
}
|
||||
|
||||
std::array<u8, 0x10> buffer{};
|
||||
std::size_t offset = 0;
|
||||
for (; offset + 0x10 < save_43.GetSize(); ++offset) {
|
||||
if (!save_43.Seek(offset, SEEK_SET)) {
|
||||
return std::nullopt;
|
||||
return {};
|
||||
}
|
||||
|
||||
save_43.ReadBytes(buffer.data(), buffer.size());
|
||||
@@ -360,26 +289,23 @@ std::optional<Key128> DeriveSDSeed() {
|
||||
}
|
||||
|
||||
if (!save_43.Seek(offset + 0x10, SEEK_SET)) {
|
||||
return std::nullopt;
|
||||
return {};
|
||||
}
|
||||
|
||||
Key128 seed{};
|
||||
if (save_43.ReadBytes(seed.data(), seed.size()) != seed.size()) {
|
||||
return std::nullopt;
|
||||
return {};
|
||||
}
|
||||
return seed;
|
||||
}
|
||||
|
||||
Loader::ResultStatus DeriveSDKeys(std::array<Key256, 2>& sd_keys, KeyManager& keys) {
|
||||
if (!keys.HasKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::SDKek))) {
|
||||
if (!keys.HasKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::SDKek)))
|
||||
return Loader::ResultStatus::ErrorMissingSDKEKSource;
|
||||
}
|
||||
if (!keys.HasKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::AESKekGeneration))) {
|
||||
if (!keys.HasKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::AESKekGeneration)))
|
||||
return Loader::ResultStatus::ErrorMissingAESKEKGenerationSource;
|
||||
}
|
||||
if (!keys.HasKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::AESKeyGeneration))) {
|
||||
if (!keys.HasKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::AESKeyGeneration)))
|
||||
return Loader::ResultStatus::ErrorMissingAESKeyGenerationSource;
|
||||
}
|
||||
|
||||
const auto sd_kek_source =
|
||||
keys.GetKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::SDKek));
|
||||
@@ -392,17 +318,14 @@ Loader::ResultStatus DeriveSDKeys(std::array<Key256, 2>& sd_keys, KeyManager& ke
|
||||
GenerateKeyEncryptionKey(sd_kek_source, master_00, aes_kek_gen, aes_key_gen);
|
||||
keys.SetKey(S128KeyType::SDKek, sd_kek);
|
||||
|
||||
if (!keys.HasKey(S128KeyType::SDSeed)) {
|
||||
if (!keys.HasKey(S128KeyType::SDSeed))
|
||||
return Loader::ResultStatus::ErrorMissingSDSeed;
|
||||
}
|
||||
const auto sd_seed = keys.GetKey(S128KeyType::SDSeed);
|
||||
|
||||
if (!keys.HasKey(S256KeyType::SDKeySource, static_cast<u64>(SDKeyType::Save))) {
|
||||
if (!keys.HasKey(S256KeyType::SDKeySource, static_cast<u64>(SDKeyType::Save)))
|
||||
return Loader::ResultStatus::ErrorMissingSDSaveKeySource;
|
||||
}
|
||||
if (!keys.HasKey(S256KeyType::SDKeySource, static_cast<u64>(SDKeyType::NCA))) {
|
||||
if (!keys.HasKey(S256KeyType::SDKeySource, static_cast<u64>(SDKeyType::NCA)))
|
||||
return Loader::ResultStatus::ErrorMissingSDNCAKeySource;
|
||||
}
|
||||
|
||||
std::array<Key256, 2> sd_key_sources{
|
||||
keys.GetKey(S256KeyType::SDKeySource, static_cast<u64>(SDKeyType::Save)),
|
||||
@@ -411,9 +334,8 @@ Loader::ResultStatus DeriveSDKeys(std::array<Key256, 2>& sd_keys, KeyManager& ke
|
||||
|
||||
// Combine sources and seed
|
||||
for (auto& source : sd_key_sources) {
|
||||
for (std::size_t i = 0; i < source.size(); ++i) {
|
||||
for (std::size_t i = 0; i < source.size(); ++i)
|
||||
source[i] ^= sd_seed[i & 0xF];
|
||||
}
|
||||
}
|
||||
|
||||
AESCipher<Key128> cipher(sd_kek, Mode::ECB);
|
||||
@@ -431,10 +353,9 @@ Loader::ResultStatus DeriveSDKeys(std::array<Key256, 2>& sd_keys, KeyManager& ke
|
||||
return Loader::ResultStatus::Success;
|
||||
}
|
||||
|
||||
std::vector<Ticket> GetTicketblob(const Common::FS::IOFile& ticket_save) {
|
||||
if (!ticket_save.IsOpen()) {
|
||||
std::vector<Ticket> GetTicketblob(const FileUtil::IOFile& ticket_save) {
|
||||
if (!ticket_save.IsOpen())
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<u8> buffer(ticket_save.GetSize());
|
||||
if (ticket_save.ReadBytes(buffer.data(), buffer.size()) != buffer.size()) {
|
||||
@@ -494,7 +415,7 @@ static std::optional<u64> FindTicketOffset(const std::array<u8, size>& data) {
|
||||
offset = i + 1;
|
||||
break;
|
||||
} else if (data[i] != 0x0) {
|
||||
return std::nullopt;
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -504,18 +425,16 @@ static std::optional<u64> FindTicketOffset(const std::array<u8, size>& data) {
|
||||
std::optional<std::pair<Key128, Key128>> ParseTicket(const Ticket& ticket,
|
||||
const RSAKeyPair<2048>& key) {
|
||||
const auto issuer = ticket.GetData().issuer;
|
||||
if (IsAllZeroArray(issuer)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
if (IsAllZeroArray(issuer))
|
||||
return {};
|
||||
if (issuer[0] != 'R' || issuer[1] != 'o' || issuer[2] != 'o' || issuer[3] != 't') {
|
||||
LOG_INFO(Crypto, "Attempting to parse ticket with non-standard certificate authority.");
|
||||
}
|
||||
|
||||
Key128 rights_id = ticket.GetData().rights_id;
|
||||
|
||||
if (rights_id == Key128{}) {
|
||||
return std::nullopt;
|
||||
}
|
||||
if (rights_id == Key128{})
|
||||
return {};
|
||||
|
||||
if (!std::any_of(ticket.GetData().title_key_common_pad.begin(),
|
||||
ticket.GetData().title_key_common_pad.end(), [](u8 b) { return b != 0; })) {
|
||||
@@ -547,17 +466,15 @@ std::optional<std::pair<Key128, Key128>> ParseTicket(const Ticket& ticket,
|
||||
std::array<u8, 0xDF> m_2;
|
||||
std::memcpy(m_2.data(), rsa_step.data() + 0x21, m_2.size());
|
||||
|
||||
if (m_0 != 0) {
|
||||
return std::nullopt;
|
||||
}
|
||||
if (m_0 != 0)
|
||||
return {};
|
||||
|
||||
m_1 = m_1 ^ MGF1<0x20>(m_2);
|
||||
m_2 = m_2 ^ MGF1<0xDF>(m_1);
|
||||
|
||||
const auto offset = FindTicketOffset(m_2);
|
||||
if (!offset) {
|
||||
return std::nullopt;
|
||||
}
|
||||
if (!offset)
|
||||
return {};
|
||||
ASSERT(*offset > 0);
|
||||
|
||||
Key128 key_temp{};
|
||||
@@ -568,8 +485,8 @@ std::optional<std::pair<Key128, Key128>> ParseTicket(const Ticket& ticket,
|
||||
|
||||
KeyManager::KeyManager() {
|
||||
// Initialize keys
|
||||
const std::string hactool_keys_dir = Common::FS::GetHactoolConfigurationPath();
|
||||
const std::string yuzu_keys_dir = Common::FS::GetUserPath(Common::FS::UserPath::KeysDir);
|
||||
const std::string hactool_keys_dir = FileUtil::GetHactoolConfigurationPath();
|
||||
const std::string yuzu_keys_dir = FileUtil::GetUserPath(FileUtil::UserPath::KeysDir);
|
||||
if (Settings::values.use_dev_keys) {
|
||||
dev_mode = true;
|
||||
AttemptLoadKeyFile(yuzu_keys_dir, hactool_keys_dir, "dev.keys", false);
|
||||
@@ -587,39 +504,34 @@ KeyManager::KeyManager() {
|
||||
}
|
||||
|
||||
static bool ValidCryptoRevisionString(std::string_view base, size_t begin, size_t length) {
|
||||
if (base.size() < begin + length) {
|
||||
if (base.size() < begin + length)
|
||||
return false;
|
||||
}
|
||||
return std::all_of(base.begin() + begin, base.begin() + begin + length,
|
||||
[](u8 c) { return std::isxdigit(c); });
|
||||
}
|
||||
|
||||
void KeyManager::LoadFromFile(const std::string& filename, bool is_title_keys) {
|
||||
std::ifstream file;
|
||||
Common::FS::OpenFStream(file, filename, std::ios_base::in);
|
||||
if (!file.is_open()) {
|
||||
OpenFStream(file, filename, std::ios_base::in);
|
||||
if (!file.is_open())
|
||||
return;
|
||||
}
|
||||
|
||||
std::string line;
|
||||
while (std::getline(file, line)) {
|
||||
std::vector<std::string> out;
|
||||
std::stringstream stream(line);
|
||||
std::string item;
|
||||
while (std::getline(stream, item, '=')) {
|
||||
while (std::getline(stream, item, '='))
|
||||
out.push_back(std::move(item));
|
||||
}
|
||||
|
||||
if (out.size() != 2) {
|
||||
if (out.size() != 2)
|
||||
continue;
|
||||
}
|
||||
|
||||
out[0].erase(std::remove(out[0].begin(), out[0].end(), ' '), out[0].end());
|
||||
out[1].erase(std::remove(out[1].begin(), out[1].end(), ' '), out[1].end());
|
||||
|
||||
if (out[0].compare(0, 1, "#") == 0) {
|
||||
if (out[0].compare(0, 1, "#") == 0)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_title_keys) {
|
||||
auto rights_id_raw = Common::HexStringToArray<16>(out[0]);
|
||||
@@ -629,26 +541,24 @@ void KeyManager::LoadFromFile(const std::string& filename, bool is_title_keys) {
|
||||
s128_keys[{S128KeyType::Titlekey, rights_id[1], rights_id[0]}] = key;
|
||||
} else {
|
||||
out[0] = Common::ToLower(out[0]);
|
||||
if (const auto iter128 = Find128ByName(out[0]); iter128 != s128_file_id.end()) {
|
||||
const auto& index = iter128->second;
|
||||
const Key128 key = Common::HexStringToArray<16>(out[1]);
|
||||
if (s128_file_id.find(out[0]) != s128_file_id.end()) {
|
||||
const auto index = s128_file_id.at(out[0]);
|
||||
Key128 key = Common::HexStringToArray<16>(out[1]);
|
||||
s128_keys[{index.type, index.field1, index.field2}] = key;
|
||||
} else if (const auto iter256 = Find256ByName(out[0]); iter256 != s256_file_id.end()) {
|
||||
const auto& index = iter256->second;
|
||||
const Key256 key = Common::HexStringToArray<32>(out[1]);
|
||||
} else if (s256_file_id.find(out[0]) != s256_file_id.end()) {
|
||||
const auto index = s256_file_id.at(out[0]);
|
||||
Key256 key = Common::HexStringToArray<32>(out[1]);
|
||||
s256_keys[{index.type, index.field1, index.field2}] = key;
|
||||
} else if (out[0].compare(0, 8, "keyblob_") == 0 &&
|
||||
out[0].compare(0, 9, "keyblob_k") != 0) {
|
||||
if (!ValidCryptoRevisionString(out[0], 8, 2)) {
|
||||
if (!ValidCryptoRevisionString(out[0], 8, 2))
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto index = std::stoul(out[0].substr(8, 2), nullptr, 16);
|
||||
keyblobs[index] = Common::HexStringToArray<0x90>(out[1]);
|
||||
} else if (out[0].compare(0, 18, "encrypted_keyblob_") == 0) {
|
||||
if (!ValidCryptoRevisionString(out[0], 18, 2)) {
|
||||
if (!ValidCryptoRevisionString(out[0], 18, 2))
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto index = std::stoul(out[0].substr(18, 2), nullptr, 16);
|
||||
encrypted_keyblobs[index] = Common::HexStringToArray<0xB0>(out[1]);
|
||||
@@ -656,9 +566,8 @@ void KeyManager::LoadFromFile(const std::string& filename, bool is_title_keys) {
|
||||
eticket_extended_kek = Common::HexStringToArray<576>(out[1]);
|
||||
} else {
|
||||
for (const auto& kv : KEYS_VARIABLE_LENGTH) {
|
||||
if (!ValidCryptoRevisionString(out[0], kv.second.size(), 2)) {
|
||||
if (!ValidCryptoRevisionString(out[0], kv.second.size(), 2))
|
||||
continue;
|
||||
}
|
||||
if (out[0].compare(0, kv.second.size(), kv.second) == 0) {
|
||||
const auto index =
|
||||
std::stoul(out[0].substr(kv.second.size(), 2), nullptr, 16);
|
||||
@@ -693,11 +602,10 @@ void KeyManager::LoadFromFile(const std::string& filename, bool is_title_keys) {
|
||||
|
||||
void KeyManager::AttemptLoadKeyFile(const std::string& dir1, const std::string& dir2,
|
||||
const std::string& filename, bool title) {
|
||||
if (Common::FS::Exists(dir1 + DIR_SEP + filename)) {
|
||||
if (FileUtil::Exists(dir1 + DIR_SEP + filename))
|
||||
LoadFromFile(dir1 + DIR_SEP + filename, title);
|
||||
} else if (Common::FS::Exists(dir2 + DIR_SEP + filename)) {
|
||||
else if (FileUtil::Exists(dir2 + DIR_SEP + filename))
|
||||
LoadFromFile(dir2 + DIR_SEP + filename, title);
|
||||
}
|
||||
}
|
||||
|
||||
bool KeyManager::BaseDeriveNecessary() const {
|
||||
@@ -705,9 +613,8 @@ bool KeyManager::BaseDeriveNecessary() const {
|
||||
return !HasKey(key_type, index1, index2);
|
||||
};
|
||||
|
||||
if (check_key_existence(S256KeyType::Header)) {
|
||||
if (check_key_existence(S256KeyType::Header))
|
||||
return true;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < CURRENT_CRYPTO_REVISION; ++i) {
|
||||
if (check_key_existence(S128KeyType::Master, i) ||
|
||||
@@ -732,16 +639,14 @@ bool KeyManager::HasKey(S256KeyType id, u64 field1, u64 field2) const {
|
||||
}
|
||||
|
||||
Key128 KeyManager::GetKey(S128KeyType id, u64 field1, u64 field2) const {
|
||||
if (!HasKey(id, field1, field2)) {
|
||||
if (!HasKey(id, field1, field2))
|
||||
return {};
|
||||
}
|
||||
return s128_keys.at({id, field1, field2});
|
||||
}
|
||||
|
||||
Key256 KeyManager::GetKey(S256KeyType id, u64 field1, u64 field2) const {
|
||||
if (!HasKey(id, field1, field2)) {
|
||||
if (!HasKey(id, field1, field2))
|
||||
return {};
|
||||
}
|
||||
return s256_keys.at({id, field1, field2});
|
||||
}
|
||||
|
||||
@@ -763,7 +668,7 @@ Key256 KeyManager::GetBISKey(u8 partition_id) const {
|
||||
template <size_t Size>
|
||||
void KeyManager::WriteKeyToFile(KeyCategory category, std::string_view keyname,
|
||||
const std::array<u8, Size>& key) {
|
||||
const std::string yuzu_keys_dir = Common::FS::GetUserPath(Common::FS::UserPath::KeysDir);
|
||||
const std::string yuzu_keys_dir = FileUtil::GetUserPath(FileUtil::UserPath::KeysDir);
|
||||
std::string filename = "title.keys_autogenerated";
|
||||
if (category == KeyCategory::Standard) {
|
||||
filename = dev_mode ? "dev.keys_autogenerated" : "prod.keys_autogenerated";
|
||||
@@ -772,9 +677,9 @@ void KeyManager::WriteKeyToFile(KeyCategory category, std::string_view keyname,
|
||||
}
|
||||
|
||||
const auto path = yuzu_keys_dir + DIR_SEP + filename;
|
||||
const auto add_info_text = !Common::FS::Exists(path);
|
||||
Common::FS::CreateFullPath(path);
|
||||
Common::FS::IOFile file{path, "a"};
|
||||
const auto add_info_text = !FileUtil::Exists(path);
|
||||
FileUtil::CreateFullPath(path);
|
||||
FileUtil::IOFile file{path, "a"};
|
||||
if (!file.IsOpen()) {
|
||||
return;
|
||||
}
|
||||
@@ -807,7 +712,8 @@ void KeyManager::SetKey(S128KeyType id, Key128 key, u64 field1, u64 field2) {
|
||||
}
|
||||
|
||||
const auto iter2 = std::find_if(
|
||||
s128_file_id.begin(), s128_file_id.end(), [&id, &field1, &field2](const auto& elem) {
|
||||
s128_file_id.begin(), s128_file_id.end(),
|
||||
[&id, &field1, &field2](const std::pair<std::string, KeyIndex<S128KeyType>> elem) {
|
||||
return std::tie(elem.second.type, elem.second.field1, elem.second.field2) ==
|
||||
std::tie(id, field1, field2);
|
||||
});
|
||||
@@ -817,11 +723,9 @@ void KeyManager::SetKey(S128KeyType id, Key128 key, u64 field1, u64 field2) {
|
||||
|
||||
// Variable cases
|
||||
if (id == S128KeyType::KeyArea) {
|
||||
static constexpr std::array<const char*, 3> kak_names = {
|
||||
"key_area_key_application_{:02X}",
|
||||
"key_area_key_ocean_{:02X}",
|
||||
"key_area_key_system_{:02X}",
|
||||
};
|
||||
static constexpr std::array<const char*, 3> kak_names = {"key_area_key_application_{:02X}",
|
||||
"key_area_key_ocean_{:02X}",
|
||||
"key_area_key_system_{:02X}"};
|
||||
WriteKeyToFile(category, fmt::format(kak_names.at(field2), field1), key);
|
||||
} else if (id == S128KeyType::Master) {
|
||||
WriteKeyToFile(category, fmt::format("master_key_{:02X}", field1), key);
|
||||
@@ -847,7 +751,8 @@ void KeyManager::SetKey(S256KeyType id, Key256 key, u64 field1, u64 field2) {
|
||||
return;
|
||||
}
|
||||
const auto iter = std::find_if(
|
||||
s256_file_id.begin(), s256_file_id.end(), [&id, &field1, &field2](const auto& elem) {
|
||||
s256_file_id.begin(), s256_file_id.end(),
|
||||
[&id, &field1, &field2](const std::pair<std::string, KeyIndex<S256KeyType>> elem) {
|
||||
return std::tie(elem.second.type, elem.second.field1, elem.second.field2) ==
|
||||
std::tie(id, field1, field2);
|
||||
});
|
||||
@@ -858,31 +763,29 @@ void KeyManager::SetKey(S256KeyType id, Key256 key, u64 field1, u64 field2) {
|
||||
}
|
||||
|
||||
bool KeyManager::KeyFileExists(bool title) {
|
||||
const std::string hactool_keys_dir = Common::FS::GetHactoolConfigurationPath();
|
||||
const std::string yuzu_keys_dir = Common::FS::GetUserPath(Common::FS::UserPath::KeysDir);
|
||||
const std::string hactool_keys_dir = FileUtil::GetHactoolConfigurationPath();
|
||||
const std::string yuzu_keys_dir = FileUtil::GetUserPath(FileUtil::UserPath::KeysDir);
|
||||
if (title) {
|
||||
return Common::FS::Exists(hactool_keys_dir + DIR_SEP + "title.keys") ||
|
||||
Common::FS::Exists(yuzu_keys_dir + DIR_SEP + "title.keys");
|
||||
return FileUtil::Exists(hactool_keys_dir + DIR_SEP + "title.keys") ||
|
||||
FileUtil::Exists(yuzu_keys_dir + DIR_SEP + "title.keys");
|
||||
}
|
||||
|
||||
if (Settings::values.use_dev_keys) {
|
||||
return Common::FS::Exists(hactool_keys_dir + DIR_SEP + "dev.keys") ||
|
||||
Common::FS::Exists(yuzu_keys_dir + DIR_SEP + "dev.keys");
|
||||
return FileUtil::Exists(hactool_keys_dir + DIR_SEP + "dev.keys") ||
|
||||
FileUtil::Exists(yuzu_keys_dir + DIR_SEP + "dev.keys");
|
||||
}
|
||||
|
||||
return Common::FS::Exists(hactool_keys_dir + DIR_SEP + "prod.keys") ||
|
||||
Common::FS::Exists(yuzu_keys_dir + DIR_SEP + "prod.keys");
|
||||
return FileUtil::Exists(hactool_keys_dir + DIR_SEP + "prod.keys") ||
|
||||
FileUtil::Exists(yuzu_keys_dir + DIR_SEP + "prod.keys");
|
||||
}
|
||||
|
||||
void KeyManager::DeriveSDSeedLazy() {
|
||||
if (HasKey(S128KeyType::SDSeed)) {
|
||||
if (HasKey(S128KeyType::SDSeed))
|
||||
return;
|
||||
}
|
||||
|
||||
const auto res = DeriveSDSeed();
|
||||
if (res) {
|
||||
if (res)
|
||||
SetKey(S128KeyType::SDSeed, *res);
|
||||
}
|
||||
}
|
||||
|
||||
static Key128 CalculateCMAC(const u8* source, size_t size, const Key128& key) {
|
||||
@@ -894,13 +797,11 @@ static Key128 CalculateCMAC(const u8* source, size_t size, const Key128& key) {
|
||||
}
|
||||
|
||||
void KeyManager::DeriveBase() {
|
||||
if (!BaseDeriveNecessary()) {
|
||||
if (!BaseDeriveNecessary())
|
||||
return;
|
||||
}
|
||||
|
||||
if (!HasKey(S128KeyType::SecureBoot) || !HasKey(S128KeyType::TSEC)) {
|
||||
if (!HasKey(S128KeyType::SecureBoot) || !HasKey(S128KeyType::TSEC))
|
||||
return;
|
||||
}
|
||||
|
||||
const auto has_bis = [this](u64 id) {
|
||||
return HasKey(S128KeyType::BIS, id, static_cast<u64>(BISKeyType::Crypto)) &&
|
||||
@@ -917,11 +818,10 @@ void KeyManager::DeriveBase() {
|
||||
static_cast<u64>(BISKeyType::Tweak));
|
||||
};
|
||||
|
||||
if (has_bis(2) && !has_bis(3)) {
|
||||
if (has_bis(2) && !has_bis(3))
|
||||
copy_bis(2, 3);
|
||||
} else if (has_bis(3) && !has_bis(2)) {
|
||||
else if (has_bis(3) && !has_bis(2))
|
||||
copy_bis(3, 2);
|
||||
}
|
||||
|
||||
std::bitset<32> revisions(0xFFFFFFFF);
|
||||
for (size_t i = 0; i < revisions.size(); ++i) {
|
||||
@@ -931,17 +831,15 @@ void KeyManager::DeriveBase() {
|
||||
}
|
||||
}
|
||||
|
||||
if (!revisions.any()) {
|
||||
if (!revisions.any())
|
||||
return;
|
||||
}
|
||||
|
||||
const auto sbk = GetKey(S128KeyType::SecureBoot);
|
||||
const auto tsec = GetKey(S128KeyType::TSEC);
|
||||
|
||||
for (size_t i = 0; i < revisions.size(); ++i) {
|
||||
if (!revisions[i]) {
|
||||
if (!revisions[i])
|
||||
continue;
|
||||
}
|
||||
|
||||
// Derive keyblob key
|
||||
const auto key = DeriveKeyblobKey(
|
||||
@@ -950,18 +848,16 @@ void KeyManager::DeriveBase() {
|
||||
SetKey(S128KeyType::Keyblob, key, i);
|
||||
|
||||
// Derive keyblob MAC key
|
||||
if (!HasKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyblobMAC))) {
|
||||
if (!HasKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyblobMAC)))
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto mac_key = DeriveKeyblobMACKey(
|
||||
key, GetKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyblobMAC)));
|
||||
SetKey(S128KeyType::KeyblobMAC, mac_key, i);
|
||||
|
||||
Key128 cmac = CalculateCMAC(encrypted_keyblobs[i].data() + 0x10, 0xA0, mac_key);
|
||||
if (std::memcmp(cmac.data(), encrypted_keyblobs[i].data(), cmac.size()) != 0) {
|
||||
if (std::memcmp(cmac.data(), encrypted_keyblobs[i].data(), cmac.size()) != 0)
|
||||
continue;
|
||||
}
|
||||
|
||||
// Decrypt keyblob
|
||||
if (keyblobs[i] == std::array<u8, 0x90>{}) {
|
||||
@@ -985,19 +881,16 @@ void KeyManager::DeriveBase() {
|
||||
|
||||
revisions.set();
|
||||
for (size_t i = 0; i < revisions.size(); ++i) {
|
||||
if (!HasKey(S128KeyType::Master, i)) {
|
||||
if (!HasKey(S128KeyType::Master, i))
|
||||
revisions.reset(i);
|
||||
}
|
||||
}
|
||||
|
||||
if (!revisions.any()) {
|
||||
if (!revisions.any())
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < revisions.size(); ++i) {
|
||||
if (!revisions[i]) {
|
||||
if (!revisions[i])
|
||||
continue;
|
||||
}
|
||||
|
||||
// Derive general purpose keys
|
||||
DeriveGeneralPurposeKeys(i);
|
||||
@@ -1027,19 +920,16 @@ void KeyManager::DeriveETicket(PartitionDataManager& data) {
|
||||
const auto es = Core::System::GetInstance().GetContentProvider().GetEntry(
|
||||
0x0100000000000033, FileSys::ContentRecordType::Program);
|
||||
|
||||
if (es == nullptr) {
|
||||
if (es == nullptr)
|
||||
return;
|
||||
}
|
||||
|
||||
const auto exefs = es->GetExeFS();
|
||||
if (exefs == nullptr) {
|
||||
if (exefs == nullptr)
|
||||
return;
|
||||
}
|
||||
|
||||
const auto main = exefs->GetFile("main");
|
||||
if (main == nullptr) {
|
||||
if (main == nullptr)
|
||||
return;
|
||||
}
|
||||
|
||||
const auto bytes = main->ReadAllBytes();
|
||||
|
||||
@@ -1049,19 +939,16 @@ void KeyManager::DeriveETicket(PartitionDataManager& data) {
|
||||
const auto seed3 = data.GetRSAKekSeed3();
|
||||
const auto mask0 = data.GetRSAKekMask0();
|
||||
|
||||
if (eticket_kek != Key128{}) {
|
||||
if (eticket_kek != Key128{})
|
||||
SetKey(S128KeyType::Source, eticket_kek, static_cast<size_t>(SourceKeyType::ETicketKek));
|
||||
}
|
||||
if (eticket_kekek != Key128{}) {
|
||||
SetKey(S128KeyType::Source, eticket_kekek,
|
||||
static_cast<size_t>(SourceKeyType::ETicketKekek));
|
||||
}
|
||||
if (seed3 != Key128{}) {
|
||||
if (seed3 != Key128{})
|
||||
SetKey(S128KeyType::RSAKek, seed3, static_cast<size_t>(RSAKekType::Seed3));
|
||||
}
|
||||
if (mask0 != Key128{}) {
|
||||
if (mask0 != Key128{})
|
||||
SetKey(S128KeyType::RSAKek, mask0, static_cast<size_t>(RSAKekType::Mask0));
|
||||
}
|
||||
if (eticket_kek == Key128{} || eticket_kekek == Key128{} || seed3 == Key128{} ||
|
||||
mask0 == Key128{}) {
|
||||
return;
|
||||
@@ -1087,9 +974,8 @@ void KeyManager::DeriveETicket(PartitionDataManager& data) {
|
||||
AESCipher<Key128> es_kek(temp_kekek, Mode::ECB);
|
||||
es_kek.Transcode(eticket_kek.data(), eticket_kek.size(), eticket_final.data(), Op::Decrypt);
|
||||
|
||||
if (eticket_final == Key128{}) {
|
||||
if (eticket_final == Key128{})
|
||||
return;
|
||||
}
|
||||
|
||||
SetKey(S128KeyType::ETicketRSAKek, eticket_final);
|
||||
|
||||
@@ -1104,20 +990,18 @@ void KeyManager::DeriveETicket(PartitionDataManager& data) {
|
||||
void KeyManager::PopulateTickets() {
|
||||
const auto rsa_key = GetETicketRSAKey();
|
||||
|
||||
if (rsa_key == RSAKeyPair<2048>{}) {
|
||||
if (rsa_key == RSAKeyPair<2048>{})
|
||||
return;
|
||||
}
|
||||
|
||||
if (!common_tickets.empty() && !personal_tickets.empty()) {
|
||||
if (!common_tickets.empty() && !personal_tickets.empty())
|
||||
return;
|
||||
}
|
||||
|
||||
const Common::FS::IOFile save1(Common::FS::GetUserPath(Common::FS::UserPath::NANDDir) +
|
||||
"/system/save/80000000000000e1",
|
||||
"rb+");
|
||||
const Common::FS::IOFile save2(Common::FS::GetUserPath(Common::FS::UserPath::NANDDir) +
|
||||
"/system/save/80000000000000e2",
|
||||
"rb+");
|
||||
const FileUtil::IOFile save1(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) +
|
||||
"/system/save/80000000000000e1",
|
||||
"rb+");
|
||||
const FileUtil::IOFile save2(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) +
|
||||
"/system/save/80000000000000e2",
|
||||
"rb+");
|
||||
|
||||
const auto blob2 = GetTicketblob(save2);
|
||||
auto res = GetTicketblob(save1);
|
||||
@@ -1127,10 +1011,8 @@ void KeyManager::PopulateTickets() {
|
||||
for (std::size_t i = 0; i < res.size(); ++i) {
|
||||
const auto common = i < idx;
|
||||
const auto pair = ParseTicket(res[i], rsa_key);
|
||||
if (!pair) {
|
||||
if (!pair)
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto& [rid, key] = *pair;
|
||||
u128 rights_id;
|
||||
std::memcpy(rights_id.data(), rid.data(), rid.size());
|
||||
@@ -1159,33 +1041,27 @@ void KeyManager::SynthesizeTickets() {
|
||||
}
|
||||
|
||||
void KeyManager::SetKeyWrapped(S128KeyType id, Key128 key, u64 field1, u64 field2) {
|
||||
if (key == Key128{}) {
|
||||
if (key == Key128{})
|
||||
return;
|
||||
}
|
||||
SetKey(id, key, field1, field2);
|
||||
}
|
||||
|
||||
void KeyManager::SetKeyWrapped(S256KeyType id, Key256 key, u64 field1, u64 field2) {
|
||||
if (key == Key256{}) {
|
||||
if (key == Key256{})
|
||||
return;
|
||||
}
|
||||
|
||||
SetKey(id, key, field1, field2);
|
||||
}
|
||||
|
||||
void KeyManager::PopulateFromPartitionData(PartitionDataManager& data) {
|
||||
if (!BaseDeriveNecessary()) {
|
||||
if (!BaseDeriveNecessary())
|
||||
return;
|
||||
}
|
||||
|
||||
if (!data.HasBoot0()) {
|
||||
if (!data.HasBoot0())
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < encrypted_keyblobs.size(); ++i) {
|
||||
if (encrypted_keyblobs[i] != std::array<u8, 0xB0>{}) {
|
||||
if (encrypted_keyblobs[i] != std::array<u8, 0xB0>{})
|
||||
continue;
|
||||
}
|
||||
encrypted_keyblobs[i] = data.GetEncryptedKeyblob(i);
|
||||
WriteKeyToFile<0xB0>(KeyCategory::Console, fmt::format("encrypted_keyblob_{:02X}", i),
|
||||
encrypted_keyblobs[i]);
|
||||
@@ -1207,9 +1083,8 @@ void KeyManager::PopulateFromPartitionData(PartitionDataManager& data) {
|
||||
static_cast<u64>(SourceKeyType::Keyblob), i);
|
||||
}
|
||||
|
||||
if (data.HasFuses()) {
|
||||
if (data.HasFuses())
|
||||
SetKeyWrapped(S128KeyType::SecureBoot, data.GetSecureBootKey());
|
||||
}
|
||||
|
||||
DeriveBase();
|
||||
|
||||
@@ -1223,9 +1098,8 @@ void KeyManager::PopulateFromPartitionData(PartitionDataManager& data) {
|
||||
|
||||
const auto masters = data.GetTZMasterKeys(latest_master);
|
||||
for (size_t i = 0; i < masters.size(); ++i) {
|
||||
if (masters[i] != Key128{} && !HasKey(S128KeyType::Master, i)) {
|
||||
if (masters[i] != Key128{} && !HasKey(S128KeyType::Master, i))
|
||||
SetKey(S128KeyType::Master, masters[i], i);
|
||||
}
|
||||
}
|
||||
|
||||
DeriveBase();
|
||||
@@ -1235,9 +1109,8 @@ void KeyManager::PopulateFromPartitionData(PartitionDataManager& data) {
|
||||
|
||||
std::array<Key128, 0x20> package2_keys{};
|
||||
for (size_t i = 0; i < package2_keys.size(); ++i) {
|
||||
if (HasKey(S128KeyType::Package2, i)) {
|
||||
if (HasKey(S128KeyType::Package2, i))
|
||||
package2_keys[i] = GetKey(S128KeyType::Package2, i);
|
||||
}
|
||||
}
|
||||
data.DecryptPackage2(package2_keys, Package2Type::NormalMain);
|
||||
|
||||
@@ -1275,15 +1148,12 @@ const std::map<u128, Ticket>& KeyManager::GetPersonalizedTickets() const {
|
||||
|
||||
bool KeyManager::AddTicketCommon(Ticket raw) {
|
||||
const auto rsa_key = GetETicketRSAKey();
|
||||
if (rsa_key == RSAKeyPair<2048>{}) {
|
||||
if (rsa_key == RSAKeyPair<2048>{})
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto pair = ParseTicket(raw, rsa_key);
|
||||
if (!pair) {
|
||||
if (!pair)
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto& [rid, key] = *pair;
|
||||
u128 rights_id;
|
||||
std::memcpy(rights_id.data(), rid.data(), rid.size());
|
||||
@@ -1294,15 +1164,12 @@ bool KeyManager::AddTicketCommon(Ticket raw) {
|
||||
|
||||
bool KeyManager::AddTicketPersonalized(Ticket raw) {
|
||||
const auto rsa_key = GetETicketRSAKey();
|
||||
if (rsa_key == RSAKeyPair<2048>{}) {
|
||||
if (rsa_key == RSAKeyPair<2048>{})
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto pair = ParseTicket(raw, rsa_key);
|
||||
if (!pair) {
|
||||
if (!pair)
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto& [rid, key] = *pair;
|
||||
u128 rights_id;
|
||||
std::memcpy(rights_id.data(), rid.data(), rid.size());
|
||||
@@ -1310,4 +1177,58 @@ bool KeyManager::AddTicketPersonalized(Ticket raw) {
|
||||
SetKey(S128KeyType::Titlekey, key, rights_id[1], rights_id[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
const boost::container::flat_map<std::string, KeyIndex<S128KeyType>> KeyManager::s128_file_id = {
|
||||
{"eticket_rsa_kek", {S128KeyType::ETicketRSAKek, 0, 0}},
|
||||
{"eticket_rsa_kek_source",
|
||||
{S128KeyType::Source, static_cast<u64>(SourceKeyType::ETicketKek), 0}},
|
||||
{"eticket_rsa_kekek_source",
|
||||
{S128KeyType::Source, static_cast<u64>(SourceKeyType::ETicketKekek), 0}},
|
||||
{"rsa_kek_mask_0", {S128KeyType::RSAKek, static_cast<u64>(RSAKekType::Mask0), 0}},
|
||||
{"rsa_kek_seed_3", {S128KeyType::RSAKek, static_cast<u64>(RSAKekType::Seed3), 0}},
|
||||
{"rsa_oaep_kek_generation_source",
|
||||
{S128KeyType::Source, static_cast<u64>(SourceKeyType::RSAOaepKekGeneration), 0}},
|
||||
{"sd_card_kek_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::SDKek), 0}},
|
||||
{"aes_kek_generation_source",
|
||||
{S128KeyType::Source, static_cast<u64>(SourceKeyType::AESKekGeneration), 0}},
|
||||
{"aes_key_generation_source",
|
||||
{S128KeyType::Source, static_cast<u64>(SourceKeyType::AESKeyGeneration), 0}},
|
||||
{"package2_key_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::Package2), 0}},
|
||||
{"master_key_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::Master), 0}},
|
||||
{"header_kek_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::HeaderKek), 0}},
|
||||
{"key_area_key_application_source",
|
||||
{S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyAreaKey),
|
||||
static_cast<u64>(KeyAreaKeyType::Application)}},
|
||||
{"key_area_key_ocean_source",
|
||||
{S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyAreaKey),
|
||||
static_cast<u64>(KeyAreaKeyType::Ocean)}},
|
||||
{"key_area_key_system_source",
|
||||
{S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyAreaKey),
|
||||
static_cast<u64>(KeyAreaKeyType::System)}},
|
||||
{"titlekek_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::Titlekek), 0}},
|
||||
{"keyblob_mac_key_source",
|
||||
{S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyblobMAC), 0}},
|
||||
{"tsec_key", {S128KeyType::TSEC, 0, 0}},
|
||||
{"secure_boot_key", {S128KeyType::SecureBoot, 0, 0}},
|
||||
{"sd_seed", {S128KeyType::SDSeed, 0, 0}},
|
||||
{"bis_key_0_crypt", {S128KeyType::BIS, 0, static_cast<u64>(BISKeyType::Crypto)}},
|
||||
{"bis_key_0_tweak", {S128KeyType::BIS, 0, static_cast<u64>(BISKeyType::Tweak)}},
|
||||
{"bis_key_1_crypt", {S128KeyType::BIS, 1, static_cast<u64>(BISKeyType::Crypto)}},
|
||||
{"bis_key_1_tweak", {S128KeyType::BIS, 1, static_cast<u64>(BISKeyType::Tweak)}},
|
||||
{"bis_key_2_crypt", {S128KeyType::BIS, 2, static_cast<u64>(BISKeyType::Crypto)}},
|
||||
{"bis_key_2_tweak", {S128KeyType::BIS, 2, static_cast<u64>(BISKeyType::Tweak)}},
|
||||
{"bis_key_3_crypt", {S128KeyType::BIS, 3, static_cast<u64>(BISKeyType::Crypto)}},
|
||||
{"bis_key_3_tweak", {S128KeyType::BIS, 3, static_cast<u64>(BISKeyType::Tweak)}},
|
||||
{"header_kek", {S128KeyType::HeaderKek, 0, 0}},
|
||||
{"sd_card_kek", {S128KeyType::SDKek, 0, 0}},
|
||||
};
|
||||
|
||||
const boost::container::flat_map<std::string, KeyIndex<S256KeyType>> KeyManager::s256_file_id = {
|
||||
{"header_key", {S256KeyType::Header, 0, 0}},
|
||||
{"sd_card_save_key_source", {S256KeyType::SDKeySource, static_cast<u64>(SDKeyType::Save), 0}},
|
||||
{"sd_card_nca_key_source", {S256KeyType::SDKeySource, static_cast<u64>(SDKeyType::NCA), 0}},
|
||||
{"header_key_source", {S256KeyType::HeaderSource, 0, 0}},
|
||||
{"sd_card_save_key", {S256KeyType::SDKey, static_cast<u64>(SDKeyType::Save), 0}},
|
||||
{"sd_card_nca_key", {S256KeyType::SDKey, static_cast<u64>(SDKeyType::NCA), 0}},
|
||||
};
|
||||
} // namespace Core::Crypto
|
||||
|
||||
@@ -10,13 +10,14 @@
|
||||
#include <string>
|
||||
|
||||
#include <variant>
|
||||
#include <boost/container/flat_map.hpp>
|
||||
#include <fmt/format.h>
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "core/crypto/partition_data_manager.h"
|
||||
#include "core/file_sys/vfs_types.h"
|
||||
|
||||
namespace Common::FS {
|
||||
namespace FileUtil {
|
||||
class IOFile;
|
||||
}
|
||||
|
||||
@@ -292,6 +293,9 @@ private:
|
||||
|
||||
void SetKeyWrapped(S128KeyType id, Key128 key, u64 field1 = 0, u64 field2 = 0);
|
||||
void SetKeyWrapped(S256KeyType id, Key256 key, u64 field1 = 0, u64 field2 = 0);
|
||||
|
||||
static const boost::container::flat_map<std::string, KeyIndex<S128KeyType>> s128_file_id;
|
||||
static const boost::container::flat_map<std::string, KeyIndex<S256KeyType>> s256_file_id;
|
||||
};
|
||||
|
||||
Key128 GenerateKeyEncryptionKey(Key128 source, Key128 master, Key128 kek_seed, Key128 key_seed);
|
||||
@@ -304,7 +308,7 @@ std::array<u8, 0x90> DecryptKeyblob(const std::array<u8, 0xB0>& encrypted_keyblo
|
||||
std::optional<Key128> DeriveSDSeed();
|
||||
Loader::ResultStatus DeriveSDKeys(std::array<Key256, 2>& sd_keys, KeyManager& keys);
|
||||
|
||||
std::vector<Ticket> GetTicketblob(const Common::FS::IOFile& ticket_save);
|
||||
std::vector<Ticket> GetTicketblob(const FileUtil::IOFile& ticket_save);
|
||||
|
||||
// Returns a pair of {rights_id, titlekey}. Fails if the ticket has no certificate authority
|
||||
// (offset 0x140-0x144 is zero)
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
#include "core/file_sys/vfs_offset.h"
|
||||
#include "core/file_sys/vfs_vector.h"
|
||||
|
||||
using Common::AsArray;
|
||||
using namespace Common;
|
||||
|
||||
namespace Core::Crypto {
|
||||
|
||||
@@ -47,123 +47,105 @@ struct Package2Header {
|
||||
};
|
||||
static_assert(sizeof(Package2Header) == 0x200, "Package2Header has incorrect size.");
|
||||
|
||||
// clang-format off
|
||||
constexpr std::array source_hashes{
|
||||
AsArray("B24BD293259DBC7AC5D63F88E60C59792498E6FC5443402C7FFE87EE8B61A3F0"), // keyblob_mac_key_source
|
||||
AsArray("7944862A3A5C31C6720595EFD302245ABD1B54CCDCF33000557681E65C5664A4"), // master_key_source
|
||||
AsArray("21E2DF100FC9E094DB51B47B9B1D6E94ED379DB8B547955BEF8FE08D8DD35603"), // package2_key_source
|
||||
AsArray("FC02B9D37B42D7A1452E71444F1F700311D1132E301A83B16062E72A78175085"), // aes_kek_generation_source
|
||||
AsArray("FBD10056999EDC7ACDB96098E47E2C3606230270D23281E671F0F389FC5BC585"), // aes_key_generation_source
|
||||
AsArray("C48B619827986C7F4E3081D59DB2B460C84312650E9A8E6B458E53E8CBCA4E87"), // titlekek_source
|
||||
AsArray("04AD66143C726B2A139FB6B21128B46F56C553B2B3887110304298D8D0092D9E"), // key_area_key_application_source
|
||||
AsArray("FD434000C8FF2B26F8E9A9D2D2C12F6BE5773CBB9DC86300E1BD99F8EA33A417"), // key_area_key_ocean_source
|
||||
AsArray("1F17B1FD51AD1C2379B58F152CA4912EC2106441E51722F38700D5937A1162F7"), // key_area_key_system_source
|
||||
AsArray("6B2ED877C2C52334AC51E59ABFA7EC457F4A7D01E46291E9F2EAA45F011D24B7"), // sd_card_kek_source
|
||||
AsArray("D482743563D3EA5DCDC3B74E97C9AC8A342164FA041A1DC80F17F6D31E4BC01C"), // sd_card_save_key_source
|
||||
AsArray("2E751CECF7D93A2B957BD5FFCB082FD038CC2853219DD3092C6DAB9838F5A7CC"), // sd_card_nca_key_source
|
||||
AsArray("1888CAED5551B3EDE01499E87CE0D86827F80820EFB275921055AA4E2ABDFFC2"), // header_kek_source
|
||||
AsArray("8F783E46852DF6BE0BA4E19273C4ADBAEE16380043E1B8C418C4089A8BD64AA6"), // header_key_source
|
||||
AsArray("D1757E52F1AE55FA882EC690BC6F954AC46A83DC22F277F8806BD55577C6EED7"), // rsa_kek_seed3
|
||||
AsArray("FC02B9D37B42D7A1452E71444F1F700311D1132E301A83B16062E72A78175085"), // rsa_kek_mask0
|
||||
const std::array<SHA256Hash, 0x10> source_hashes{
|
||||
"B24BD293259DBC7AC5D63F88E60C59792498E6FC5443402C7FFE87EE8B61A3F0"_array32, // keyblob_mac_key_source
|
||||
"7944862A3A5C31C6720595EFD302245ABD1B54CCDCF33000557681E65C5664A4"_array32, // master_key_source
|
||||
"21E2DF100FC9E094DB51B47B9B1D6E94ED379DB8B547955BEF8FE08D8DD35603"_array32, // package2_key_source
|
||||
"FC02B9D37B42D7A1452E71444F1F700311D1132E301A83B16062E72A78175085"_array32, // aes_kek_generation_source
|
||||
"FBD10056999EDC7ACDB96098E47E2C3606230270D23281E671F0F389FC5BC585"_array32, // aes_key_generation_source
|
||||
"C48B619827986C7F4E3081D59DB2B460C84312650E9A8E6B458E53E8CBCA4E87"_array32, // titlekek_source
|
||||
"04AD66143C726B2A139FB6B21128B46F56C553B2B3887110304298D8D0092D9E"_array32, // key_area_key_application_source
|
||||
"FD434000C8FF2B26F8E9A9D2D2C12F6BE5773CBB9DC86300E1BD99F8EA33A417"_array32, // key_area_key_ocean_source
|
||||
"1F17B1FD51AD1C2379B58F152CA4912EC2106441E51722F38700D5937A1162F7"_array32, // key_area_key_system_source
|
||||
"6B2ED877C2C52334AC51E59ABFA7EC457F4A7D01E46291E9F2EAA45F011D24B7"_array32, // sd_card_kek_source
|
||||
"D482743563D3EA5DCDC3B74E97C9AC8A342164FA041A1DC80F17F6D31E4BC01C"_array32, // sd_card_save_key_source
|
||||
"2E751CECF7D93A2B957BD5FFCB082FD038CC2853219DD3092C6DAB9838F5A7CC"_array32, // sd_card_nca_key_source
|
||||
"1888CAED5551B3EDE01499E87CE0D86827F80820EFB275921055AA4E2ABDFFC2"_array32, // header_kek_source
|
||||
"8F783E46852DF6BE0BA4E19273C4ADBAEE16380043E1B8C418C4089A8BD64AA6"_array32, // header_key_source
|
||||
"D1757E52F1AE55FA882EC690BC6F954AC46A83DC22F277F8806BD55577C6EED7"_array32, // rsa_kek_seed3
|
||||
"FC02B9D37B42D7A1452E71444F1F700311D1132E301A83B16062E72A78175085"_array32, // rsa_kek_mask0
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
// clang-format off
|
||||
constexpr std::array keyblob_source_hashes{
|
||||
AsArray("8A06FE274AC491436791FDB388BCDD3AB9943BD4DEF8094418CDAC150FD73786"), // keyblob_key_source_00
|
||||
AsArray("2D5CAEB2521FEF70B47E17D6D0F11F8CE2C1E442A979AD8035832C4E9FBCCC4B"), // keyblob_key_source_01
|
||||
AsArray("61C5005E713BAE780641683AF43E5F5C0E03671117F702F401282847D2FC6064"), // keyblob_key_source_02
|
||||
AsArray("8E9795928E1C4428E1B78F0BE724D7294D6934689C11B190943923B9D5B85903"), // keyblob_key_source_03
|
||||
AsArray("95FA33AF95AFF9D9B61D164655B32710ED8D615D46C7D6CC3CC70481B686B402"), // keyblob_key_source_04
|
||||
AsArray("3F5BE7B3C8B1ABD8C10B4B703D44766BA08730562C172A4FE0D6B866B3E2DB3E"), // keyblob_key_source_05
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_06
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_07
|
||||
const std::array<SHA256Hash, 0x20> keyblob_source_hashes{
|
||||
"8A06FE274AC491436791FDB388BCDD3AB9943BD4DEF8094418CDAC150FD73786"_array32, // keyblob_key_source_00
|
||||
"2D5CAEB2521FEF70B47E17D6D0F11F8CE2C1E442A979AD8035832C4E9FBCCC4B"_array32, // keyblob_key_source_01
|
||||
"61C5005E713BAE780641683AF43E5F5C0E03671117F702F401282847D2FC6064"_array32, // keyblob_key_source_02
|
||||
"8E9795928E1C4428E1B78F0BE724D7294D6934689C11B190943923B9D5B85903"_array32, // keyblob_key_source_03
|
||||
"95FA33AF95AFF9D9B61D164655B32710ED8D615D46C7D6CC3CC70481B686B402"_array32, // keyblob_key_source_04
|
||||
"3F5BE7B3C8B1ABD8C10B4B703D44766BA08730562C172A4FE0D6B866B3E2DB3E"_array32, // keyblob_key_source_05
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_06
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_07
|
||||
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_08
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_09
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_0A
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_0B
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_0C
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_0D
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_0E
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_0F
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_08
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_09
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_0A
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_0B
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_0C
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_0D
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_0E
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_0F
|
||||
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_10
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_11
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_12
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_13
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_14
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_15
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_16
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_17
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_10
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_11
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_12
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_13
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_14
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_15
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_16
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_17
|
||||
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_18
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_19
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_1A
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_1B
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_1C
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_1D
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_1E
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_1F
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_18
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_19
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_1A
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_1B
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_1C
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_1D
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_1E
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_1F
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
// clang-format off
|
||||
constexpr std::array master_key_hashes{
|
||||
AsArray("0EE359BE3C864BB0782E1D70A718A0342C551EED28C369754F9C4F691BECF7CA"), // master_key_00
|
||||
AsArray("4FE707B7E4ABDAF727C894AAF13B1351BFE2AC90D875F73B2E20FA94B9CC661E"), // master_key_01
|
||||
AsArray("79277C0237A2252EC3DFAC1F7C359C2B3D121E9DB15BB9AB4C2B4408D2F3AE09"), // master_key_02
|
||||
AsArray("4F36C565D13325F65EE134073C6A578FFCB0008E02D69400836844EAB7432754"), // master_key_03
|
||||
AsArray("75FF1D95D26113550EE6FCC20ACB58E97EDEB3A2FF52543ED5AEC63BDCC3DA50"), // master_key_04
|
||||
AsArray("EBE2BCD6704673EC0F88A187BB2AD9F1CC82B718C389425941BDC194DC46B0DD"), // master_key_05
|
||||
AsArray("9497E6779F5D840F2BBA1DE4E95BA1D6F21EFC94717D5AE5CA37D7EC5BD37A19"), // master_key_06
|
||||
AsArray("4EC96B8CB01B8DCE382149443430B2B6EBCB2983348AFA04A25E53609DABEDF6"), // master_key_07
|
||||
const std::array<SHA256Hash, 0x20> master_key_hashes{
|
||||
"0EE359BE3C864BB0782E1D70A718A0342C551EED28C369754F9C4F691BECF7CA"_array32, // master_key_00
|
||||
"4FE707B7E4ABDAF727C894AAF13B1351BFE2AC90D875F73B2E20FA94B9CC661E"_array32, // master_key_01
|
||||
"79277C0237A2252EC3DFAC1F7C359C2B3D121E9DB15BB9AB4C2B4408D2F3AE09"_array32, // master_key_02
|
||||
"4F36C565D13325F65EE134073C6A578FFCB0008E02D69400836844EAB7432754"_array32, // master_key_03
|
||||
"75FF1D95D26113550EE6FCC20ACB58E97EDEB3A2FF52543ED5AEC63BDCC3DA50"_array32, // master_key_04
|
||||
"EBE2BCD6704673EC0F88A187BB2AD9F1CC82B718C389425941BDC194DC46B0DD"_array32, // master_key_05
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_06
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_07
|
||||
|
||||
AsArray("2998E2E23609BC2675FF062A2D64AF5B1B78DFF463B24119D64A1B64F01B2D51"), // master_key_08
|
||||
AsArray("9D486A98067C44B37CF173D3BF577891EB6081FF6B4A166347D9DBBF7025076B"), // master_key_09
|
||||
AsArray("4EC5A237A75A083A9C5F6CF615601522A7F822D06BD4BA32612C9CEBBB29BD45"), // master_key_0A
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_0B
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_0C
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_0D
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_0E
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_0F
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_08
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_09
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_0A
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_0B
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_0C
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_0D
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_0E
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_0F
|
||||
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_10
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_11
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_12
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_13
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_14
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_15
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_16
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_17
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_10
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_11
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_12
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_13
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_14
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_15
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_16
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_17
|
||||
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_18
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_19
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_1A
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_1B
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_1C
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_1D
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_1E
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_1F
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_18
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_19
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_1A
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_1B
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_1C
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_1D
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_1E
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_1F
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
static constexpr u8 CalculateMaxKeyblobSourceHash() {
|
||||
const auto is_zero = [](const auto& data) {
|
||||
// TODO: Replace with std::all_of whenever mingw decides to update their
|
||||
// libraries to include the constexpr variant of it.
|
||||
for (const auto element : data) {
|
||||
if (element != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
static u8 CalculateMaxKeyblobSourceHash() {
|
||||
for (s8 i = 0x1F; i >= 0; --i) {
|
||||
if (!is_zero(keyblob_source_hashes[i])) {
|
||||
if (keyblob_source_hashes[i] != SHA256Hash{})
|
||||
return static_cast<u8>(i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -364,11 +346,12 @@ FileSys::VirtualFile PartitionDataManager::GetPackage2Raw(Package2Type type) con
|
||||
}
|
||||
|
||||
static bool AttemptDecrypt(const std::array<u8, 16>& key, Package2Header& header) {
|
||||
const std::vector<u8> iv(header.header_ctr.begin(), header.header_ctr.end());
|
||||
Package2Header temp = header;
|
||||
AESCipher<Key128> cipher(key, Mode::CTR);
|
||||
cipher.SetIV(header.header_ctr);
|
||||
cipher.Transcode(&temp.header_ctr, sizeof(Package2Header) - sizeof(Package2Header::signature),
|
||||
&temp.header_ctr, Op::Decrypt);
|
||||
cipher.SetIV(iv);
|
||||
cipher.Transcode(&temp.header_ctr, sizeof(Package2Header) - 0x100, &temp.header_ctr,
|
||||
Op::Decrypt);
|
||||
if (temp.magic == Common::MakeMagic('P', 'K', '2', '1')) {
|
||||
header = temp;
|
||||
return true;
|
||||
@@ -405,7 +388,7 @@ void PartitionDataManager::DecryptPackage2(const std::array<Key128, 0x20>& packa
|
||||
auto c = a->ReadAllBytes();
|
||||
|
||||
AESCipher<Key128> cipher(package2_keys[revision], Mode::CTR);
|
||||
cipher.SetIV(header.section_ctr[1]);
|
||||
cipher.SetIV({header.section_ctr[1].begin(), header.section_ctr[1].end()});
|
||||
cipher.Transcode(c.data(), c.size(), c.data(), Op::Decrypt);
|
||||
|
||||
const auto ini_file = std::make_shared<FileSys::VectorVfsFile>(c);
|
||||
|
||||
@@ -2,11 +2,14 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "core/core.h"
|
||||
#include "core/device_memory.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
namespace Core {
|
||||
|
||||
DeviceMemory::DeviceMemory() : buffer{DramMemoryMap::Size} {}
|
||||
DeviceMemory::DeviceMemory(System& system) : buffer{DramMemoryMap::Size}, system{system} {}
|
||||
|
||||
DeviceMemory::~DeviceMemory() = default;
|
||||
|
||||
} // namespace Core
|
||||
|
||||
@@ -4,11 +4,14 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/virtual_buffer.h"
|
||||
|
||||
namespace Core {
|
||||
|
||||
class System;
|
||||
|
||||
namespace DramMemoryMap {
|
||||
enum : u64 {
|
||||
Base = 0x80000000ULL,
|
||||
@@ -23,7 +26,7 @@ enum : u64 {
|
||||
|
||||
class DeviceMemory : NonCopyable {
|
||||
public:
|
||||
explicit DeviceMemory();
|
||||
explicit DeviceMemory(Core::System& system);
|
||||
~DeviceMemory();
|
||||
|
||||
template <typename T>
|
||||
@@ -42,6 +45,7 @@ public:
|
||||
|
||||
private:
|
||||
Common::VirtualBuffer<u8> buffer;
|
||||
Core::System& system;
|
||||
};
|
||||
|
||||
} // namespace Core
|
||||
|
||||
@@ -86,7 +86,7 @@ VirtualFile BISFactory::OpenPartitionStorage(BisPartitionId id) const {
|
||||
auto& keys = Core::Crypto::KeyManager::Instance();
|
||||
Core::Crypto::PartitionDataManager pdm{
|
||||
Core::System::GetInstance().GetFilesystem()->OpenDirectory(
|
||||
Common::FS::GetUserPath(Common::FS::UserPath::SysDataDir), Mode::Read)};
|
||||
FileUtil::GetUserPath(FileUtil::UserPath::SysDataDir), Mode::Read)};
|
||||
keys.PopulateFromPartitionData(pdm);
|
||||
|
||||
switch (id) {
|
||||
|
||||
@@ -495,10 +495,9 @@ VirtualFile NCA::Decrypt(const NCASectionHeader& s_header, VirtualFile in, u64 s
|
||||
|
||||
auto out = std::make_shared<Core::Crypto::CTREncryptionLayer>(std::move(in), *key,
|
||||
starting_offset);
|
||||
Core::Crypto::CTREncryptionLayer::IVData iv{};
|
||||
for (std::size_t i = 0; i < 8; ++i) {
|
||||
iv[i] = s_header.raw.section_ctr[8 - i - 1];
|
||||
}
|
||||
std::vector<u8> iv(16);
|
||||
for (u8 i = 0; i < 8; ++i)
|
||||
iv[i] = s_header.raw.section_ctr[0x8 - i - 1];
|
||||
out->SetIV(iv);
|
||||
return std::static_pointer_cast<VfsFile>(out);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace FileSys {
|
||||
@@ -12,11 +11,13 @@ namespace FileSys {
|
||||
enum class Mode : u32 {
|
||||
Read = 1,
|
||||
Write = 2,
|
||||
ReadWrite = Read | Write,
|
||||
ReadWrite = 3,
|
||||
Append = 4,
|
||||
WriteAppend = Write | Append,
|
||||
WriteAppend = 6,
|
||||
};
|
||||
|
||||
DECLARE_ENUM_FLAG_OPERATORS(Mode)
|
||||
inline u32 operator&(Mode lhs, Mode rhs) {
|
||||
return static_cast<u32>(lhs) & static_cast<u32>(rhs);
|
||||
}
|
||||
|
||||
} // namespace FileSys
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
|
||||
@@ -67,7 +66,7 @@ std::size_t BKTR::Read(u8* data, std::size_t length, std::size_t offset) const {
|
||||
Core::Crypto::AESCipher<Core::Crypto::Key128> cipher(key, Core::Crypto::Mode::CTR);
|
||||
|
||||
// Calculate AES IV
|
||||
std::array<u8, 16> iv{};
|
||||
std::vector<u8> iv(16);
|
||||
auto subsection_ctr = subsection.ctr;
|
||||
auto offset_iv = section_offset + base_offset;
|
||||
for (std::size_t i = 0; i < section_ctr.size(); ++i)
|
||||
|
||||
@@ -288,8 +288,8 @@ std::optional<std::vector<Core::Memory::CheatEntry>> ReadCheatFileFromFolder(
|
||||
}
|
||||
|
||||
Core::Memory::TextCheatParser parser;
|
||||
return parser.Parse(system,
|
||||
std::string_view(reinterpret_cast<const char*>(data.data()), data.size()));
|
||||
return parser.Parse(
|
||||
system, std::string_view(reinterpret_cast<const char* const>(data.data()), data.size()));
|
||||
}
|
||||
|
||||
} // Anonymous namespace
|
||||
|
||||
@@ -344,18 +344,15 @@ VirtualFile RegisteredCache::GetFileAtID(NcaID id) const {
|
||||
|
||||
static std::optional<NcaID> CheckMapForContentRecord(const std::map<u64, CNMT>& map, u64 title_id,
|
||||
ContentRecordType type) {
|
||||
const auto cmnt_iter = map.find(title_id);
|
||||
if (cmnt_iter == map.cend()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
if (map.find(title_id) == map.end())
|
||||
return {};
|
||||
|
||||
const auto& cnmt = cmnt_iter->second;
|
||||
const auto& content_records = cnmt.GetContentRecords();
|
||||
const auto iter = std::find_if(content_records.cbegin(), content_records.cend(),
|
||||
const auto& cnmt = map.at(title_id);
|
||||
|
||||
const auto iter = std::find_if(cnmt.GetContentRecords().begin(), cnmt.GetContentRecords().end(),
|
||||
[type](const ContentRecord& rec) { return rec.type == type; });
|
||||
if (iter == content_records.cend()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
if (iter == cnmt.GetContentRecords().end())
|
||||
return {};
|
||||
|
||||
return std::make_optional(iter->nca_id);
|
||||
}
|
||||
@@ -470,16 +467,14 @@ VirtualFile RegisteredCache::GetEntryUnparsed(u64 title_id, ContentRecordType ty
|
||||
|
||||
std::optional<u32> RegisteredCache::GetEntryVersion(u64 title_id) const {
|
||||
const auto meta_iter = meta.find(title_id);
|
||||
if (meta_iter != meta.cend()) {
|
||||
if (meta_iter != meta.end())
|
||||
return meta_iter->second.GetTitleVersion();
|
||||
}
|
||||
|
||||
const auto yuzu_meta_iter = yuzu_meta.find(title_id);
|
||||
if (yuzu_meta_iter != yuzu_meta.cend()) {
|
||||
if (yuzu_meta_iter != yuzu_meta.end())
|
||||
return yuzu_meta_iter->second.GetTitleVersion();
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
return {};
|
||||
}
|
||||
|
||||
VirtualFile RegisteredCache::GetEntryRaw(u64 title_id, ContentRecordType type) const {
|
||||
@@ -552,6 +547,56 @@ InstallResult RegisteredCache::InstallEntry(const XCI& xci, bool overwrite_if_ex
|
||||
return InstallEntry(*xci.GetSecurePartitionNSP(), overwrite_if_exists, copy);
|
||||
}
|
||||
|
||||
bool RegisteredCache::RemoveExistingEntry(u64 title_id) {
|
||||
const auto delete_nca = [this](const NcaID& id) {
|
||||
const auto path = GetRelativePathFromNcaID(id, false, true, false);
|
||||
|
||||
if (dir->GetFileRelative(path) == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Core::Crypto::SHA256Hash hash{};
|
||||
mbedtls_sha256_ret(id.data(), id.size(), hash.data(), 0);
|
||||
const auto dirname = fmt::format("000000{:02X}", hash[0]);
|
||||
|
||||
const auto dir2 = GetOrCreateDirectoryRelative(dir, dirname);
|
||||
|
||||
const auto res = dir2->DeleteFile(fmt::format("{}.nca", Common::HexToString(id, false)));
|
||||
|
||||
return res;
|
||||
};
|
||||
|
||||
// If an entry exists in the registered cache, remove it
|
||||
if (HasEntry(title_id, ContentRecordType::Meta)) {
|
||||
LOG_INFO(Loader,
|
||||
"Previously installed entry (v{}) for title_id={:016X} detected! "
|
||||
"Attempting to remove...",
|
||||
GetEntryVersion(title_id).value_or(0), title_id);
|
||||
// Get all the ncas associated with the current CNMT and delete them
|
||||
const auto meta_old_id =
|
||||
GetNcaIDFromMetadata(title_id, ContentRecordType::Meta).value_or(NcaID{});
|
||||
const auto program_id =
|
||||
GetNcaIDFromMetadata(title_id, ContentRecordType::Program).value_or(NcaID{});
|
||||
const auto data_id =
|
||||
GetNcaIDFromMetadata(title_id, ContentRecordType::Data).value_or(NcaID{});
|
||||
const auto control_id =
|
||||
GetNcaIDFromMetadata(title_id, ContentRecordType::Control).value_or(NcaID{});
|
||||
const auto html_id =
|
||||
GetNcaIDFromMetadata(title_id, ContentRecordType::HtmlDocument).value_or(NcaID{});
|
||||
const auto legal_id =
|
||||
GetNcaIDFromMetadata(title_id, ContentRecordType::LegalInformation).value_or(NcaID{});
|
||||
|
||||
delete_nca(meta_old_id);
|
||||
delete_nca(program_id);
|
||||
delete_nca(data_id);
|
||||
delete_nca(control_id);
|
||||
delete_nca(html_id);
|
||||
delete_nca(legal_id);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
InstallResult RegisteredCache::InstallEntry(const NSP& nsp, bool overwrite_if_exists,
|
||||
const VfsCopyFunction& copy) {
|
||||
const auto ncas = nsp.GetNCAsCollapsed();
|
||||
@@ -647,57 +692,6 @@ InstallResult RegisteredCache::InstallEntry(const NCA& nca, TitleType type,
|
||||
return RawInstallNCA(nca, copy, overwrite_if_exists, c_rec.nca_id);
|
||||
}
|
||||
|
||||
bool RegisteredCache::RemoveExistingEntry(u64 title_id) const {
|
||||
const auto delete_nca = [this](const NcaID& id) {
|
||||
const auto path = GetRelativePathFromNcaID(id, false, true, false);
|
||||
|
||||
const bool isFile = dir->GetFileRelative(path) != nullptr;
|
||||
const bool isDir = dir->GetDirectoryRelative(path) != nullptr;
|
||||
|
||||
if (isFile) {
|
||||
return dir->DeleteFile(path);
|
||||
} else if (isDir) {
|
||||
return dir->DeleteSubdirectoryRecursive(path);
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
// If an entry exists in the registered cache, remove it
|
||||
if (HasEntry(title_id, ContentRecordType::Meta)) {
|
||||
LOG_INFO(Loader,
|
||||
"Previously installed entry (v{}) for title_id={:016X} detected! "
|
||||
"Attempting to remove...",
|
||||
GetEntryVersion(title_id).value_or(0), title_id);
|
||||
|
||||
// Get all the ncas associated with the current CNMT and delete them
|
||||
const auto meta_old_id =
|
||||
GetNcaIDFromMetadata(title_id, ContentRecordType::Meta).value_or(NcaID{});
|
||||
const auto program_id =
|
||||
GetNcaIDFromMetadata(title_id, ContentRecordType::Program).value_or(NcaID{});
|
||||
const auto data_id =
|
||||
GetNcaIDFromMetadata(title_id, ContentRecordType::Data).value_or(NcaID{});
|
||||
const auto control_id =
|
||||
GetNcaIDFromMetadata(title_id, ContentRecordType::Control).value_or(NcaID{});
|
||||
const auto html_id =
|
||||
GetNcaIDFromMetadata(title_id, ContentRecordType::HtmlDocument).value_or(NcaID{});
|
||||
const auto legal_id =
|
||||
GetNcaIDFromMetadata(title_id, ContentRecordType::LegalInformation).value_or(NcaID{});
|
||||
|
||||
const auto deleted_meta = delete_nca(meta_old_id);
|
||||
const auto deleted_program = delete_nca(program_id);
|
||||
const auto deleted_data = delete_nca(data_id);
|
||||
const auto deleted_control = delete_nca(control_id);
|
||||
const auto deleted_html = delete_nca(html_id);
|
||||
const auto deleted_legal = delete_nca(legal_id);
|
||||
|
||||
return deleted_meta && (deleted_meta || deleted_program || deleted_data ||
|
||||
deleted_control || deleted_html || deleted_legal);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
InstallResult RegisteredCache::RawInstallNCA(const NCA& nca, const VfsCopyFunction& copy,
|
||||
bool overwrite_if_exists,
|
||||
std::optional<NcaID> override_id) {
|
||||
@@ -728,7 +722,7 @@ InstallResult RegisteredCache::RawInstallNCA(const NCA& nca, const VfsCopyFuncti
|
||||
LOG_WARNING(Loader, "Overwriting existing NCA...");
|
||||
VirtualDir c_dir;
|
||||
{ c_dir = dir->GetFileRelative(path)->GetContainingDirectory(); }
|
||||
c_dir->DeleteFile(Common::FS::GetFilename(path));
|
||||
c_dir->DeleteFile(FileUtil::GetFilename(path));
|
||||
}
|
||||
|
||||
auto out = dir->CreateFileRelative(path);
|
||||
|
||||
@@ -133,9 +133,9 @@ public:
|
||||
// Parsing function defines the conversion from raw file to NCA. If there are other steps
|
||||
// besides creating the NCA from the file (e.g. NAX0 on SD Card), that should go in a custom
|
||||
// parsing function.
|
||||
explicit RegisteredCache(
|
||||
VirtualDir dir, ContentProviderParsingFunction parsing_function =
|
||||
[](const VirtualFile& file, const NcaID& id) { return file; });
|
||||
explicit RegisteredCache(VirtualDir dir,
|
||||
ContentProviderParsingFunction parsing_function =
|
||||
[](const VirtualFile& file, const NcaID& id) { return file; });
|
||||
~RegisteredCache() override;
|
||||
|
||||
void Refresh() override;
|
||||
@@ -155,6 +155,9 @@ public:
|
||||
std::optional<TitleType> title_type = {}, std::optional<ContentRecordType> record_type = {},
|
||||
std::optional<u64> title_id = {}) const override;
|
||||
|
||||
// Removes an existing entry based on title id
|
||||
bool RemoveExistingEntry(u64 title_id);
|
||||
|
||||
// Raw copies all the ncas from the xci/nsp to the csache. Does some quick checks to make sure
|
||||
// there is a meta NCA and all of them are accessible.
|
||||
InstallResult InstallEntry(const XCI& xci, bool overwrite_if_exists = false,
|
||||
@@ -169,9 +172,6 @@ public:
|
||||
InstallResult InstallEntry(const NCA& nca, TitleType type, bool overwrite_if_exists = false,
|
||||
const VfsCopyFunction& copy = &VfsRawCopy);
|
||||
|
||||
// Removes an existing entry based on title id
|
||||
bool RemoveExistingEntry(u64 title_id) const;
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
void IterateAllMetadata(std::vector<T>& out,
|
||||
|
||||
@@ -17,23 +17,23 @@ constexpr char SAVE_DATA_SIZE_FILENAME[] = ".yuzu_save_size";
|
||||
|
||||
namespace {
|
||||
|
||||
void PrintSaveDataAttributeWarnings(SaveDataAttribute meta) {
|
||||
void PrintSaveDataDescriptorWarnings(SaveDataDescriptor meta) {
|
||||
if (meta.type == SaveDataType::SystemSaveData || meta.type == SaveDataType::SaveData) {
|
||||
if (meta.zero_1 != 0) {
|
||||
LOG_WARNING(Service_FS,
|
||||
"Possibly incorrect SaveDataAttribute, type is "
|
||||
"Possibly incorrect SaveDataDescriptor, type is "
|
||||
"SystemSaveData||SaveData but offset 0x28 is non-zero ({:016X}).",
|
||||
meta.zero_1);
|
||||
}
|
||||
if (meta.zero_2 != 0) {
|
||||
LOG_WARNING(Service_FS,
|
||||
"Possibly incorrect SaveDataAttribute, type is "
|
||||
"Possibly incorrect SaveDataDescriptor, type is "
|
||||
"SystemSaveData||SaveData but offset 0x30 is non-zero ({:016X}).",
|
||||
meta.zero_2);
|
||||
}
|
||||
if (meta.zero_3 != 0) {
|
||||
LOG_WARNING(Service_FS,
|
||||
"Possibly incorrect SaveDataAttribute, type is "
|
||||
"Possibly incorrect SaveDataDescriptor, type is "
|
||||
"SystemSaveData||SaveData but offset 0x38 is non-zero ({:016X}).",
|
||||
meta.zero_3);
|
||||
}
|
||||
@@ -41,32 +41,33 @@ void PrintSaveDataAttributeWarnings(SaveDataAttribute meta) {
|
||||
|
||||
if (meta.type == SaveDataType::SystemSaveData && meta.title_id != 0) {
|
||||
LOG_WARNING(Service_FS,
|
||||
"Possibly incorrect SaveDataAttribute, type is SystemSaveData but title_id is "
|
||||
"Possibly incorrect SaveDataDescriptor, type is SystemSaveData but title_id is "
|
||||
"non-zero ({:016X}).",
|
||||
meta.title_id);
|
||||
}
|
||||
|
||||
if (meta.type == SaveDataType::DeviceSaveData && meta.user_id != u128{0, 0}) {
|
||||
LOG_WARNING(Service_FS,
|
||||
"Possibly incorrect SaveDataAttribute, type is DeviceSaveData but user_id is "
|
||||
"Possibly incorrect SaveDataDescriptor, type is DeviceSaveData but user_id is "
|
||||
"non-zero ({:016X}{:016X})",
|
||||
meta.user_id[1], meta.user_id[0]);
|
||||
}
|
||||
}
|
||||
|
||||
bool ShouldSaveDataBeAutomaticallyCreated(SaveDataSpaceId space, const SaveDataAttribute& attr) {
|
||||
return attr.type == SaveDataType::CacheStorage || attr.type == SaveDataType::TemporaryStorage ||
|
||||
bool ShouldSaveDataBeAutomaticallyCreated(SaveDataSpaceId space, const SaveDataDescriptor& desc) {
|
||||
return desc.type == SaveDataType::CacheStorage || desc.type == SaveDataType::TemporaryStorage ||
|
||||
(space == SaveDataSpaceId::NandUser && ///< Normal Save Data -- Current Title & User
|
||||
(attr.type == SaveDataType::SaveData || attr.type == SaveDataType::DeviceSaveData) &&
|
||||
attr.title_id == 0 && attr.save_id == 0);
|
||||
(desc.type == SaveDataType::SaveData || desc.type == SaveDataType::DeviceSaveData) &&
|
||||
desc.title_id == 0 && desc.save_id == 0);
|
||||
}
|
||||
|
||||
} // Anonymous namespace
|
||||
|
||||
std::string SaveDataAttribute::DebugInfo() const {
|
||||
return fmt::format("[title_id={:016X}, user_id={:016X}{:016X}, save_id={:016X}, type={:02X}, "
|
||||
std::string SaveDataDescriptor::DebugInfo() const {
|
||||
return fmt::format("[type={:02X}, title_id={:016X}, user_id={:016X}{:016X}, "
|
||||
"save_id={:016X}, "
|
||||
"rank={}, index={}]",
|
||||
title_id, user_id[1], user_id[0], save_id, static_cast<u8>(type),
|
||||
static_cast<u8>(type), title_id, user_id[1], user_id[0], save_id,
|
||||
static_cast<u8>(rank), index);
|
||||
}
|
||||
|
||||
@@ -79,8 +80,8 @@ SaveDataFactory::SaveDataFactory(VirtualDir save_directory) : dir(std::move(save
|
||||
SaveDataFactory::~SaveDataFactory() = default;
|
||||
|
||||
ResultVal<VirtualDir> SaveDataFactory::Create(SaveDataSpaceId space,
|
||||
const SaveDataAttribute& meta) const {
|
||||
PrintSaveDataAttributeWarnings(meta);
|
||||
const SaveDataDescriptor& meta) const {
|
||||
PrintSaveDataDescriptorWarnings(meta);
|
||||
|
||||
const auto save_directory =
|
||||
GetFullPath(space, meta.type, meta.title_id, meta.user_id, meta.save_id);
|
||||
@@ -97,7 +98,7 @@ ResultVal<VirtualDir> SaveDataFactory::Create(SaveDataSpaceId space,
|
||||
}
|
||||
|
||||
ResultVal<VirtualDir> SaveDataFactory::Open(SaveDataSpaceId space,
|
||||
const SaveDataAttribute& meta) const {
|
||||
const SaveDataDescriptor& meta) const {
|
||||
|
||||
const auto save_directory =
|
||||
GetFullPath(space, meta.type, meta.title_id, meta.user_id, meta.save_id);
|
||||
|
||||
@@ -21,7 +21,6 @@ enum class SaveDataSpaceId : u8 {
|
||||
TemporaryStorage = 3,
|
||||
SdCardUser = 4,
|
||||
ProperSystem = 100,
|
||||
SafeMode = 101,
|
||||
};
|
||||
|
||||
enum class SaveDataType : u8 {
|
||||
@@ -31,50 +30,28 @@ enum class SaveDataType : u8 {
|
||||
DeviceSaveData = 3,
|
||||
TemporaryStorage = 4,
|
||||
CacheStorage = 5,
|
||||
SystemBcat = 6,
|
||||
};
|
||||
|
||||
enum class SaveDataRank : u8 {
|
||||
Primary = 0,
|
||||
Secondary = 1,
|
||||
Primary,
|
||||
Secondary,
|
||||
};
|
||||
|
||||
enum class SaveDataFlags : u32 {
|
||||
None = (0 << 0),
|
||||
KeepAfterResettingSystemSaveData = (1 << 0),
|
||||
KeepAfterRefurbishment = (1 << 1),
|
||||
KeepAfterResettingSystemSaveDataWithoutUserSaveData = (1 << 2),
|
||||
NeedsSecureDelete = (1 << 3),
|
||||
};
|
||||
|
||||
struct SaveDataAttribute {
|
||||
u64 title_id;
|
||||
struct SaveDataDescriptor {
|
||||
u64_le title_id;
|
||||
u128 user_id;
|
||||
u64 save_id;
|
||||
u64_le save_id;
|
||||
SaveDataType type;
|
||||
SaveDataRank rank;
|
||||
u16 index;
|
||||
u16_le index;
|
||||
INSERT_PADDING_BYTES(4);
|
||||
u64 zero_1;
|
||||
u64 zero_2;
|
||||
u64 zero_3;
|
||||
u64_le zero_1;
|
||||
u64_le zero_2;
|
||||
u64_le zero_3;
|
||||
|
||||
std::string DebugInfo() const;
|
||||
};
|
||||
static_assert(sizeof(SaveDataAttribute) == 0x40, "SaveDataAttribute has incorrect size.");
|
||||
|
||||
struct SaveDataExtraData {
|
||||
SaveDataAttribute attr;
|
||||
u64 owner_id;
|
||||
s64 timestamp;
|
||||
SaveDataFlags flags;
|
||||
INSERT_PADDING_BYTES(4);
|
||||
s64 available_size;
|
||||
s64 journal_size;
|
||||
s64 commit_id;
|
||||
std::array<u8, 0x190> unused;
|
||||
};
|
||||
static_assert(sizeof(SaveDataExtraData) == 0x200, "SaveDataExtraData has incorrect size.");
|
||||
static_assert(sizeof(SaveDataDescriptor) == 0x40, "SaveDataDescriptor has incorrect size.");
|
||||
|
||||
struct SaveDataSize {
|
||||
u64 normal;
|
||||
@@ -87,8 +64,8 @@ public:
|
||||
explicit SaveDataFactory(VirtualDir dir);
|
||||
~SaveDataFactory();
|
||||
|
||||
ResultVal<VirtualDir> Create(SaveDataSpaceId space, const SaveDataAttribute& meta) const;
|
||||
ResultVal<VirtualDir> Open(SaveDataSpaceId space, const SaveDataAttribute& meta) const;
|
||||
ResultVal<VirtualDir> Create(SaveDataSpaceId space, const SaveDataDescriptor& meta) const;
|
||||
ResultVal<VirtualDir> Open(SaveDataSpaceId space, const SaveDataDescriptor& meta) const;
|
||||
|
||||
VirtualDir GetSaveDataSpaceDirectory(SaveDataSpaceId space) const;
|
||||
|
||||
|
||||
@@ -27,12 +27,18 @@ VirtualDir MiiModel() {
|
||||
auto out = std::make_shared<VectorVfsDirectory>(std::vector<VirtualFile>{},
|
||||
std::vector<VirtualDir>{}, "data");
|
||||
|
||||
out->AddFile(MakeArrayFile(MiiModelData::TEXTURE_LOW_LINEAR, "NXTextureLowLinear.dat"));
|
||||
out->AddFile(MakeArrayFile(MiiModelData::TEXTURE_LOW_SRGB, "NXTextureLowSRGB.dat"));
|
||||
out->AddFile(MakeArrayFile(MiiModelData::TEXTURE_MID_LINEAR, "NXTextureMidLinear.dat"));
|
||||
out->AddFile(MakeArrayFile(MiiModelData::TEXTURE_MID_SRGB, "NXTextureMidSRGB.dat"));
|
||||
out->AddFile(MakeArrayFile(MiiModelData::SHAPE_HIGH, "ShapeHigh.dat"));
|
||||
out->AddFile(MakeArrayFile(MiiModelData::SHAPE_MID, "ShapeMid.dat"));
|
||||
out->AddFile(std::make_shared<ArrayVfsFile<MiiModelData::TEXTURE_LOW_LINEAR.size()>>(
|
||||
MiiModelData::TEXTURE_LOW_LINEAR, "NXTextureLowLinear.dat"));
|
||||
out->AddFile(std::make_shared<ArrayVfsFile<MiiModelData::TEXTURE_LOW_SRGB.size()>>(
|
||||
MiiModelData::TEXTURE_LOW_SRGB, "NXTextureLowSRGB.dat"));
|
||||
out->AddFile(std::make_shared<ArrayVfsFile<MiiModelData::TEXTURE_MID_LINEAR.size()>>(
|
||||
MiiModelData::TEXTURE_MID_LINEAR, "NXTextureMidLinear.dat"));
|
||||
out->AddFile(std::make_shared<ArrayVfsFile<MiiModelData::TEXTURE_MID_SRGB.size()>>(
|
||||
MiiModelData::TEXTURE_MID_SRGB, "NXTextureMidSRGB.dat"));
|
||||
out->AddFile(std::make_shared<ArrayVfsFile<MiiModelData::SHAPE_HIGH.size()>>(
|
||||
MiiModelData::SHAPE_HIGH, "ShapeHigh.dat"));
|
||||
out->AddFile(std::make_shared<ArrayVfsFile<MiiModelData::SHAPE_MID.size()>>(
|
||||
MiiModelData::SHAPE_MID, "ShapeMid.dat"));
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -24,18 +24,19 @@ constexpr std::array<u8, 30> WORD_TXT{
|
||||
} // namespace NgWord1Data
|
||||
|
||||
VirtualDir NgWord1() {
|
||||
std::vector<VirtualFile> files;
|
||||
files.reserve(NgWord1Data::NUMBER_WORD_TXT_FILES);
|
||||
std::vector<VirtualFile> files(NgWord1Data::NUMBER_WORD_TXT_FILES);
|
||||
|
||||
for (std::size_t i = 0; i < files.size(); ++i) {
|
||||
files.push_back(MakeArrayFile(NgWord1Data::WORD_TXT, fmt::format("{}.txt", i)));
|
||||
files[i] = std::make_shared<ArrayVfsFile<NgWord1Data::WORD_TXT.size()>>(
|
||||
NgWord1Data::WORD_TXT, fmt::format("{}.txt", i));
|
||||
}
|
||||
|
||||
files.push_back(MakeArrayFile(NgWord1Data::WORD_TXT, "common.txt"));
|
||||
files.push_back(MakeArrayFile(NgWord1Data::VERSION_DAT, "version.dat"));
|
||||
files.push_back(std::make_shared<ArrayVfsFile<NgWord1Data::WORD_TXT.size()>>(
|
||||
NgWord1Data::WORD_TXT, "common.txt"));
|
||||
files.push_back(std::make_shared<ArrayVfsFile<NgWord1Data::VERSION_DAT.size()>>(
|
||||
NgWord1Data::VERSION_DAT, "version.dat"));
|
||||
|
||||
return std::make_shared<VectorVfsDirectory>(std::move(files), std::vector<VirtualDir>{},
|
||||
"data");
|
||||
return std::make_shared<VectorVfsDirectory>(files, std::vector<VirtualDir>{}, "data");
|
||||
}
|
||||
|
||||
namespace NgWord2Data {
|
||||
@@ -54,22 +55,27 @@ constexpr std::array<u8, 0x2C> AC_NX_DATA{
|
||||
} // namespace NgWord2Data
|
||||
|
||||
VirtualDir NgWord2() {
|
||||
std::vector<VirtualFile> files;
|
||||
files.reserve(NgWord2Data::NUMBER_AC_NX_FILES * 3);
|
||||
std::vector<VirtualFile> files(NgWord2Data::NUMBER_AC_NX_FILES * 3);
|
||||
|
||||
for (std::size_t i = 0; i < NgWord2Data::NUMBER_AC_NX_FILES; ++i) {
|
||||
files.push_back(MakeArrayFile(NgWord2Data::AC_NX_DATA, fmt::format("ac_{}_b1_nx", i)));
|
||||
files.push_back(MakeArrayFile(NgWord2Data::AC_NX_DATA, fmt::format("ac_{}_b2_nx", i)));
|
||||
files.push_back(MakeArrayFile(NgWord2Data::AC_NX_DATA, fmt::format("ac_{}_not_b_nx", i)));
|
||||
files[3 * i] = std::make_shared<ArrayVfsFile<NgWord2Data::AC_NX_DATA.size()>>(
|
||||
NgWord2Data::AC_NX_DATA, fmt::format("ac_{}_b1_nx", i));
|
||||
files[3 * i + 1] = std::make_shared<ArrayVfsFile<NgWord2Data::AC_NX_DATA.size()>>(
|
||||
NgWord2Data::AC_NX_DATA, fmt::format("ac_{}_b2_nx", i));
|
||||
files[3 * i + 2] = std::make_shared<ArrayVfsFile<NgWord2Data::AC_NX_DATA.size()>>(
|
||||
NgWord2Data::AC_NX_DATA, fmt::format("ac_{}_not_b_nx", i));
|
||||
}
|
||||
|
||||
files.push_back(MakeArrayFile(NgWord2Data::AC_NX_DATA, "ac_common_b1_nx"));
|
||||
files.push_back(MakeArrayFile(NgWord2Data::AC_NX_DATA, "ac_common_b2_nx"));
|
||||
files.push_back(MakeArrayFile(NgWord2Data::AC_NX_DATA, "ac_common_not_b_nx"));
|
||||
files.push_back(MakeArrayFile(NgWord2Data::VERSION_DAT, "version.dat"));
|
||||
files.push_back(std::make_shared<ArrayVfsFile<NgWord2Data::AC_NX_DATA.size()>>(
|
||||
NgWord2Data::AC_NX_DATA, "ac_common_b1_nx"));
|
||||
files.push_back(std::make_shared<ArrayVfsFile<NgWord2Data::AC_NX_DATA.size()>>(
|
||||
NgWord2Data::AC_NX_DATA, "ac_common_b2_nx"));
|
||||
files.push_back(std::make_shared<ArrayVfsFile<NgWord2Data::AC_NX_DATA.size()>>(
|
||||
NgWord2Data::AC_NX_DATA, "ac_common_not_b_nx"));
|
||||
files.push_back(std::make_shared<ArrayVfsFile<NgWord2Data::VERSION_DAT.size()>>(
|
||||
NgWord2Data::VERSION_DAT, "version.dat"));
|
||||
|
||||
return std::make_shared<VectorVfsDirectory>(std::move(files), std::vector<VirtualDir>{},
|
||||
"data");
|
||||
return std::make_shared<VectorVfsDirectory>(files, std::vector<VirtualDir>{}, "data");
|
||||
}
|
||||
|
||||
} // namespace FileSys::SystemArchive
|
||||
|
||||
@@ -2,9 +2,6 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <array>
|
||||
#include <vector>
|
||||
|
||||
#include "common/swap.h"
|
||||
#include "core/file_sys/system_archive/time_zone_binary.h"
|
||||
#include "core/file_sys/vfs_vector.h"
|
||||
@@ -618,49 +615,43 @@ static constexpr std::array<u8, 9633> LOCATION_NAMES{
|
||||
0x0a};
|
||||
|
||||
static VirtualFile GenerateDefaultTimeZoneFile() {
|
||||
struct TimeZoneInfo {
|
||||
struct {
|
||||
s64_be at;
|
||||
std::array<u8, 7> padding1;
|
||||
INSERT_PADDING_BYTES(7);
|
||||
std::array<char, 4> time_zone_chars;
|
||||
std::array<u8, 2> padding2;
|
||||
INSERT_PADDING_BYTES(2);
|
||||
std::array<char, 6> time_zone_name;
|
||||
};
|
||||
} time_zone_info{};
|
||||
|
||||
VirtualFile file{std::make_shared<VectorVfsFile>(
|
||||
std::vector<u8>(sizeof(Service::Time::TimeZone::TzifHeader) + sizeof(TimeZoneInfo)),
|
||||
const VirtualFile file{std::make_shared<VectorVfsFile>(
|
||||
std::vector<u8>(sizeof(Service::Time::TimeZone::TzifHeader) + sizeof(time_zone_info)),
|
||||
"GMT")};
|
||||
|
||||
const Service::Time::TimeZone::TzifHeader header{
|
||||
.magic = 0x545a6966,
|
||||
.version = 0x32,
|
||||
.ttis_gmt_count = 1,
|
||||
.ttis_std_count = 1,
|
||||
.time_count = 1,
|
||||
.type_count = 1,
|
||||
.char_count = 4,
|
||||
};
|
||||
Service::Time::TimeZone::TzifHeader header{};
|
||||
header.magic = 0x545a6966;
|
||||
header.version = 0x32;
|
||||
header.ttis_gmt_count = 0x1;
|
||||
header.ttis_std_count = 0x1;
|
||||
header.time_count = 0x1;
|
||||
header.type_count = 0x1;
|
||||
header.char_count = 0x4;
|
||||
file->WriteObject(header, 0);
|
||||
|
||||
const TimeZoneInfo time_zone_info{
|
||||
.at = 0xf8,
|
||||
.padding1 = {},
|
||||
.time_zone_chars = {'G', 'M', 'T', '\0'},
|
||||
.padding2 = {},
|
||||
.time_zone_name = {'\n', 'G', 'M', 'T', '0', '\n'},
|
||||
};
|
||||
time_zone_info.at = 0xf8;
|
||||
time_zone_info.time_zone_chars = {'G', 'M', 'T', '\0'};
|
||||
time_zone_info.time_zone_name = {'\n', 'G', 'M', 'T', '0', '\n'};
|
||||
file->WriteObject(time_zone_info, sizeof(Service::Time::TimeZone::TzifHeader));
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
VirtualDir TimeZoneBinary() {
|
||||
std::vector<VirtualDir> root_dirs{std::make_shared<VectorVfsDirectory>(
|
||||
const std::vector<VirtualDir> root_dirs{std::make_shared<VectorVfsDirectory>(
|
||||
std::vector<VirtualFile>{GenerateDefaultTimeZoneFile()}, std::vector<VirtualDir>{},
|
||||
"zoneinfo")};
|
||||
std::vector<VirtualFile> root_files{MakeArrayFile(LOCATION_NAMES, "binaryList.txt")};
|
||||
|
||||
return std::make_shared<VectorVfsDirectory>(std::move(root_files), std::move(root_dirs),
|
||||
"data");
|
||||
const std::vector<VirtualFile> root_files{
|
||||
std::make_shared<ArrayVfsFile<LOCATION_NAMES.size()>>(LOCATION_NAMES, "binaryList.txt")};
|
||||
return std::make_shared<VectorVfsDirectory>(root_files, root_dirs, "data");
|
||||
}
|
||||
|
||||
} // namespace FileSys::SystemArchive
|
||||
|
||||
@@ -30,7 +30,7 @@ bool VfsFilesystem::IsWritable() const {
|
||||
}
|
||||
|
||||
VfsEntryType VfsFilesystem::GetEntryType(std::string_view path_) const {
|
||||
const auto path = Common::FS::SanitizePath(path_);
|
||||
const auto path = FileUtil::SanitizePath(path_);
|
||||
if (root->GetFileRelative(path) != nullptr)
|
||||
return VfsEntryType::File;
|
||||
if (root->GetDirectoryRelative(path) != nullptr)
|
||||
@@ -40,22 +40,22 @@ VfsEntryType VfsFilesystem::GetEntryType(std::string_view path_) const {
|
||||
}
|
||||
|
||||
VirtualFile VfsFilesystem::OpenFile(std::string_view path_, Mode perms) {
|
||||
const auto path = Common::FS::SanitizePath(path_);
|
||||
const auto path = FileUtil::SanitizePath(path_);
|
||||
return root->GetFileRelative(path);
|
||||
}
|
||||
|
||||
VirtualFile VfsFilesystem::CreateFile(std::string_view path_, Mode perms) {
|
||||
const auto path = Common::FS::SanitizePath(path_);
|
||||
const auto path = FileUtil::SanitizePath(path_);
|
||||
return root->CreateFileRelative(path);
|
||||
}
|
||||
|
||||
VirtualFile VfsFilesystem::CopyFile(std::string_view old_path_, std::string_view new_path_) {
|
||||
const auto old_path = Common::FS::SanitizePath(old_path_);
|
||||
const auto new_path = Common::FS::SanitizePath(new_path_);
|
||||
const auto old_path = FileUtil::SanitizePath(old_path_);
|
||||
const auto new_path = FileUtil::SanitizePath(new_path_);
|
||||
|
||||
// VfsDirectory impls are only required to implement copy across the current directory.
|
||||
if (Common::FS::GetParentPath(old_path) == Common::FS::GetParentPath(new_path)) {
|
||||
if (!root->Copy(Common::FS::GetFilename(old_path), Common::FS::GetFilename(new_path)))
|
||||
if (FileUtil::GetParentPath(old_path) == FileUtil::GetParentPath(new_path)) {
|
||||
if (!root->Copy(FileUtil::GetFilename(old_path), FileUtil::GetFilename(new_path)))
|
||||
return nullptr;
|
||||
return OpenFile(new_path, Mode::ReadWrite);
|
||||
}
|
||||
@@ -76,8 +76,8 @@ VirtualFile VfsFilesystem::CopyFile(std::string_view old_path_, std::string_view
|
||||
}
|
||||
|
||||
VirtualFile VfsFilesystem::MoveFile(std::string_view old_path, std::string_view new_path) {
|
||||
const auto sanitized_old_path = Common::FS::SanitizePath(old_path);
|
||||
const auto sanitized_new_path = Common::FS::SanitizePath(new_path);
|
||||
const auto sanitized_old_path = FileUtil::SanitizePath(old_path);
|
||||
const auto sanitized_new_path = FileUtil::SanitizePath(new_path);
|
||||
|
||||
// Again, non-default impls are highly encouraged to provide a more optimized version of this.
|
||||
auto out = CopyFile(sanitized_old_path, sanitized_new_path);
|
||||
@@ -89,26 +89,26 @@ VirtualFile VfsFilesystem::MoveFile(std::string_view old_path, std::string_view
|
||||
}
|
||||
|
||||
bool VfsFilesystem::DeleteFile(std::string_view path_) {
|
||||
const auto path = Common::FS::SanitizePath(path_);
|
||||
auto parent = OpenDirectory(Common::FS::GetParentPath(path), Mode::Write);
|
||||
const auto path = FileUtil::SanitizePath(path_);
|
||||
auto parent = OpenDirectory(FileUtil::GetParentPath(path), Mode::Write);
|
||||
if (parent == nullptr)
|
||||
return false;
|
||||
return parent->DeleteFile(Common::FS::GetFilename(path));
|
||||
return parent->DeleteFile(FileUtil::GetFilename(path));
|
||||
}
|
||||
|
||||
VirtualDir VfsFilesystem::OpenDirectory(std::string_view path_, Mode perms) {
|
||||
const auto path = Common::FS::SanitizePath(path_);
|
||||
const auto path = FileUtil::SanitizePath(path_);
|
||||
return root->GetDirectoryRelative(path);
|
||||
}
|
||||
|
||||
VirtualDir VfsFilesystem::CreateDirectory(std::string_view path_, Mode perms) {
|
||||
const auto path = Common::FS::SanitizePath(path_);
|
||||
const auto path = FileUtil::SanitizePath(path_);
|
||||
return root->CreateDirectoryRelative(path);
|
||||
}
|
||||
|
||||
VirtualDir VfsFilesystem::CopyDirectory(std::string_view old_path_, std::string_view new_path_) {
|
||||
const auto old_path = Common::FS::SanitizePath(old_path_);
|
||||
const auto new_path = Common::FS::SanitizePath(new_path_);
|
||||
const auto old_path = FileUtil::SanitizePath(old_path_);
|
||||
const auto new_path = FileUtil::SanitizePath(new_path_);
|
||||
|
||||
// Non-default impls are highly encouraged to provide a more optimized version of this.
|
||||
auto old_dir = OpenDirectory(old_path, Mode::Read);
|
||||
@@ -139,8 +139,8 @@ VirtualDir VfsFilesystem::CopyDirectory(std::string_view old_path_, std::string_
|
||||
}
|
||||
|
||||
VirtualDir VfsFilesystem::MoveDirectory(std::string_view old_path, std::string_view new_path) {
|
||||
const auto sanitized_old_path = Common::FS::SanitizePath(old_path);
|
||||
const auto sanitized_new_path = Common::FS::SanitizePath(new_path);
|
||||
const auto sanitized_old_path = FileUtil::SanitizePath(old_path);
|
||||
const auto sanitized_new_path = FileUtil::SanitizePath(new_path);
|
||||
|
||||
// Non-default impls are highly encouraged to provide a more optimized version of this.
|
||||
auto out = CopyDirectory(sanitized_old_path, sanitized_new_path);
|
||||
@@ -152,17 +152,17 @@ VirtualDir VfsFilesystem::MoveDirectory(std::string_view old_path, std::string_v
|
||||
}
|
||||
|
||||
bool VfsFilesystem::DeleteDirectory(std::string_view path_) {
|
||||
const auto path = Common::FS::SanitizePath(path_);
|
||||
auto parent = OpenDirectory(Common::FS::GetParentPath(path), Mode::Write);
|
||||
const auto path = FileUtil::SanitizePath(path_);
|
||||
auto parent = OpenDirectory(FileUtil::GetParentPath(path), Mode::Write);
|
||||
if (parent == nullptr)
|
||||
return false;
|
||||
return parent->DeleteSubdirectoryRecursive(Common::FS::GetFilename(path));
|
||||
return parent->DeleteSubdirectoryRecursive(FileUtil::GetFilename(path));
|
||||
}
|
||||
|
||||
VfsFile::~VfsFile() = default;
|
||||
|
||||
std::string VfsFile::GetExtension() const {
|
||||
return std::string(Common::FS::GetExtensionFromFilename(GetName()));
|
||||
return std::string(FileUtil::GetExtensionFromFilename(GetName()));
|
||||
}
|
||||
|
||||
VfsDirectory::~VfsDirectory() = default;
|
||||
@@ -203,7 +203,7 @@ std::string VfsFile::GetFullPath() const {
|
||||
}
|
||||
|
||||
std::shared_ptr<VfsFile> VfsDirectory::GetFileRelative(std::string_view path) const {
|
||||
auto vec = Common::FS::SplitPathComponents(path);
|
||||
auto vec = FileUtil::SplitPathComponents(path);
|
||||
vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }),
|
||||
vec.end());
|
||||
if (vec.empty()) {
|
||||
@@ -239,7 +239,7 @@ std::shared_ptr<VfsFile> VfsDirectory::GetFileAbsolute(std::string_view path) co
|
||||
}
|
||||
|
||||
std::shared_ptr<VfsDirectory> VfsDirectory::GetDirectoryRelative(std::string_view path) const {
|
||||
auto vec = Common::FS::SplitPathComponents(path);
|
||||
auto vec = FileUtil::SplitPathComponents(path);
|
||||
vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }),
|
||||
vec.end());
|
||||
if (vec.empty()) {
|
||||
@@ -301,7 +301,7 @@ std::size_t VfsDirectory::GetSize() const {
|
||||
}
|
||||
|
||||
std::shared_ptr<VfsFile> VfsDirectory::CreateFileRelative(std::string_view path) {
|
||||
auto vec = Common::FS::SplitPathComponents(path);
|
||||
auto vec = FileUtil::SplitPathComponents(path);
|
||||
vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }),
|
||||
vec.end());
|
||||
if (vec.empty()) {
|
||||
@@ -320,7 +320,7 @@ std::shared_ptr<VfsFile> VfsDirectory::CreateFileRelative(std::string_view path)
|
||||
}
|
||||
}
|
||||
|
||||
return dir->CreateFileRelative(Common::FS::GetPathWithoutTop(path));
|
||||
return dir->CreateFileRelative(FileUtil::GetPathWithoutTop(path));
|
||||
}
|
||||
|
||||
std::shared_ptr<VfsFile> VfsDirectory::CreateFileAbsolute(std::string_view path) {
|
||||
@@ -332,7 +332,7 @@ std::shared_ptr<VfsFile> VfsDirectory::CreateFileAbsolute(std::string_view path)
|
||||
}
|
||||
|
||||
std::shared_ptr<VfsDirectory> VfsDirectory::CreateDirectoryRelative(std::string_view path) {
|
||||
auto vec = Common::FS::SplitPathComponents(path);
|
||||
auto vec = FileUtil::SplitPathComponents(path);
|
||||
vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }),
|
||||
vec.end());
|
||||
if (vec.empty()) {
|
||||
@@ -351,7 +351,7 @@ std::shared_ptr<VfsDirectory> VfsDirectory::CreateDirectoryRelative(std::string_
|
||||
}
|
||||
}
|
||||
|
||||
return dir->CreateDirectoryRelative(Common::FS::GetPathWithoutTop(path));
|
||||
return dir->CreateDirectoryRelative(FileUtil::GetPathWithoutTop(path));
|
||||
}
|
||||
|
||||
std::shared_ptr<VfsDirectory> VfsDirectory::CreateDirectoryAbsolute(std::string_view path) {
|
||||
|
||||
@@ -49,7 +49,7 @@ VirtualDir ExtractZIP(VirtualFile file) {
|
||||
if (zip_fread(file2.get(), buf.data(), buf.size()) != s64(buf.size()))
|
||||
return nullptr;
|
||||
|
||||
const auto parts = Common::FS::SplitPathComponents(stat.name);
|
||||
const auto parts = FileUtil::SplitPathComponents(stat.name);
|
||||
const auto new_file = std::make_shared<VectorVfsFile>(buf, parts.back());
|
||||
|
||||
std::shared_ptr<VectorVfsDirectory> dtrv = out;
|
||||
|
||||
@@ -14,28 +14,24 @@
|
||||
|
||||
namespace FileSys {
|
||||
|
||||
namespace FS = Common::FS;
|
||||
|
||||
static std::string ModeFlagsToString(Mode mode) {
|
||||
std::string mode_str;
|
||||
|
||||
// Calculate the correct open mode for the file.
|
||||
if (True(mode & Mode::Read) && True(mode & Mode::Write)) {
|
||||
if (True(mode & Mode::Append)) {
|
||||
if (mode & Mode::Read && mode & Mode::Write) {
|
||||
if (mode & Mode::Append)
|
||||
mode_str = "a+";
|
||||
} else {
|
||||
else
|
||||
mode_str = "r+";
|
||||
}
|
||||
} else {
|
||||
if (True(mode & Mode::Read)) {
|
||||
if (mode & Mode::Read)
|
||||
mode_str = "r";
|
||||
} else if (True(mode & Mode::Append)) {
|
||||
else if (mode & Mode::Append)
|
||||
mode_str = "a";
|
||||
} else if (True(mode & Mode::Write)) {
|
||||
else if (mode & Mode::Write)
|
||||
mode_str = "w";
|
||||
} else {
|
||||
else
|
||||
UNREACHABLE_MSG("Invalid file open mode: {:02X}", static_cast<u8>(mode));
|
||||
}
|
||||
}
|
||||
|
||||
mode_str += "b";
|
||||
@@ -59,82 +55,78 @@ bool RealVfsFilesystem::IsWritable() const {
|
||||
}
|
||||
|
||||
VfsEntryType RealVfsFilesystem::GetEntryType(std::string_view path_) const {
|
||||
const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault);
|
||||
if (!FS::Exists(path)) {
|
||||
const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault);
|
||||
if (!FileUtil::Exists(path))
|
||||
return VfsEntryType::None;
|
||||
}
|
||||
if (FS::IsDirectory(path)) {
|
||||
if (FileUtil::IsDirectory(path))
|
||||
return VfsEntryType::Directory;
|
||||
}
|
||||
|
||||
return VfsEntryType::File;
|
||||
}
|
||||
|
||||
VirtualFile RealVfsFilesystem::OpenFile(std::string_view path_, Mode perms) {
|
||||
const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault);
|
||||
|
||||
if (const auto weak_iter = cache.find(path); weak_iter != cache.cend()) {
|
||||
const auto& weak = weak_iter->second;
|
||||
|
||||
const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault);
|
||||
if (cache.find(path) != cache.end()) {
|
||||
auto weak = cache[path];
|
||||
if (!weak.expired()) {
|
||||
return std::shared_ptr<RealVfsFile>(new RealVfsFile(*this, weak.lock(), path, perms));
|
||||
}
|
||||
}
|
||||
|
||||
if (!FS::Exists(path) && True(perms & Mode::WriteAppend)) {
|
||||
FS::CreateEmptyFile(path);
|
||||
}
|
||||
if (!FileUtil::Exists(path) && (perms & Mode::WriteAppend) != 0)
|
||||
FileUtil::CreateEmptyFile(path);
|
||||
|
||||
auto backing = std::make_shared<FS::IOFile>(path, ModeFlagsToString(perms).c_str());
|
||||
cache.insert_or_assign(path, backing);
|
||||
auto backing = std::make_shared<FileUtil::IOFile>(path, ModeFlagsToString(perms).c_str());
|
||||
cache[path] = backing;
|
||||
|
||||
// Cannot use make_shared as RealVfsFile constructor is private
|
||||
return std::shared_ptr<RealVfsFile>(new RealVfsFile(*this, backing, path, perms));
|
||||
}
|
||||
|
||||
VirtualFile RealVfsFilesystem::CreateFile(std::string_view path_, Mode perms) {
|
||||
const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault);
|
||||
const auto path_fwd = FS::SanitizePath(path, FS::DirectorySeparator::ForwardSlash);
|
||||
if (!FS::Exists(path)) {
|
||||
FS::CreateFullPath(path_fwd);
|
||||
if (!FS::CreateEmptyFile(path)) {
|
||||
const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault);
|
||||
const auto path_fwd = FileUtil::SanitizePath(path, FileUtil::DirectorySeparator::ForwardSlash);
|
||||
if (!FileUtil::Exists(path)) {
|
||||
FileUtil::CreateFullPath(path_fwd);
|
||||
if (!FileUtil::CreateEmptyFile(path))
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
return OpenFile(path, perms);
|
||||
}
|
||||
|
||||
VirtualFile RealVfsFilesystem::CopyFile(std::string_view old_path_, std::string_view new_path_) {
|
||||
const auto old_path = FS::SanitizePath(old_path_, FS::DirectorySeparator::PlatformDefault);
|
||||
const auto new_path = FS::SanitizePath(new_path_, FS::DirectorySeparator::PlatformDefault);
|
||||
const auto old_path =
|
||||
FileUtil::SanitizePath(old_path_, FileUtil::DirectorySeparator::PlatformDefault);
|
||||
const auto new_path =
|
||||
FileUtil::SanitizePath(new_path_, FileUtil::DirectorySeparator::PlatformDefault);
|
||||
|
||||
if (!FS::Exists(old_path) || FS::Exists(new_path) || FS::IsDirectory(old_path) ||
|
||||
!FS::Copy(old_path, new_path)) {
|
||||
if (!FileUtil::Exists(old_path) || FileUtil::Exists(new_path) ||
|
||||
FileUtil::IsDirectory(old_path) || !FileUtil::Copy(old_path, new_path))
|
||||
return nullptr;
|
||||
}
|
||||
return OpenFile(new_path, Mode::ReadWrite);
|
||||
}
|
||||
|
||||
VirtualFile RealVfsFilesystem::MoveFile(std::string_view old_path_, std::string_view new_path_) {
|
||||
const auto old_path = FS::SanitizePath(old_path_, FS::DirectorySeparator::PlatformDefault);
|
||||
const auto new_path = FS::SanitizePath(new_path_, FS::DirectorySeparator::PlatformDefault);
|
||||
const auto cached_file_iter = cache.find(old_path);
|
||||
const auto old_path =
|
||||
FileUtil::SanitizePath(old_path_, FileUtil::DirectorySeparator::PlatformDefault);
|
||||
const auto new_path =
|
||||
FileUtil::SanitizePath(new_path_, FileUtil::DirectorySeparator::PlatformDefault);
|
||||
|
||||
if (cached_file_iter != cache.cend()) {
|
||||
auto file = cached_file_iter->second.lock();
|
||||
if (cache.find(old_path) != cache.end()) {
|
||||
auto file = cache[old_path].lock();
|
||||
|
||||
if (!cached_file_iter->second.expired()) {
|
||||
if (!cache[old_path].expired()) {
|
||||
file->Close();
|
||||
}
|
||||
|
||||
if (!FS::Exists(old_path) || FS::Exists(new_path) || FS::IsDirectory(old_path) ||
|
||||
!FS::Rename(old_path, new_path)) {
|
||||
if (!FileUtil::Exists(old_path) || FileUtil::Exists(new_path) ||
|
||||
FileUtil::IsDirectory(old_path) || !FileUtil::Rename(old_path, new_path)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
cache.erase(old_path);
|
||||
file->Open(new_path, "r+b");
|
||||
cache.insert_or_assign(new_path, std::move(file));
|
||||
cache[new_path] = file;
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
return nullptr;
|
||||
@@ -144,33 +136,28 @@ VirtualFile RealVfsFilesystem::MoveFile(std::string_view old_path_, std::string_
|
||||
}
|
||||
|
||||
bool RealVfsFilesystem::DeleteFile(std::string_view path_) {
|
||||
const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault);
|
||||
const auto cached_iter = cache.find(path);
|
||||
|
||||
if (cached_iter != cache.cend()) {
|
||||
if (!cached_iter->second.expired()) {
|
||||
cached_iter->second.lock()->Close();
|
||||
}
|
||||
const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault);
|
||||
if (cache.find(path) != cache.end()) {
|
||||
if (!cache[path].expired())
|
||||
cache[path].lock()->Close();
|
||||
cache.erase(path);
|
||||
}
|
||||
|
||||
return FS::Delete(path);
|
||||
return FileUtil::Delete(path);
|
||||
}
|
||||
|
||||
VirtualDir RealVfsFilesystem::OpenDirectory(std::string_view path_, Mode perms) {
|
||||
const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault);
|
||||
const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault);
|
||||
// Cannot use make_shared as RealVfsDirectory constructor is private
|
||||
return std::shared_ptr<RealVfsDirectory>(new RealVfsDirectory(*this, path, perms));
|
||||
}
|
||||
|
||||
VirtualDir RealVfsFilesystem::CreateDirectory(std::string_view path_, Mode perms) {
|
||||
const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault);
|
||||
const auto path_fwd = FS::SanitizePath(path, FS::DirectorySeparator::ForwardSlash);
|
||||
if (!FS::Exists(path)) {
|
||||
FS::CreateFullPath(path_fwd);
|
||||
if (!FS::CreateDir(path)) {
|
||||
const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault);
|
||||
const auto path_fwd = FileUtil::SanitizePath(path, FileUtil::DirectorySeparator::ForwardSlash);
|
||||
if (!FileUtil::Exists(path)) {
|
||||
FileUtil::CreateFullPath(path_fwd);
|
||||
if (!FileUtil::CreateDir(path))
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
// Cannot use make_shared as RealVfsDirectory constructor is private
|
||||
return std::shared_ptr<RealVfsDirectory>(new RealVfsDirectory(*this, path, perms));
|
||||
@@ -178,75 +165,67 @@ VirtualDir RealVfsFilesystem::CreateDirectory(std::string_view path_, Mode perms
|
||||
|
||||
VirtualDir RealVfsFilesystem::CopyDirectory(std::string_view old_path_,
|
||||
std::string_view new_path_) {
|
||||
const auto old_path = FS::SanitizePath(old_path_, FS::DirectorySeparator::PlatformDefault);
|
||||
const auto new_path = FS::SanitizePath(new_path_, FS::DirectorySeparator::PlatformDefault);
|
||||
if (!FS::Exists(old_path) || FS::Exists(new_path) || !FS::IsDirectory(old_path)) {
|
||||
const auto old_path =
|
||||
FileUtil::SanitizePath(old_path_, FileUtil::DirectorySeparator::PlatformDefault);
|
||||
const auto new_path =
|
||||
FileUtil::SanitizePath(new_path_, FileUtil::DirectorySeparator::PlatformDefault);
|
||||
if (!FileUtil::Exists(old_path) || FileUtil::Exists(new_path) ||
|
||||
!FileUtil::IsDirectory(old_path))
|
||||
return nullptr;
|
||||
}
|
||||
FS::CopyDir(old_path, new_path);
|
||||
FileUtil::CopyDir(old_path, new_path);
|
||||
return OpenDirectory(new_path, Mode::ReadWrite);
|
||||
}
|
||||
|
||||
VirtualDir RealVfsFilesystem::MoveDirectory(std::string_view old_path_,
|
||||
std::string_view new_path_) {
|
||||
const auto old_path = FS::SanitizePath(old_path_, FS::DirectorySeparator::PlatformDefault);
|
||||
const auto new_path = FS::SanitizePath(new_path_, FS::DirectorySeparator::PlatformDefault);
|
||||
|
||||
if (!FS::Exists(old_path) || FS::Exists(new_path) || FS::IsDirectory(old_path) ||
|
||||
!FS::Rename(old_path, new_path)) {
|
||||
const auto old_path =
|
||||
FileUtil::SanitizePath(old_path_, FileUtil::DirectorySeparator::PlatformDefault);
|
||||
const auto new_path =
|
||||
FileUtil::SanitizePath(new_path_, FileUtil::DirectorySeparator::PlatformDefault);
|
||||
if (!FileUtil::Exists(old_path) || FileUtil::Exists(new_path) ||
|
||||
FileUtil::IsDirectory(old_path) || !FileUtil::Rename(old_path, new_path))
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
for (auto& kv : cache) {
|
||||
// If the path in the cache doesn't start with old_path, then bail on this file.
|
||||
if (kv.first.rfind(old_path, 0) != 0) {
|
||||
continue;
|
||||
// Path in cache starts with old_path
|
||||
if (kv.first.rfind(old_path, 0) == 0) {
|
||||
const auto file_old_path =
|
||||
FileUtil::SanitizePath(kv.first, FileUtil::DirectorySeparator::PlatformDefault);
|
||||
const auto file_new_path =
|
||||
FileUtil::SanitizePath(new_path + DIR_SEP + kv.first.substr(old_path.size()),
|
||||
FileUtil::DirectorySeparator::PlatformDefault);
|
||||
auto cached = cache[file_old_path];
|
||||
if (!cached.expired()) {
|
||||
auto file = cached.lock();
|
||||
file->Open(file_new_path, "r+b");
|
||||
cache.erase(file_old_path);
|
||||
cache[file_new_path] = file;
|
||||
}
|
||||
}
|
||||
|
||||
const auto file_old_path =
|
||||
FS::SanitizePath(kv.first, FS::DirectorySeparator::PlatformDefault);
|
||||
auto file_new_path = FS::SanitizePath(new_path + DIR_SEP + kv.first.substr(old_path.size()),
|
||||
FS::DirectorySeparator::PlatformDefault);
|
||||
const auto& cached = cache[file_old_path];
|
||||
|
||||
if (cached.expired()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto file = cached.lock();
|
||||
file->Open(file_new_path, "r+b");
|
||||
cache.erase(file_old_path);
|
||||
cache.insert_or_assign(std::move(file_new_path), std::move(file));
|
||||
}
|
||||
|
||||
return OpenDirectory(new_path, Mode::ReadWrite);
|
||||
}
|
||||
|
||||
bool RealVfsFilesystem::DeleteDirectory(std::string_view path_) {
|
||||
const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault);
|
||||
|
||||
const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault);
|
||||
for (auto& kv : cache) {
|
||||
// If the path in the cache doesn't start with path, then bail on this file.
|
||||
if (kv.first.rfind(path, 0) != 0) {
|
||||
continue;
|
||||
// Path in cache starts with old_path
|
||||
if (kv.first.rfind(path, 0) == 0) {
|
||||
if (!cache[kv.first].expired())
|
||||
cache[kv.first].lock()->Close();
|
||||
cache.erase(kv.first);
|
||||
}
|
||||
|
||||
const auto& entry = cache[kv.first];
|
||||
if (!entry.expired()) {
|
||||
entry.lock()->Close();
|
||||
}
|
||||
|
||||
cache.erase(kv.first);
|
||||
}
|
||||
|
||||
return FS::DeleteDirRecursively(path);
|
||||
return FileUtil::DeleteDirRecursively(path);
|
||||
}
|
||||
|
||||
RealVfsFile::RealVfsFile(RealVfsFilesystem& base_, std::shared_ptr<FS::IOFile> backing_,
|
||||
RealVfsFile::RealVfsFile(RealVfsFilesystem& base_, std::shared_ptr<FileUtil::IOFile> backing_,
|
||||
const std::string& path_, Mode perms_)
|
||||
: base(base_), backing(std::move(backing_)), path(path_), parent_path(FS::GetParentPath(path_)),
|
||||
path_components(FS::SplitPathComponents(path_)),
|
||||
parent_components(FS::SliceVector(path_components, 0, path_components.size() - 1)),
|
||||
: base(base_), backing(std::move(backing_)), path(path_),
|
||||
parent_path(FileUtil::GetParentPath(path_)),
|
||||
path_components(FileUtil::SplitPathComponents(path_)),
|
||||
parent_components(FileUtil::SliceVector(path_components, 0, path_components.size() - 1)),
|
||||
perms(perms_) {}
|
||||
|
||||
RealVfsFile::~RealVfsFile() = default;
|
||||
@@ -268,24 +247,22 @@ std::shared_ptr<VfsDirectory> RealVfsFile::GetContainingDirectory() const {
|
||||
}
|
||||
|
||||
bool RealVfsFile::IsWritable() const {
|
||||
return True(perms & Mode::WriteAppend);
|
||||
return (perms & Mode::WriteAppend) != 0;
|
||||
}
|
||||
|
||||
bool RealVfsFile::IsReadable() const {
|
||||
return True(perms & Mode::ReadWrite);
|
||||
return (perms & Mode::ReadWrite) != 0;
|
||||
}
|
||||
|
||||
std::size_t RealVfsFile::Read(u8* data, std::size_t length, std::size_t offset) const {
|
||||
if (!backing->Seek(static_cast<s64>(offset), SEEK_SET)) {
|
||||
if (!backing->Seek(offset, SEEK_SET))
|
||||
return 0;
|
||||
}
|
||||
return backing->ReadBytes(data, length);
|
||||
}
|
||||
|
||||
std::size_t RealVfsFile::Write(const u8* data, std::size_t length, std::size_t offset) {
|
||||
if (!backing->Seek(static_cast<s64>(offset), SEEK_SET)) {
|
||||
if (!backing->Seek(offset, SEEK_SET))
|
||||
return 0;
|
||||
}
|
||||
return backing->WriteBytes(data, length);
|
||||
}
|
||||
|
||||
@@ -302,18 +279,16 @@ bool RealVfsFile::Close() {
|
||||
|
||||
template <>
|
||||
std::vector<VirtualFile> RealVfsDirectory::IterateEntries<RealVfsFile, VfsFile>() const {
|
||||
if (perms == Mode::Append) {
|
||||
if (perms == Mode::Append)
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<VirtualFile> out;
|
||||
FS::ForeachDirectoryEntry(
|
||||
FileUtil::ForeachDirectoryEntry(
|
||||
nullptr, path,
|
||||
[&out, this](u64* entries_out, const std::string& directory, const std::string& filename) {
|
||||
const std::string full_path = directory + DIR_SEP + filename;
|
||||
if (!FS::IsDirectory(full_path)) {
|
||||
if (!FileUtil::IsDirectory(full_path))
|
||||
out.emplace_back(base.OpenFile(full_path, perms));
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
@@ -322,18 +297,16 @@ std::vector<VirtualFile> RealVfsDirectory::IterateEntries<RealVfsFile, VfsFile>(
|
||||
|
||||
template <>
|
||||
std::vector<VirtualDir> RealVfsDirectory::IterateEntries<RealVfsDirectory, VfsDirectory>() const {
|
||||
if (perms == Mode::Append) {
|
||||
if (perms == Mode::Append)
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<VirtualDir> out;
|
||||
FS::ForeachDirectoryEntry(
|
||||
FileUtil::ForeachDirectoryEntry(
|
||||
nullptr, path,
|
||||
[&out, this](u64* entries_out, const std::string& directory, const std::string& filename) {
|
||||
const std::string full_path = directory + DIR_SEP + filename;
|
||||
if (FS::IsDirectory(full_path)) {
|
||||
if (FileUtil::IsDirectory(full_path))
|
||||
out.emplace_back(base.OpenDirectory(full_path, perms));
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
@@ -341,30 +314,28 @@ std::vector<VirtualDir> RealVfsDirectory::IterateEntries<RealVfsDirectory, VfsDi
|
||||
}
|
||||
|
||||
RealVfsDirectory::RealVfsDirectory(RealVfsFilesystem& base_, const std::string& path_, Mode perms_)
|
||||
: base(base_), path(FS::RemoveTrailingSlash(path_)), parent_path(FS::GetParentPath(path)),
|
||||
path_components(FS::SplitPathComponents(path)),
|
||||
parent_components(FS::SliceVector(path_components, 0, path_components.size() - 1)),
|
||||
: base(base_), path(FileUtil::RemoveTrailingSlash(path_)),
|
||||
parent_path(FileUtil::GetParentPath(path)),
|
||||
path_components(FileUtil::SplitPathComponents(path)),
|
||||
parent_components(FileUtil::SliceVector(path_components, 0, path_components.size() - 1)),
|
||||
perms(perms_) {
|
||||
if (!FS::Exists(path) && True(perms & Mode::WriteAppend)) {
|
||||
FS::CreateDir(path);
|
||||
}
|
||||
if (!FileUtil::Exists(path) && perms & Mode::WriteAppend)
|
||||
FileUtil::CreateDir(path);
|
||||
}
|
||||
|
||||
RealVfsDirectory::~RealVfsDirectory() = default;
|
||||
|
||||
std::shared_ptr<VfsFile> RealVfsDirectory::GetFileRelative(std::string_view path) const {
|
||||
const auto full_path = FS::SanitizePath(this->path + DIR_SEP + std::string(path));
|
||||
if (!FS::Exists(full_path) || FS::IsDirectory(full_path)) {
|
||||
const auto full_path = FileUtil::SanitizePath(this->path + DIR_SEP + std::string(path));
|
||||
if (!FileUtil::Exists(full_path) || FileUtil::IsDirectory(full_path))
|
||||
return nullptr;
|
||||
}
|
||||
return base.OpenFile(full_path, perms);
|
||||
}
|
||||
|
||||
std::shared_ptr<VfsDirectory> RealVfsDirectory::GetDirectoryRelative(std::string_view path) const {
|
||||
const auto full_path = FS::SanitizePath(this->path + DIR_SEP + std::string(path));
|
||||
if (!FS::Exists(full_path) || !FS::IsDirectory(full_path)) {
|
||||
const auto full_path = FileUtil::SanitizePath(this->path + DIR_SEP + std::string(path));
|
||||
if (!FileUtil::Exists(full_path) || !FileUtil::IsDirectory(full_path))
|
||||
return nullptr;
|
||||
}
|
||||
return base.OpenDirectory(full_path, perms);
|
||||
}
|
||||
|
||||
@@ -377,17 +348,17 @@ std::shared_ptr<VfsDirectory> RealVfsDirectory::GetSubdirectory(std::string_view
|
||||
}
|
||||
|
||||
std::shared_ptr<VfsFile> RealVfsDirectory::CreateFileRelative(std::string_view path) {
|
||||
const auto full_path = FS::SanitizePath(this->path + DIR_SEP + std::string(path));
|
||||
const auto full_path = FileUtil::SanitizePath(this->path + DIR_SEP + std::string(path));
|
||||
return base.CreateFile(full_path, perms);
|
||||
}
|
||||
|
||||
std::shared_ptr<VfsDirectory> RealVfsDirectory::CreateDirectoryRelative(std::string_view path) {
|
||||
const auto full_path = FS::SanitizePath(this->path + DIR_SEP + std::string(path));
|
||||
const auto full_path = FileUtil::SanitizePath(this->path + DIR_SEP + std::string(path));
|
||||
return base.CreateDirectory(full_path, perms);
|
||||
}
|
||||
|
||||
bool RealVfsDirectory::DeleteSubdirectoryRecursive(std::string_view name) {
|
||||
const auto full_path = FS::SanitizePath(this->path + DIR_SEP + std::string(name));
|
||||
auto full_path = FileUtil::SanitizePath(this->path + DIR_SEP + std::string(name));
|
||||
return base.DeleteDirectory(full_path);
|
||||
}
|
||||
|
||||
@@ -400,11 +371,11 @@ std::vector<std::shared_ptr<VfsDirectory>> RealVfsDirectory::GetSubdirectories()
|
||||
}
|
||||
|
||||
bool RealVfsDirectory::IsWritable() const {
|
||||
return True(perms & Mode::WriteAppend);
|
||||
return (perms & Mode::WriteAppend) != 0;
|
||||
}
|
||||
|
||||
bool RealVfsDirectory::IsReadable() const {
|
||||
return True(perms & Mode::ReadWrite);
|
||||
return (perms & Mode::ReadWrite) != 0;
|
||||
}
|
||||
|
||||
std::string RealVfsDirectory::GetName() const {
|
||||
@@ -412,9 +383,8 @@ std::string RealVfsDirectory::GetName() const {
|
||||
}
|
||||
|
||||
std::shared_ptr<VfsDirectory> RealVfsDirectory::GetParentDirectory() const {
|
||||
if (path_components.size() <= 1) {
|
||||
if (path_components.size() <= 1)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return base.OpenDirectory(parent_path, perms);
|
||||
}
|
||||
@@ -451,17 +421,16 @@ std::string RealVfsDirectory::GetFullPath() const {
|
||||
}
|
||||
|
||||
std::map<std::string, VfsEntryType, std::less<>> RealVfsDirectory::GetEntries() const {
|
||||
if (perms == Mode::Append) {
|
||||
if (perms == Mode::Append)
|
||||
return {};
|
||||
}
|
||||
|
||||
std::map<std::string, VfsEntryType, std::less<>> out;
|
||||
FS::ForeachDirectoryEntry(
|
||||
FileUtil::ForeachDirectoryEntry(
|
||||
nullptr, path,
|
||||
[&out](u64* entries_out, const std::string& directory, const std::string& filename) {
|
||||
const std::string full_path = directory + DIR_SEP + filename;
|
||||
out.emplace(filename,
|
||||
FS::IsDirectory(full_path) ? VfsEntryType::Directory : VfsEntryType::File);
|
||||
out.emplace(filename, FileUtil::IsDirectory(full_path) ? VfsEntryType::Directory
|
||||
: VfsEntryType::File);
|
||||
return true;
|
||||
});
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include "core/file_sys/mode.h"
|
||||
#include "core/file_sys/vfs.h"
|
||||
|
||||
namespace Common::FS {
|
||||
namespace FileUtil {
|
||||
class IOFile;
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ public:
|
||||
bool DeleteDirectory(std::string_view path) override;
|
||||
|
||||
private:
|
||||
boost::container::flat_map<std::string, std::weak_ptr<Common::FS::IOFile>> cache;
|
||||
boost::container::flat_map<std::string, std::weak_ptr<FileUtil::IOFile>> cache;
|
||||
};
|
||||
|
||||
// An implmentation of VfsFile that represents a file on the user's computer.
|
||||
@@ -58,13 +58,13 @@ public:
|
||||
bool Rename(std::string_view name) override;
|
||||
|
||||
private:
|
||||
RealVfsFile(RealVfsFilesystem& base, std::shared_ptr<Common::FS::IOFile> backing,
|
||||
RealVfsFile(RealVfsFilesystem& base, std::shared_ptr<FileUtil::IOFile> backing,
|
||||
const std::string& path, Mode perms = Mode::Read);
|
||||
|
||||
bool Close();
|
||||
|
||||
RealVfsFilesystem& base;
|
||||
std::shared_ptr<Common::FS::IOFile> backing;
|
||||
std::shared_ptr<FileUtil::IOFile> backing;
|
||||
std::string path;
|
||||
std::string parent_path;
|
||||
std::vector<std::string> path_components;
|
||||
|
||||
@@ -4,11 +4,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "core/file_sys/vfs.h"
|
||||
|
||||
namespace FileSys {
|
||||
@@ -17,8 +13,7 @@ namespace FileSys {
|
||||
template <std::size_t size>
|
||||
class ArrayVfsFile : public VfsFile {
|
||||
public:
|
||||
explicit ArrayVfsFile(const std::array<u8, size>& data, std::string name = "",
|
||||
VirtualDir parent = nullptr)
|
||||
ArrayVfsFile(std::array<u8, size> data, std::string name = "", VirtualDir parent = nullptr)
|
||||
: data(data), name(std::move(name)), parent(std::move(parent)) {}
|
||||
|
||||
std::string GetName() const override {
|
||||
@@ -66,12 +61,6 @@ private:
|
||||
VirtualDir parent;
|
||||
};
|
||||
|
||||
template <std::size_t Size, typename... Args>
|
||||
std::shared_ptr<ArrayVfsFile<Size>> MakeArrayFile(const std::array<u8, Size>& data,
|
||||
Args&&... args) {
|
||||
return std::make_shared<ArrayVfsFile<Size>>(data, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
// An implementation of VfsFile that is backed by a vector optionally supplied upon construction
|
||||
class VectorVfsFile : public VfsFile {
|
||||
public:
|
||||
|
||||
@@ -44,7 +44,7 @@ static bool CalculateHMAC256(Destination* out, const SourceKey* key, std::size_t
|
||||
}
|
||||
|
||||
NAX::NAX(VirtualFile file_) : header(std::make_unique<NAXHeader>()), file(std::move(file_)) {
|
||||
std::string path = Common::FS::SanitizePath(file->GetFullPath());
|
||||
std::string path = FileUtil::SanitizePath(file->GetFullPath());
|
||||
static const std::regex nax_path_regex("/registered/(000000[0-9A-F]{2})/([0-9A-F]{32})\\.nca",
|
||||
std::regex_constants::ECMAScript |
|
||||
std::regex_constants::icase);
|
||||
@@ -70,18 +70,14 @@ NAX::NAX(VirtualFile file_, std::array<u8, 0x10> nca_id)
|
||||
NAX::~NAX() = default;
|
||||
|
||||
Loader::ResultStatus NAX::Parse(std::string_view path) {
|
||||
if (file == nullptr) {
|
||||
return Loader::ResultStatus::ErrorNullFile;
|
||||
}
|
||||
if (file->ReadObject(header.get()) != sizeof(NAXHeader)) {
|
||||
if (file->ReadObject(header.get()) != sizeof(NAXHeader))
|
||||
return Loader::ResultStatus::ErrorBadNAXHeader;
|
||||
}
|
||||
if (header->magic != Common::MakeMagic('N', 'A', 'X', '0')) {
|
||||
|
||||
if (header->magic != Common::MakeMagic('N', 'A', 'X', '0'))
|
||||
return Loader::ResultStatus::ErrorBadNAXHeader;
|
||||
}
|
||||
if (file->GetSize() < NAX_HEADER_PADDING_SIZE + header->file_size) {
|
||||
|
||||
if (file->GetSize() < NAX_HEADER_PADDING_SIZE + header->file_size)
|
||||
return Loader::ResultStatus::ErrorIncorrectNAXFileSize;
|
||||
}
|
||||
|
||||
keys.DeriveSDSeedLazy();
|
||||
std::array<Core::Crypto::Key256, 2> sd_keys{};
|
||||
|
||||
@@ -39,7 +39,7 @@ public:
|
||||
|
||||
class Scoped {
|
||||
public:
|
||||
[[nodiscard]] explicit Scoped(GraphicsContext& context_) : context(context_) {
|
||||
explicit Scoped(GraphicsContext& context_) : context(context_) {
|
||||
context.MakeCurrent();
|
||||
}
|
||||
~Scoped() {
|
||||
@@ -52,7 +52,7 @@ public:
|
||||
|
||||
/// Calls MakeCurrent on the context and calls DoneCurrent when the scope for the returned value
|
||||
/// ends
|
||||
[[nodiscard]] Scoped Acquire() {
|
||||
Scoped Acquire() {
|
||||
return Scoped{*this};
|
||||
}
|
||||
};
|
||||
|
||||
@@ -229,8 +229,6 @@ inline void ResponseBuilder::Push(u32 value) {
|
||||
|
||||
template <typename T>
|
||||
void ResponseBuilder::PushRaw(const T& value) {
|
||||
static_assert(std::is_trivially_copyable_v<T>,
|
||||
"It's undefined behavior to use memcpy with non-trivially copyable objects");
|
||||
std::memcpy(cmdbuf + index, &value, sizeof(T));
|
||||
index += (sizeof(T) + 3) / 4; // round up to word length
|
||||
}
|
||||
@@ -386,8 +384,6 @@ inline s32 RequestParser::Pop() {
|
||||
|
||||
template <typename T>
|
||||
void RequestParser::PopRaw(T& value) {
|
||||
static_assert(std::is_trivially_copyable_v<T>,
|
||||
"It's undefined behavior to use memcpy with non-trivially copyable objects");
|
||||
std::memcpy(&value, cmdbuf + index, sizeof(T));
|
||||
index += (sizeof(T) + 3) / 4; // round up to word length
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ ResultCode AddressArbiter::IncrementAndSignalToAddressIfEqual(VAddr address, s32
|
||||
do {
|
||||
current_value = monitor.ExclusiveRead32(current_core, address);
|
||||
|
||||
if (current_value != static_cast<u32>(value)) {
|
||||
if (current_value != value) {
|
||||
return ERR_INVALID_STATE;
|
||||
}
|
||||
current_value++;
|
||||
|
||||
@@ -293,15 +293,13 @@ std::vector<u8> HLERequestContext::ReadBuffer(std::size_t buffer_index) const {
|
||||
BufferDescriptorA()[buffer_index].Size()};
|
||||
|
||||
if (is_buffer_a) {
|
||||
ASSERT_OR_EXECUTE_MSG(
|
||||
BufferDescriptorA().size() > buffer_index, { return buffer; },
|
||||
"BufferDescriptorA invalid buffer_index {}", buffer_index);
|
||||
ASSERT_OR_EXECUTE_MSG(BufferDescriptorA().size() > buffer_index, { return buffer; },
|
||||
"BufferDescriptorA invalid buffer_index {}", buffer_index);
|
||||
buffer.resize(BufferDescriptorA()[buffer_index].Size());
|
||||
memory.ReadBlock(BufferDescriptorA()[buffer_index].Address(), buffer.data(), buffer.size());
|
||||
} else {
|
||||
ASSERT_OR_EXECUTE_MSG(
|
||||
BufferDescriptorX().size() > buffer_index, { return buffer; },
|
||||
"BufferDescriptorX invalid buffer_index {}", buffer_index);
|
||||
ASSERT_OR_EXECUTE_MSG(BufferDescriptorX().size() > buffer_index, { return buffer; },
|
||||
"BufferDescriptorX invalid buffer_index {}", buffer_index);
|
||||
buffer.resize(BufferDescriptorX()[buffer_index].Size());
|
||||
memory.ReadBlock(BufferDescriptorX()[buffer_index].Address(), buffer.data(), buffer.size());
|
||||
}
|
||||
@@ -326,16 +324,16 @@ std::size_t HLERequestContext::WriteBuffer(const void* buffer, std::size_t size,
|
||||
}
|
||||
|
||||
if (is_buffer_b) {
|
||||
ASSERT_OR_EXECUTE_MSG(
|
||||
BufferDescriptorB().size() > buffer_index &&
|
||||
BufferDescriptorB()[buffer_index].Size() >= size,
|
||||
{ return 0; }, "BufferDescriptorB is invalid, index={}, size={}", buffer_index, size);
|
||||
ASSERT_OR_EXECUTE_MSG(BufferDescriptorB().size() > buffer_index &&
|
||||
BufferDescriptorB()[buffer_index].Size() >= size,
|
||||
{ return 0; }, "BufferDescriptorB is invalid, index={}, size={}",
|
||||
buffer_index, size);
|
||||
memory.WriteBlock(BufferDescriptorB()[buffer_index].Address(), buffer, size);
|
||||
} else {
|
||||
ASSERT_OR_EXECUTE_MSG(
|
||||
BufferDescriptorC().size() > buffer_index &&
|
||||
BufferDescriptorC()[buffer_index].Size() >= size,
|
||||
{ return 0; }, "BufferDescriptorC is invalid, index={}, size={}", buffer_index, size);
|
||||
ASSERT_OR_EXECUTE_MSG(BufferDescriptorC().size() > buffer_index &&
|
||||
BufferDescriptorC()[buffer_index].Size() >= size,
|
||||
{ return 0; }, "BufferDescriptorC is invalid, index={}, size={}",
|
||||
buffer_index, size);
|
||||
memory.WriteBlock(BufferDescriptorC()[buffer_index].Address(), buffer, size);
|
||||
}
|
||||
|
||||
@@ -346,14 +344,12 @@ std::size_t HLERequestContext::GetReadBufferSize(std::size_t buffer_index) const
|
||||
const bool is_buffer_a{BufferDescriptorA().size() > buffer_index &&
|
||||
BufferDescriptorA()[buffer_index].Size()};
|
||||
if (is_buffer_a) {
|
||||
ASSERT_OR_EXECUTE_MSG(
|
||||
BufferDescriptorA().size() > buffer_index, { return 0; },
|
||||
"BufferDescriptorA invalid buffer_index {}", buffer_index);
|
||||
ASSERT_OR_EXECUTE_MSG(BufferDescriptorA().size() > buffer_index, { return 0; },
|
||||
"BufferDescriptorA invalid buffer_index {}", buffer_index);
|
||||
return BufferDescriptorA()[buffer_index].Size();
|
||||
} else {
|
||||
ASSERT_OR_EXECUTE_MSG(
|
||||
BufferDescriptorX().size() > buffer_index, { return 0; },
|
||||
"BufferDescriptorX invalid buffer_index {}", buffer_index);
|
||||
ASSERT_OR_EXECUTE_MSG(BufferDescriptorX().size() > buffer_index, { return 0; },
|
||||
"BufferDescriptorX invalid buffer_index {}", buffer_index);
|
||||
return BufferDescriptorX()[buffer_index].Size();
|
||||
}
|
||||
}
|
||||
@@ -362,14 +358,12 @@ std::size_t HLERequestContext::GetWriteBufferSize(std::size_t buffer_index) cons
|
||||
const bool is_buffer_b{BufferDescriptorB().size() > buffer_index &&
|
||||
BufferDescriptorB()[buffer_index].Size()};
|
||||
if (is_buffer_b) {
|
||||
ASSERT_OR_EXECUTE_MSG(
|
||||
BufferDescriptorB().size() > buffer_index, { return 0; },
|
||||
"BufferDescriptorB invalid buffer_index {}", buffer_index);
|
||||
ASSERT_OR_EXECUTE_MSG(BufferDescriptorB().size() > buffer_index, { return 0; },
|
||||
"BufferDescriptorB invalid buffer_index {}", buffer_index);
|
||||
return BufferDescriptorB()[buffer_index].Size();
|
||||
} else {
|
||||
ASSERT_OR_EXECUTE_MSG(
|
||||
BufferDescriptorC().size() > buffer_index, { return 0; },
|
||||
"BufferDescriptorC invalid buffer_index {}", buffer_index);
|
||||
ASSERT_OR_EXECUTE_MSG(BufferDescriptorC().size() > buffer_index, { return 0; },
|
||||
"BufferDescriptorC invalid buffer_index {}", buffer_index);
|
||||
return BufferDescriptorC()[buffer_index].Size();
|
||||
}
|
||||
return 0;
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
#include <vector>
|
||||
#include <boost/container/small_vector.hpp>
|
||||
#include "common/common_types.h"
|
||||
#include "common/concepts.h"
|
||||
#include "common/swap.h"
|
||||
#include "core/hle/ipc.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
@@ -194,24 +193,23 @@ public:
|
||||
|
||||
/* Helper function to write a buffer using the appropriate buffer descriptor
|
||||
*
|
||||
* @tparam T an arbitrary container that satisfies the
|
||||
* ContiguousContainer concept in the C++ standard library or a trivially copyable type.
|
||||
* @tparam ContiguousContainer an arbitrary container that satisfies the
|
||||
* ContiguousContainer concept in the C++ standard library.
|
||||
*
|
||||
* @param data The container/data to write into a buffer.
|
||||
* @param container The container to write the data of into a buffer.
|
||||
* @param buffer_index The buffer in particular to write to.
|
||||
*/
|
||||
template <typename T, typename = std::enable_if_t<!std::is_pointer_v<T>>>
|
||||
std::size_t WriteBuffer(const T& data, std::size_t buffer_index = 0) const {
|
||||
if constexpr (Common::IsSTLContainer<T>) {
|
||||
using ContiguousType = typename T::value_type;
|
||||
static_assert(std::is_trivially_copyable_v<ContiguousType>,
|
||||
"Container to WriteBuffer must contain trivially copyable objects");
|
||||
return WriteBuffer(std::data(data), std::size(data) * sizeof(ContiguousType),
|
||||
buffer_index);
|
||||
} else {
|
||||
static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable");
|
||||
return WriteBuffer(&data, sizeof(T), buffer_index);
|
||||
}
|
||||
template <typename ContiguousContainer,
|
||||
typename = std::enable_if_t<!std::is_pointer_v<ContiguousContainer>>>
|
||||
std::size_t WriteBuffer(const ContiguousContainer& container,
|
||||
std::size_t buffer_index = 0) const {
|
||||
using ContiguousType = typename ContiguousContainer::value_type;
|
||||
|
||||
static_assert(std::is_trivially_copyable_v<ContiguousType>,
|
||||
"Container to WriteBuffer must contain trivially copyable objects");
|
||||
|
||||
return WriteBuffer(std::data(container), std::size(container) * sizeof(ContiguousType),
|
||||
buffer_index);
|
||||
}
|
||||
|
||||
/// Helper function to get the size of the input buffer
|
||||
|
||||
@@ -604,6 +604,7 @@ ResultCode PageTable::MapPages(VAddr addr, const PageLinkedList& page_linked_lis
|
||||
if (const auto result{
|
||||
Operate(cur_addr, node.GetNumPages(), perm, OperationType::Map, node.GetAddress())};
|
||||
result.IsError()) {
|
||||
const MemoryInfo info{block_manager->FindBlock(cur_addr).GetMemoryInfo()};
|
||||
const std::size_t num_pages{(addr - cur_addr) / PageSize};
|
||||
|
||||
ASSERT(
|
||||
@@ -851,12 +852,11 @@ ResultCode PageTable::LockForDeviceAddressSpace(VAddr addr, std::size_t size) {
|
||||
return result;
|
||||
}
|
||||
|
||||
block_manager->UpdateLock(
|
||||
addr, size / PageSize,
|
||||
[](MemoryBlockManager::iterator block, MemoryPermission perm) {
|
||||
block->ShareToDevice(perm);
|
||||
},
|
||||
perm);
|
||||
block_manager->UpdateLock(addr, size / PageSize,
|
||||
[](MemoryBlockManager::iterator block, MemoryPermission perm) {
|
||||
block->ShareToDevice(perm);
|
||||
},
|
||||
perm);
|
||||
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
@@ -874,12 +874,11 @@ ResultCode PageTable::UnlockForDeviceAddressSpace(VAddr addr, std::size_t size)
|
||||
return result;
|
||||
}
|
||||
|
||||
block_manager->UpdateLock(
|
||||
addr, size / PageSize,
|
||||
[](MemoryBlockManager::iterator block, MemoryPermission perm) {
|
||||
block->UnshareToDevice(perm);
|
||||
},
|
||||
perm);
|
||||
block_manager->UpdateLock(addr, size / PageSize,
|
||||
[](MemoryBlockManager::iterator block, MemoryPermission perm) {
|
||||
block->UnshareToDevice(perm);
|
||||
},
|
||||
perm);
|
||||
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -7,15 +7,22 @@
|
||||
#include "core/hle/kernel/memory/system_control.h"
|
||||
|
||||
namespace Kernel::Memory::SystemControl {
|
||||
namespace {
|
||||
|
||||
u64 GenerateRandomU64ForInit() {
|
||||
static std::random_device device;
|
||||
static std::mt19937 gen(device());
|
||||
static std::uniform_int_distribution<u64> distribution(1, std::numeric_limits<u64>::max());
|
||||
return distribution(gen);
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
u64 GenerateUniformRange(u64 min, u64 max, F f) {
|
||||
// Handle the case where the difference is too large to represent.
|
||||
/* Handle the case where the difference is too large to represent. */
|
||||
if (max == std::numeric_limits<u64>::max() && min == std::numeric_limits<u64>::min()) {
|
||||
return f();
|
||||
}
|
||||
|
||||
// Iterate until we get a value in range.
|
||||
/* Iterate until we get a value in range. */
|
||||
const u64 range_size = ((max + 1) - min);
|
||||
const u64 effective_max = (std::numeric_limits<u64>::max() / range_size) * range_size;
|
||||
while (true) {
|
||||
@@ -25,14 +32,6 @@ u64 GenerateUniformRange(u64 min, u64 max, F f) {
|
||||
}
|
||||
}
|
||||
|
||||
u64 GenerateRandomU64ForInit() {
|
||||
static std::random_device device;
|
||||
static std::mt19937 gen(device());
|
||||
static std::uniform_int_distribution<u64> distribution(1, std::numeric_limits<u64>::max());
|
||||
return distribution(gen);
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
u64 GenerateRandomRange(u64 min, u64 max) {
|
||||
return GenerateUniformRange(min, max, GenerateRandomU64ForInit);
|
||||
}
|
||||
|
||||
@@ -8,6 +8,11 @@
|
||||
|
||||
namespace Kernel::Memory::SystemControl {
|
||||
|
||||
u64 GenerateRandomU64ForInit();
|
||||
|
||||
template <typename F>
|
||||
u64 GenerateUniformRange(u64 min, u64 max, F f);
|
||||
|
||||
u64 GenerateRandomRange(u64 min, u64 max);
|
||||
|
||||
} // namespace Kernel::Memory::SystemControl
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user