Skip to content

Commit

Permalink
nn_idb: Implement icon database reading
Browse files Browse the repository at this point in the history
  • Loading branch information
Maschell committed Apr 26, 2024
1 parent 8e4e1cb commit 5984b88
Show file tree
Hide file tree
Showing 6 changed files with 257 additions and 0 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ SOURCES := cafe \
libraries/libirc/src \
libraries/nn_erreula \
libraries/nn_sl \
libraries/nn_idb \
libraries/nn_swkbd
DATA := data
INCLUDES := include \
Expand Down
8 changes: 8 additions & 0 deletions include/nn/idb.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#pragma once

/**
* \defgroup nn_idb nn_idb
*/

#include <nn/idb/idb_cpp.h>
#include <nn/idb/IDBReader.h>
55 changes: 55 additions & 0 deletions include/nn/idb/IDBReader.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#pragma once

#ifdef __cplusplus

#include <cstdio>
#include <nn/idb/idb_cpp.h>
#include <nn/result.h>
#include <string>

namespace nn::idb {
class IDBReader {
public:
IDBReader() = default;

~IDBReader();

nn::Result LoadIconDataFromIdb(uint64_t titleId, nn::idb::IconDataRaw &iconData) const;

bool SearchFromDataBase(nn::idb::IconDataKey &key, uint32_t &outIndex) const;

bool LoadIconDataFromDatabase(uint32_t index, nn::idb::IconDataRaw &iconData) const;

bool LoadIconData(uint64_t titleId, uint32_t u1, nn::idb::IconDataRaw &iconData) const;

/**
* Initializes the IDBReader from a custom path
* @param path Path to "BaristaIconDataBase.dat"
* @return true on success, false on error
*/
bool Initialize(const std::string &path);

/**
* Initializes the IDBReader to read icons from the Wii U Menu icon cache
* (fs:/vol/storage_mlc01/usr/save/%08X/%08X/user/common/BaristaIconDataBase.dat)
* @return true on success, false on error
*/
bool Initialize();

void Finalize();

private:
bool InitializeFile();

void FinalizeFile();

int LoadFromFile(void *buffer, uint32_t size, uint32_t offset) const;

std::string mPath = {};
FileHeader *mFileHeader = {};
FILE *mFile = {};
bool mInitDone = false;
};
} // namespace nn::idb

#endif
56 changes: 56 additions & 0 deletions include/nn/idb/idb_cpp.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#pragma once

#ifdef __cplusplus

#include <wut.h>
#include <cstdint>

namespace nn::idb {
struct WUT_PACKED FileHeaderEntry {
uint64_t titleId;
uint32_t u1;
WUT_UNKNOWN_BYTES(0xC);
};
WUT_CHECK_SIZE(FileHeaderEntry, 0x18);
WUT_CHECK_OFFSET(FileHeaderEntry, 0x00, titleId);
WUT_CHECK_OFFSET(FileHeaderEntry, 0x08, u1);

struct WUT_PACKED FileHeader {
uint32_t version;
FileHeaderEntry entries[300];
};
WUT_CHECK_SIZE(FileHeader, 0x1c24);
WUT_CHECK_OFFSET(FileHeader, 0x00, version);
WUT_CHECK_OFFSET(FileHeader, 0x04, entries);

struct WUT_PACKED IconDataKey {
uint64_t titleId;
uint32_t u1; // maybe some kind of filter (or version)?
};
WUT_CHECK_SIZE(IconDataKey, 0xC);
WUT_CHECK_OFFSET(IconDataKey, 0x00, titleId);
WUT_CHECK_OFFSET(IconDataKey, 0x08, u1);

struct WUT_PACKED Utf16NameBuffer {
char16_t utf16Str[0x100];
};
WUT_CHECK_SIZE(Utf16NameBuffer, 0x200);
WUT_CHECK_OFFSET(Utf16NameBuffer, 0x00, utf16Str);

struct WUT_PACKED IconDataRaw {
uint64_t titleID;
WUT_UNKNOWN_BYTES(0xC);
char u6[0x10];
WUT_UNKNOWN_BYTES(0xC);
Utf16NameBuffer names[0xF];
WUT_UNKNOWN_BYTES(0x200);
uint8_t icon[0x1002c];
WUT_UNKNOWN_BYTES(0x4);
};
WUT_CHECK_SIZE(IconDataRaw, 0x12060);
WUT_CHECK_OFFSET(IconDataRaw, 0x00, titleID);
WUT_CHECK_OFFSET(IconDataRaw, 0x30, names);
WUT_CHECK_OFFSET(IconDataRaw, 0x2030, icon);
} // namespace nn::idb

#endif
136 changes: 136 additions & 0 deletions libraries/nn_idb/IDBReader.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
#include <malloc.h>
#include <nn/idb/IDBReader.h>
#include <nn/idb/idb_cpp.h>
#include <sysapp/title.h>

namespace nn::idb {
IDBReader::~IDBReader() {
Finalize();
}

nn::Result IDBReader::LoadIconDataFromIdb(uint64_t titleId, IconDataRaw &iconData) const {
if (!LoadIconData(titleId, 0xFFFFFFFF, iconData)) {
return {Result::LEVEL_FATAL, Result::RESULT_MODULE_NN_SL, 1};
}
return {{0}};
}

bool IDBReader::SearchFromDataBase(IconDataKey &key, uint32_t &outIndex) const {
if (!mInitDone) {
return false;
}
int index = 0;
for (const auto &entry : mFileHeader->entries) {
if (entry.titleId == key.titleId && (entry.u1 == key.u1 || key.u1 == 0xFFFFFFFF)) {
outIndex = index;
return true;
}
index++;
}
return false;
}

bool IDBReader::LoadIconDataFromDatabase(uint32_t index, IconDataRaw &iconData) const {
if (!mInitDone) {
return false;
}
auto res = LoadFromFile(&iconData, sizeof(IconDataRaw), index * sizeof(IconDataRaw) + sizeof(FileHeader));
return res == sizeof(IconDataRaw);
}

bool IDBReader::LoadIconData(uint64_t titleId, uint32_t u1, IconDataRaw &iconData) const {
if (!mInitDone) {
return false;
}
IconDataKey dataKey = {
.titleId = titleId,
.u1 = u1};
uint32_t index;


if (SearchFromDataBase(dataKey, index)) {
return LoadIconDataFromDatabase(index, iconData);
}
return false;
}

bool IDBReader::Initialize(const std::string &path) {
this->mPath = path;
if (!mFileHeader) {
mFileHeader = (FileHeader *) memalign(0x40, sizeof(*mFileHeader));
if (!mFileHeader) {
return false;
}
}

if (!InitializeFile()) {
Finalize();
return false;
}

if (LoadFromFile(mFileHeader, sizeof(*mFileHeader), 0) != sizeof(*mFileHeader)) {
Finalize();
return false;
}
if (mFileHeader->version != 0) {
Finalize();
return false;
}

mInitDone = true;
return true;
}

bool IDBReader::Initialize() {
uint64_t menuTid = _SYSGetSystemApplicationTitleId(SYSTEM_APP_ID_WII_U_MENU);
auto *menuTidPtr = (uint32_t *) menuTid;
char path[90];
snprintf(path, sizeof(path), "fs:/vol/storage_mlc01/usr/save/%08X/%08X/user/common/BaristaIconDataBase.dat", menuTidPtr[0], menuTidPtr[1]);

return Initialize(path);
}

void IDBReader::Finalize() {
if (mFileHeader) {
free(mFileHeader);
mFileHeader = nullptr;
}
FinalizeFile();
mInitDone = false;
}

bool IDBReader::InitializeFile() {
if (!mFile) {
mFile = fopen(mPath.c_str(), "r");
if (!mFile) {
return false;
}
}
return true;
}

void IDBReader::FinalizeFile() {
if (mFile) {
fclose(mFile);
mFile = nullptr;
}
}

int IDBReader::LoadFromFile(void *buffer, uint32_t size, uint32_t offset) const {
if (!mFile) {
return 0;
}
size_t bytesRead;

if (fseek(mFile, offset, SEEK_SET) != 0) {
return false;
}

bytesRead = ::fread(buffer, 1, (size_t) size, mFile);

if (bytesRead != size) {
bytesRead = 0;
}
return bytesRead;
}
} // namespace nn::idb
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@
#include <nn/ffl/miidata.h>
#include <nn/hpad/beta.h>
#include <nn/hpad/hpad.h>
#include <nn/idb.h>
#include <nn/nets2/somemopt.h>
#include <nn/nfp/nfp_cpp.h>
#include <nn/nfp/amiibo_settings_cpp.h>
Expand Down

0 comments on commit 5984b88

Please sign in to comment.