Skip to content

Commit

Permalink
nn_olv: More work on post API
Browse files Browse the repository at this point in the history
  • Loading branch information
Exzap committed Aug 3, 2023
1 parent 67819a6 commit 0d96255
Show file tree
Hide file tree
Showing 12 changed files with 655 additions and 207 deletions.
2 changes: 2 additions & 0 deletions src/Cafe/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,8 @@ add_library(CemuCafe
OS/libs/nn_olv/nn_olv_UploadFavoriteTypes.h
OS/libs/nn_olv/nn_olv_PostTypes.cpp
OS/libs/nn_olv/nn_olv_PostTypes.h
OS/libs/nn_olv/nn_olv_OfflineDB.cpp
OS/libs/nn_olv/nn_olv_OfflineDB.h
OS/libs/nn_pdm/nn_pdm.cpp
OS/libs/nn_pdm/nn_pdm.h
OS/libs/nn_save/nn_save.cpp
Expand Down
3 changes: 2 additions & 1 deletion src/Cafe/OS/libs/coreinit/coreinit_MCP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -546,6 +546,7 @@ void coreinitExport_UCReadSysConfig(PPCInterpreter_t* hCPU)
{
// get parental online control for online features
// note: This option is account-bound, the p_acct1 prefix indicates that the account in slot 1 is used
// a non-zero value means network access is restricted through parental access. 0 means allowed
// account in slot 1
if (ucParam->resultPtr != _swapEndianU32(MPTR_NULL))
memory_writeU8(_swapEndianU32(ucParam->resultPtr), 0); // data type is guessed
Expand All @@ -561,7 +562,7 @@ void coreinitExport_UCReadSysConfig(PPCInterpreter_t* hCPU)
{
// miiverse restrictions
if (ucParam->resultPtr != _swapEndianU32(MPTR_NULL))
memory_writeU8(_swapEndianU32(ucParam->resultPtr), 0); // data type is guessed (0 -> no restrictions, 1 -> read only?, 2 -> no access?)
memory_writeU8(_swapEndianU32(ucParam->resultPtr), 0); // data type is guessed (0 -> no restrictions, 1 -> read only, 2 -> no access)
}
else if (_strcmpi(ucParam->settingName, "s_acct01.uuid") == 0)
{
Expand Down
190 changes: 10 additions & 180 deletions src/Cafe/OS/libs/nn_olv/nn_olv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "nn_olv_DownloadCommunityTypes.h"
#include "nn_olv_UploadFavoriteTypes.h"
#include "nn_olv_PostTypes.h"
#include "nn_olv_OfflineDB.h"

#include "Cafe/OS/libs/proc_ui/proc_ui.h"
#include "Cafe/OS/libs/coreinit/coreinit_Time.h"
Expand All @@ -13,179 +14,6 @@ namespace nn
{
namespace olv
{
struct DownloadedPostData_t
{
/* +0x0000 */ uint32be flags;
/* +0x0004 */ uint32be userPrincipalId;
/* +0x0008 */ char postId[0x20]; // size guessed
/* +0x0028 */ uint64 postDate;
/* +0x0030 */ uint8 feeling;
/* +0x0031 */ uint8 padding0031[3];
/* +0x0034 */ uint32be regionId;
/* +0x0038 */ uint8 platformId;
/* +0x0039 */ uint8 languageId;
/* +0x003A */ uint8 countryId;
/* +0x003B */ uint8 padding003B[1];
/* +0x003C */ uint16be bodyText[0x100]; // actual size is unknown
/* +0x023C */ uint32be bodyTextLength;
/* +0x0240 */ uint8 compressedMemoBody[0xA000]; // 40KB
/* +0xA240 */ uint32be compressedMemoBodyRelated; // size of compressed data?
/* +0xA244 */ uint16be topicTag[0x98];
// app data
/* +0xA374 */ uint8 appData[0x400];
/* +0xA774 */ uint32be appDataLength;
// external binary
/* +0xA778 */ uint8 externalBinaryUrl[0x100];
/* +0xA878 */ uint32be externalBinaryDataSize;
// external image
/* +0xA87C */ uint8 externalImageDataUrl[0x100];
/* +0xA97C */ uint32be externalImageDataSize;
// external url ?
/* +0xA980 */ char externalUrl[0x100];
// mii
/* +0xAA80 */ uint8 miiData[0x60];
/* +0xAAE0 */ uint16be miiNickname[0x20];
/* +0xAB20 */ uint8 unusedAB20[0x14E0];

// everything above is part of DownloadedDataBase
// everything below is part of DownloadedPostData
/* +0xC000 */ uint8 uknDataC000[8]; // ??
/* +0xC008 */ uint32be communityId;
/* +0xC00C */ uint32be empathyCount;
/* +0xC010 */ uint32be commentCount;
/* +0xC014 */ uint8 unused[0x1F4];
}; // size: 0xC208

static_assert(sizeof(DownloadedPostData_t) == 0xC208, "");
static_assert(offsetof(DownloadedPostData_t, postDate) == 0x0028, "");
static_assert(offsetof(DownloadedPostData_t, platformId) == 0x0038, "");
static_assert(offsetof(DownloadedPostData_t, bodyText) == 0x003C, "");
static_assert(offsetof(DownloadedPostData_t, compressedMemoBody) == 0x0240, "");
static_assert(offsetof(DownloadedPostData_t, topicTag) == 0xA244, "");
static_assert(offsetof(DownloadedPostData_t, appData) == 0xA374, "");
static_assert(offsetof(DownloadedPostData_t, externalBinaryUrl) == 0xA778, "");
static_assert(offsetof(DownloadedPostData_t, externalImageDataUrl) == 0xA87C, "");
static_assert(offsetof(DownloadedPostData_t, externalUrl) == 0xA980, "");
static_assert(offsetof(DownloadedPostData_t, miiData) == 0xAA80, "");
static_assert(offsetof(DownloadedPostData_t, miiNickname) == 0xAAE0, "");
static_assert(offsetof(DownloadedPostData_t, unusedAB20) == 0xAB20, "");
static_assert(offsetof(DownloadedPostData_t, communityId) == 0xC008, "");
static_assert(offsetof(DownloadedPostData_t, empathyCount) == 0xC00C, "");
static_assert(offsetof(DownloadedPostData_t, commentCount) == 0xC010, "");

const int POST_DATA_FLAG_HAS_BODY_TEXT = (0x0001);
const int POST_DATA_FLAG_HAS_BODY_MEMO = (0x0002);


void export_DownloadPostDataList(PPCInterpreter_t* hCPU)
{
ppcDefineParamTypePtr(downloadedTopicData, void, 0); // DownloadedTopicData
ppcDefineParamTypePtr(downloadedPostData, DownloadedPostData_t, 1); // DownloadedPostData
ppcDefineParamTypePtr(downloadedPostDataSize, uint32be, 2);
ppcDefineParamS32(maxCount, 3);
ppcDefineParamTypePtr(listParam, void, 4); // DownloadPostDataListParam

maxCount = 0; // DISABLED

// just some test
for (sint32 i = 0; i < maxCount; i++)
{
DownloadedPostData_t* postData = downloadedPostData + i;
memset(postData, 0, sizeof(DownloadedPostData_t));
postData->userPrincipalId = 0x1000 + i;
// post id
sprintf(postData->postId, "postid-%04x", i+(GetTickCount()%10000));
postData->bodyTextLength = 12;
postData->bodyText[0] = 'H';
postData->bodyText[1] = 'e';
postData->bodyText[2] = 'l';
postData->bodyText[3] = 'l';
postData->bodyText[4] = 'o';
postData->bodyText[5] = ' ';
postData->bodyText[6] = 'w';
postData->bodyText[7] = 'o';
postData->bodyText[8] = 'r';
postData->bodyText[9] = 'l';
postData->bodyText[10] = 'd';
postData->bodyText[11] = '!';

postData->miiNickname[0] = 'C';
postData->miiNickname[1] = 'e';
postData->miiNickname[2] = 'm';
postData->miiNickname[3] = 'u';
postData->miiNickname[4] = '-';
postData->miiNickname[5] = 'M';
postData->miiNickname[6] = 'i';
postData->miiNickname[7] = 'i';

postData->topicTag[0] = 't';
postData->topicTag[1] = 'o';
postData->topicTag[2] = 'p';
postData->topicTag[3] = 'i';
postData->topicTag[4] = 'c';

postData->flags = POST_DATA_FLAG_HAS_BODY_TEXT;
}
*downloadedPostDataSize = maxCount;

osLib_returnFromFunction(hCPU, 0);
}

void exportDownloadPostData_TestFlags(PPCInterpreter_t* hCPU)
{
ppcDefineParamTypePtr(downloadedPostData, DownloadedPostData_t, 0);
ppcDefineParamU32(testFlags, 1);

if (((uint32)downloadedPostData->flags) & testFlags)
osLib_returnFromFunction(hCPU, 1);
else
osLib_returnFromFunction(hCPU, 0);
}

void exportDownloadPostData_GetPostId(PPCInterpreter_t* hCPU)
{
ppcDefineParamTypePtr(downloadedPostData, DownloadedPostData_t, 0);
osLib_returnFromFunction(hCPU, memory_getVirtualOffsetFromPointer(downloadedPostData->postId));
}

void exportDownloadPostData_GetMiiNickname(PPCInterpreter_t* hCPU)
{
ppcDefineParamTypePtr(downloadedPostData, DownloadedPostData_t, 0);
if(downloadedPostData->miiNickname[0] == 0 )
osLib_returnFromFunction(hCPU, MPTR_NULL);
else
osLib_returnFromFunction(hCPU, memory_getVirtualOffsetFromPointer(downloadedPostData->miiNickname));
}

void exportDownloadPostData_GetTopicTag(PPCInterpreter_t* hCPU)
{
ppcDefineParamTypePtr(downloadedPostData, DownloadedPostData_t, 0);
osLib_returnFromFunction(hCPU, memory_getVirtualOffsetFromPointer(downloadedPostData->topicTag));
}

void exportDownloadPostData_GetBodyText(PPCInterpreter_t* hCPU)
{
ppcDefineParamTypePtr(downloadedPostData, DownloadedPostData_t, 0);
ppcDefineParamWStrBE(strOut, 1);
ppcDefineParamS32(maxLength, 2);

if (((uint32)downloadedPostData->flags&POST_DATA_FLAG_HAS_BODY_TEXT) == 0)
{
osLib_returnFromFunction(hCPU, 0xC1106800);
return;
}

memset(strOut, 0, sizeof(uint16be)*maxLength);
sint32 copyLen = std::min(maxLength - 1, (sint32)downloadedPostData->bodyTextLength);
for (sint32 i = 0; i < copyLen; i++)
{
strOut[i] = downloadedPostData->bodyText[i];
}
strOut[copyLen] = '\0';

osLib_returnFromFunction(hCPU, 0);
}

struct PortalAppParam_t
{
/* +0x1A663B */ char serviceToken[32]; // size is unknown
Expand Down Expand Up @@ -284,6 +112,10 @@ namespace nn

void load()
{
g_ReportTypes = 0;
g_IsOnlineMode = false;
g_IsInitialized = false;
g_IsOfflineDBMode = false;

loadOliveInitializeTypes();
loadOliveUploadCommunityTypes();
Expand All @@ -293,13 +125,6 @@ namespace nn

cafeExportRegisterFunc(GetErrorCode, "nn_olv", "GetErrorCode__Q2_2nn3olvFRCQ2_2nn6Result", LogType::None);

osLib_addFunction("nn_olv", "DownloadPostDataList__Q2_2nn3olvFPQ3_2nn3olv19DownloadedTopicDataPQ3_2nn3olv18DownloadedPostDataPUiUiPCQ3_2nn3olv25DownloadPostDataListParam", export_DownloadPostDataList);
// osLib_addFunction("nn_olv", "TestFlags__Q3_2nn3olv18DownloadedDataBaseCFUi", exportDownloadPostData_TestFlags);
// osLib_addFunction("nn_olv", "GetPostId__Q3_2nn3olv18DownloadedDataBaseCFv", exportDownloadPostData_GetPostId);
// osLib_addFunction("nn_olv", "GetMiiNickname__Q3_2nn3olv18DownloadedDataBaseCFv", exportDownloadPostData_GetMiiNickname);
// osLib_addFunction("nn_olv", "GetTopicTag__Q3_2nn3olv18DownloadedDataBaseCFv", exportDownloadPostData_GetTopicTag);
// osLib_addFunction("nn_olv", "GetBodyText__Q3_2nn3olv18DownloadedDataBaseCFPwUi", exportDownloadPostData_GetBodyText);

osLib_addFunction("nn_olv", "GetServiceToken__Q4_2nn3olv6hidden14PortalAppParamCFv", exportPortalAppParam_GetServiceToken);

cafeExportRegisterFunc(StubPostApp, "nn_olv", "UploadPostDataByPostApp__Q2_2nn3olvFPCQ3_2nn3olv28UploadPostDataByPostAppParam", LogType::Force);
Expand All @@ -314,5 +139,10 @@ namespace nn
cafeExportRegisterFunc(UploadedPostData_GetPostId, "nn_olv", "GetPostId__Q3_2nn3olv16UploadedPostDataCFv", LogType::Force);
}

void unload() // not called yet
{
OfflineDB_Shutdown();
}

}
}
1 change: 1 addition & 0 deletions src/Cafe/OS/libs/nn_olv/nn_olv.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,6 @@ namespace nn
sint32 GetOlvAccessKey(uint32_t* pOutKey);

void load();
void unload();
}
}
35 changes: 35 additions & 0 deletions src/Cafe/OS/libs/nn_olv/nn_olv_Common.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ namespace nn
extern uint32_t g_ReportTypes;
extern bool g_IsInitialized;
extern bool g_IsOnlineMode;
extern bool g_IsOfflineDBMode; // use offline cache for posts

static void InitializeOliveRequest(CurlRequestHelper& req)
{
Expand Down Expand Up @@ -175,5 +176,39 @@ namespace nn
bool FormatCommunityCode(char* pOutCode, uint32* outLen, uint32 communityId);

sint32 olv_curlformcode_to_error(CURLFORMcode code);

// convert and copy utf8 string into UC2 big-endian array
template<size_t TLength>
uint32 SetStringUC2(uint16be(&str)[TLength], std::string_view sv, bool unescape = false)
{
if(unescape)
{
// todo
}
std::wstring ws = boost::nowide::widen(sv);
size_t copyLen = std::min<size_t>(TLength-1, ws.size());
for(size_t i=0; i<copyLen; i++)
str[i] = ws[i];
str[copyLen] = '\0';
return copyLen;
}

// safely copy null-terminated UC2 big-endian string into UC2 big-endian array
template<size_t TLength>
uint32 SetStringUC2(uint16be(&str)[TLength], const uint16be* strIn)
{
size_t copyLen = TLength-1;
for(size_t i=0; i<copyLen; i++)
{
if(strIn[i] == 0)
{
str[i] = 0;
return i;
}
str[i] = strIn[i];
}
str[copyLen] = '\0';
return copyLen;
}
}
}
10 changes: 8 additions & 2 deletions src/Cafe/OS/libs/nn_olv/nn_olv_InitializeTypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ namespace nn
{
namespace olv
{

uint32_t g_ReportTypes = 0;
bool g_IsOnlineMode = false;
bool g_IsInitialized = false;
bool g_IsOfflineDBMode = false;
ParamPackStorage g_ParamPack;
DiscoveryResultStorage g_DiscoveryResults;

Expand Down Expand Up @@ -241,9 +241,15 @@ namespace nn

g_IsInitialized = true;

if(ActiveSettings::GetNetworkService() == NetworkService::Nintendo)
{
// since the official Miiverse was shut down, use local post archive instead
g_IsOnlineMode = true;
g_IsOfflineDBMode = true;
return OLV_RESULT_SUCCESS;
}
if ((pParam->m_Flags & InitializeParam::FLAG_OFFLINE_MODE) == 0)
{

g_IsOnlineMode = true;

independentServiceToken_t token;
Expand Down
Loading

0 comments on commit 0d96255

Please sign in to comment.