mirror of
https://github.com/cemu-project/Cemu.git
synced 2025-07-03 21:41:19 +12:00
Add all the files
This commit is contained in:
parent
e3db07a16a
commit
d60742f52b
1445 changed files with 430238 additions and 0 deletions
333
src/Cafe/IOSU/legacy/iosu_nim.cpp
Normal file
333
src/Cafe/IOSU/legacy/iosu_nim.cpp
Normal file
|
@ -0,0 +1,333 @@
|
|||
#include "iosu_nim.h"
|
||||
#include "iosu_ioctl.h"
|
||||
#include "iosu_act.h"
|
||||
#include "iosu_mcp.h"
|
||||
#include "util/crypto/aes128.h"
|
||||
#include "curl/curl.h"
|
||||
#include "openssl/bn.h"
|
||||
#include "openssl/x509.h"
|
||||
#include "openssl/ssl.h"
|
||||
#include "util/helpers/helpers.h"
|
||||
|
||||
#include <thread>
|
||||
|
||||
#include "Cemu/napi/napi.h"
|
||||
#include "Cemu/ncrypto/ncrypto.h"
|
||||
|
||||
namespace iosu
|
||||
{
|
||||
namespace nim
|
||||
{
|
||||
struct NIMTitleLatestVersion
|
||||
{
|
||||
uint64 titleId;
|
||||
uint32 version;
|
||||
};
|
||||
|
||||
#define PACKAGE_TYPE_UPDATE (1)
|
||||
|
||||
struct NIMPackage
|
||||
{
|
||||
uint64 titleId;
|
||||
uint16 version;
|
||||
uint8 type;
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
bool isInitialized;
|
||||
// version list
|
||||
sint32 latestVersion;
|
||||
char fqdn[256];
|
||||
std::vector<NIMTitleLatestVersion> titlesLatestVersion;
|
||||
// nim packages
|
||||
// note: Seems like scope.rpx expects the number of packages to never change after the initial GetNum call?
|
||||
std::vector<NIMPackage*> packages;
|
||||
bool packageListReady;
|
||||
bool backgroundThreadStarted;
|
||||
} g_nim = {};
|
||||
|
||||
bool nim_getLatestVersion()
|
||||
{
|
||||
g_nim.latestVersion = -1;
|
||||
NAPI::AuthInfo authInfo;
|
||||
authInfo.country = NCrypto::GetCountryAsString(Account::GetCurrentAccount().GetCountry());
|
||||
authInfo.region = NCrypto::SEEPROM_GetRegion();
|
||||
auto versionListVersionResult = NAPI::TAG_GetVersionListVersion(authInfo);
|
||||
if (!versionListVersionResult.isValid)
|
||||
return false;
|
||||
if (versionListVersionResult.fqdnURL.size() >= 256)
|
||||
{
|
||||
cemuLog_force("NIM: fqdn URL too long");
|
||||
return false;
|
||||
}
|
||||
g_nim.latestVersion = (sint32)versionListVersionResult.version;
|
||||
strcpy(g_nim.fqdn, versionListVersionResult.fqdnURL.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool nim_getVersionList()
|
||||
{
|
||||
g_nim.titlesLatestVersion.clear();
|
||||
|
||||
NAPI::AuthInfo authInfo;
|
||||
authInfo.country = NCrypto::GetCountryAsString(Account::GetCurrentAccount().GetCountry());
|
||||
authInfo.region = NCrypto::SEEPROM_GetRegion();
|
||||
auto versionListVersionResult = NAPI::TAG_GetVersionListVersion(authInfo);
|
||||
if (!versionListVersionResult.isValid)
|
||||
return false;
|
||||
auto versionListResult = TAG_GetVersionList(authInfo, versionListVersionResult.fqdnURL, versionListVersionResult.version);
|
||||
if (!versionListResult.isValid)
|
||||
return false;
|
||||
for (auto& itr : versionListResult.titleVersionList)
|
||||
{
|
||||
NIMTitleLatestVersion titleLatestVersion;
|
||||
titleLatestVersion.titleId = itr.first;
|
||||
titleLatestVersion.version = itr.second;
|
||||
g_nim.titlesLatestVersion.push_back(titleLatestVersion);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
NIMTitleLatestVersion* nim_findTitleLatestVersion(uint64 titleId)
|
||||
{
|
||||
for (auto& titleLatestVersion : g_nim.titlesLatestVersion)
|
||||
{
|
||||
if (titleLatestVersion.titleId == titleId)
|
||||
return &titleLatestVersion;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void nim_buildDownloadList()
|
||||
{
|
||||
sint32 titleCount = mcpGetTitleCount();
|
||||
MCPTitleInfo* titleList = (MCPTitleInfo*)malloc(titleCount * sizeof(MCPTitleInfo));
|
||||
memset(titleList, 0, titleCount * sizeof(MCPTitleInfo));
|
||||
|
||||
uint32be titleCountBE = titleCount;
|
||||
if (mcpGetTitleList(titleList, titleCount * sizeof(MCPTitleInfo), &titleCountBE) != 0)
|
||||
{
|
||||
forceLog_printf("IOSU: nim failed to acquire title list");
|
||||
free(titleList);
|
||||
return;
|
||||
}
|
||||
titleCount = titleCountBE;
|
||||
// check for game updates
|
||||
for (sint32 i = 0; i < titleCount; i++)
|
||||
{
|
||||
if( titleList[i].titleIdHigh != 0x00050000 )
|
||||
continue;
|
||||
// find update title in title version list
|
||||
uint64 titleId = (0x0005000EULL << 32) | ((uint64)(uint32)titleList[i].titleIdLow);
|
||||
NIMTitleLatestVersion* latestVersionInfo = nim_findTitleLatestVersion(titleId);
|
||||
if(latestVersionInfo == nullptr)
|
||||
continue;
|
||||
// compare version
|
||||
if(latestVersionInfo->version <= (uint32)titleList[i].titleVersion )
|
||||
continue; // already on latest version
|
||||
// add to packages
|
||||
NIMPackage* nimPackage = (NIMPackage*)malloc(sizeof(NIMPackage));
|
||||
memset(nimPackage, 0, sizeof(NIMPackage));
|
||||
nimPackage->titleId = titleId;
|
||||
nimPackage->type = PACKAGE_TYPE_UPDATE;
|
||||
g_nim.packages.push_back(nimPackage);
|
||||
}
|
||||
// check for AOC/titles to download
|
||||
// todo
|
||||
free(titleList);
|
||||
}
|
||||
|
||||
void nim_getPackagesInfo(uint64* titleIdList, sint32 count, titlePackageInfo_t* packageInfoList)
|
||||
{
|
||||
memset(packageInfoList, 0, sizeof(titlePackageInfo_t)*count);
|
||||
for (sint32 i = 0; i < count; i++)
|
||||
{
|
||||
uint64 titleId = _swapEndianU64(titleIdList[i]);
|
||||
titlePackageInfo_t* packageInfo = packageInfoList + i;
|
||||
|
||||
packageInfo->titleId = _swapEndianU64(titleIdList[0]);
|
||||
|
||||
packageInfo->ukn0C = 1; // update
|
||||
|
||||
// pending
|
||||
packageInfo->ukn48 = 0; // with 0 there is no progress bar, with 3 there is a progress bar
|
||||
packageInfo->ukn40 = (5 << 20) | (0 << 27) | (1<<31) | (0x30000<<0);
|
||||
|
||||
packageInfo->ukn0F = 1;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
struct idbeIconCacheEntry_t
|
||||
{
|
||||
void setIconData(NAPI::IDBEIconDataV0& newIconData)
|
||||
{
|
||||
iconData = newIconData;
|
||||
hasIconData = true;
|
||||
}
|
||||
|
||||
void setNoIcon()
|
||||
{
|
||||
hasIconData = false;
|
||||
iconData = {};
|
||||
}
|
||||
|
||||
uint64 titleId;
|
||||
uint32 lastRequestTime;
|
||||
bool hasIconData{ false };
|
||||
NAPI::IDBEIconDataV0 iconData{};
|
||||
};
|
||||
|
||||
std::vector<idbeIconCacheEntry_t> idbeIconCache;
|
||||
|
||||
void idbe_addIconToCache(uint64 titleId, NAPI::IDBEIconDataV0* iconData)
|
||||
{
|
||||
idbeIconCacheEntry_t newCacheEntry;
|
||||
newCacheEntry.titleId = titleId;
|
||||
newCacheEntry.lastRequestTime = GetTickCount();
|
||||
if (iconData)
|
||||
newCacheEntry.setIconData(*iconData);
|
||||
else
|
||||
newCacheEntry.setNoIcon();
|
||||
idbeIconCache.push_back(newCacheEntry);
|
||||
}
|
||||
|
||||
sint32 nim_getIconDatabaseEntry(uint64 titleId, void* idbeIconOutput)
|
||||
{
|
||||
// if titleId is an update, replace it with gameId instead
|
||||
if ((uint32)(titleId >> 32) == 0x0005000EULL)
|
||||
{
|
||||
titleId &= ~0xF00000000ULL;
|
||||
}
|
||||
|
||||
for (auto& entry : idbeIconCache)
|
||||
{
|
||||
if (entry.titleId == titleId)
|
||||
{
|
||||
if( entry.hasIconData )
|
||||
memcpy(idbeIconOutput, &entry.iconData, sizeof(NAPI::IDBEIconDataV0));
|
||||
else
|
||||
memset(idbeIconOutput, 0, sizeof(NAPI::IDBEIconDataV0));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
auto result = NAPI::IDBE_Request(titleId);
|
||||
if (!result)
|
||||
{
|
||||
memset(idbeIconOutput, 0, sizeof(NAPI::IDBEIconDataV0));
|
||||
forceLog_printf("NIM: Unable to download IDBE icon");
|
||||
return 0;
|
||||
}
|
||||
// add new cache entry
|
||||
idbe_addIconToCache(titleId, &*result);
|
||||
// return result
|
||||
memcpy(idbeIconOutput, &*result, sizeof(NAPI::IDBEIconDataV0));
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nim_backgroundThread()
|
||||
{
|
||||
while (iosuAct_isAccountDataLoaded() == false)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(500));
|
||||
}
|
||||
|
||||
if (nim_getLatestVersion())
|
||||
{
|
||||
if (nim_getVersionList())
|
||||
{
|
||||
nim_buildDownloadList();
|
||||
}
|
||||
}
|
||||
g_nim.packageListReady = true;
|
||||
}
|
||||
|
||||
void iosuNim_waitUntilPackageListReady()
|
||||
{
|
||||
if (g_nim.backgroundThreadStarted == false)
|
||||
{
|
||||
forceLog_printf("IOSU: Starting nim background thread");
|
||||
std::thread t(nim_backgroundThread);
|
||||
t.detach();
|
||||
g_nim.backgroundThreadStarted = true;
|
||||
}
|
||||
while (g_nim.packageListReady == false)
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||||
}
|
||||
|
||||
|
||||
void iosuNim_thread()
|
||||
{
|
||||
SetThreadName("iosuNim_thread");
|
||||
while (true)
|
||||
{
|
||||
uint32 returnValue = 0; // Ioctl return value
|
||||
ioQueueEntry_t* ioQueueEntry = iosuIoctl_getNextWithWait(IOS_DEVICE_NIM);
|
||||
if (ioQueueEntry->request == IOSU_NIM_REQUEST_CEMU)
|
||||
{
|
||||
iosuNimCemuRequest_t* nimCemuRequest = (iosuNimCemuRequest_t*)ioQueueEntry->bufferVectors[0].buffer.GetPtr();
|
||||
if (nimCemuRequest->requestCode == IOSU_NIM_GET_ICON_DATABASE_ENTRY)
|
||||
{
|
||||
nimCemuRequest->returnCode = nim_getIconDatabaseEntry(nimCemuRequest->titleId, nimCemuRequest->ptr.GetPtr());
|
||||
}
|
||||
else if (nimCemuRequest->requestCode == IOSU_NIM_GET_PACKAGE_COUNT)
|
||||
{
|
||||
iosuNim_waitUntilPackageListReady();
|
||||
nimCemuRequest->resultU32.u32 = (uint32)g_nim.packages.size();
|
||||
nimCemuRequest->returnCode = 0;
|
||||
}
|
||||
else if (nimCemuRequest->requestCode == IOSU_NIM_GET_PACKAGES_TITLEID)
|
||||
{
|
||||
iosuNim_waitUntilPackageListReady();
|
||||
uint32 maxCount = nimCemuRequest->maxCount;
|
||||
uint64* titleIdList = (uint64*)nimCemuRequest->ptr.GetPtr();
|
||||
uint32 count = 0;
|
||||
memset(titleIdList, 0, sizeof(uint64) * maxCount);
|
||||
for (auto& package : g_nim.packages)
|
||||
{
|
||||
titleIdList[count] = _swapEndianU64(package->titleId);
|
||||
count++;
|
||||
if (count >= maxCount)
|
||||
break;
|
||||
}
|
||||
nimCemuRequest->returnCode = 0;
|
||||
}
|
||||
else if (nimCemuRequest->requestCode == IOSU_NIM_GET_PACKAGES_INFO)
|
||||
{
|
||||
iosuNim_waitUntilPackageListReady();
|
||||
uint32 maxCount = nimCemuRequest->maxCount;
|
||||
uint64* titleIdList = (uint64*)nimCemuRequest->ptr.GetPtr();
|
||||
titlePackageInfo_t* packageInfo = (titlePackageInfo_t*)nimCemuRequest->ptr2.GetPtr();
|
||||
nim_getPackagesInfo(titleIdList, maxCount, packageInfo);
|
||||
nimCemuRequest->returnCode = 0;
|
||||
}
|
||||
else
|
||||
cemu_assert_unimplemented();
|
||||
}
|
||||
else
|
||||
cemu_assert_unimplemented();
|
||||
iosuIoctl_completeRequest(ioQueueEntry, returnValue);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
if (g_nim.isInitialized)
|
||||
return;
|
||||
std::vector<idbeIconCacheEntry_t> idbeIconCache = std::vector<idbeIconCacheEntry_t>();
|
||||
g_nim.titlesLatestVersion = std::vector<NIMTitleLatestVersion>();
|
||||
g_nim.packages = std::vector<NIMPackage*>();
|
||||
g_nim.packageListReady = false;
|
||||
g_nim.backgroundThreadStarted = false;
|
||||
std::thread t2(iosuNim_thread);
|
||||
t2.detach();
|
||||
g_nim.isInitialized = true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue