[XAM/User] XamReadTile: support reading gamerpic from profile tile_64.png file
This commit is contained in:
parent
3c6fc95d45
commit
a74fd46e13
|
@ -30,6 +30,10 @@ std::string X_XAMACCOUNTINFO::GetGamertagString() const {
|
||||||
return xe::to_string(std::wstring(gamertag));
|
return xe::to_string(std::wstring(gamertag));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::wstring UserProfile::directory() const {
|
||||||
|
return xe::to_wstring(cvars::profile_directory);
|
||||||
|
}
|
||||||
|
|
||||||
bool UserProfile::DecryptAccountFile(const uint8_t* data,
|
bool UserProfile::DecryptAccountFile(const uint8_t* data,
|
||||||
X_XAMACCOUNTINFO* output, bool devkit) {
|
X_XAMACCOUNTINFO* output, bool devkit) {
|
||||||
const uint8_t* key = util::GetXeKey(0x19, devkit);
|
const uint8_t* key = util::GetXeKey(0x19, devkit);
|
||||||
|
|
|
@ -25,6 +25,34 @@ namespace xam {
|
||||||
|
|
||||||
constexpr uint32_t kDashboardID = 0xFFFE07D1;
|
constexpr uint32_t kDashboardID = 0xFFFE07D1;
|
||||||
|
|
||||||
|
// https://github.com/jogolden/testdev/blob/master/xkelib/xam/_xamext.h#L68
|
||||||
|
enum class XTileType {
|
||||||
|
kAchievement,
|
||||||
|
kGameIcon,
|
||||||
|
kGamerTile,
|
||||||
|
kGamerTileSmall,
|
||||||
|
kLocalGamerTile,
|
||||||
|
kLocalGamerTileSmall,
|
||||||
|
kBkgnd,
|
||||||
|
kAwardedGamerTile,
|
||||||
|
kAwardedGamerTileSmall,
|
||||||
|
kGamerTileByImageId,
|
||||||
|
kPersonalGamerTile,
|
||||||
|
kPersonalGamerTileSmall,
|
||||||
|
kGamerTileByKey,
|
||||||
|
kAvatarGamerTile,
|
||||||
|
kAvatarGamerTileSmall,
|
||||||
|
kAvatarFullBody
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: find filenames of other tile types that are stored in profile
|
||||||
|
static const std::map<XTileType, wchar_t*> kTileFileNames = {
|
||||||
|
{XTileType::kPersonalGamerTile, L"tile_64.png"},
|
||||||
|
{XTileType::kPersonalGamerTileSmall, L"tile_32.png"},
|
||||||
|
{XTileType::kAvatarGamerTile, L"avtr_64.png"},
|
||||||
|
{XTileType::kAvatarGamerTileSmall, L"avtr_32.png"},
|
||||||
|
};
|
||||||
|
|
||||||
// from https://github.com/xemio/testdev/blob/master/xkelib/xam/_xamext.h
|
// from https://github.com/xemio/testdev/blob/master/xkelib/xam/_xamext.h
|
||||||
#pragma pack(push, 4)
|
#pragma pack(push, 4)
|
||||||
struct X_XAMACCOUNTINFO {
|
struct X_XAMACCOUNTINFO {
|
||||||
|
@ -142,6 +170,7 @@ class UserProfile {
|
||||||
|
|
||||||
uint64_t xuid() const { return account_.xuid_online; }
|
uint64_t xuid() const { return account_.xuid_online; }
|
||||||
std::string name() const { return account_.GetGamertagString(); }
|
std::string name() const { return account_.GetGamertagString(); }
|
||||||
|
std::wstring directory() const;
|
||||||
// uint32_t signin_state() const { return 1; }
|
// uint32_t signin_state() const { return 1; }
|
||||||
|
|
||||||
xdbf::GpdFile* SetTitleSpaData(const xdbf::SpaFile& spa_data);
|
xdbf::GpdFile* SetTitleSpaData(const xdbf::SpaFile& spa_data);
|
||||||
|
|
|
@ -759,79 +759,91 @@ dword_result_t XamUserCreateTitlesPlayedEnumerator(
|
||||||
DECLARE_XAM_EXPORT1(XamUserCreateTitlesPlayedEnumerator, kUserProfiles,
|
DECLARE_XAM_EXPORT1(XamUserCreateTitlesPlayedEnumerator, kUserProfiles,
|
||||||
kImplemented);
|
kImplemented);
|
||||||
|
|
||||||
// https://github.com/jogolden/testdev/blob/master/xkelib/xam/_xamext.h#L68
|
|
||||||
enum class XTileType {
|
|
||||||
kAchievement,
|
|
||||||
kGameIcon,
|
|
||||||
kGamerTile,
|
|
||||||
kGamerTileSmall,
|
|
||||||
kLocalGamerTile,
|
|
||||||
kLocalGamerTileSmall,
|
|
||||||
kBkgnd,
|
|
||||||
kAwardedGamerTile,
|
|
||||||
kAwardedGamerTileSmall,
|
|
||||||
kGamerTileByImageId,
|
|
||||||
kPersonalGamerTile,
|
|
||||||
kPersonalGamerTileSmall,
|
|
||||||
kGamerTileByKey,
|
|
||||||
kAvatarGamerTile,
|
|
||||||
kAvatarGamerTileSmall,
|
|
||||||
kAvatarFullBody
|
|
||||||
};
|
|
||||||
|
|
||||||
dword_result_t XamReadTile(dword_t tile_type, dword_t game_id, qword_t item_id,
|
dword_result_t XamReadTile(dword_t tile_type, dword_t game_id, qword_t item_id,
|
||||||
dword_t offset, lpdword_t output_ptr,
|
dword_t offset, lpdword_t output_ptr,
|
||||||
lpdword_t buffer_size_ptr, dword_t overlapped_ptr) {
|
lpdword_t buffer_size_ptr, dword_t overlapped_ptr) {
|
||||||
if (!output_ptr || !buffer_size_ptr) {
|
// Wrap function in a lambda func so we can use return to exit out when
|
||||||
return X_ERROR_FILE_NOT_FOUND;
|
// needed, but still always be able to set the xoverlapped value
|
||||||
}
|
// this way we don't need a bunch of if/else nesting to accomplish the same
|
||||||
|
auto main_fn = [tile_type, game_id, item_id, offset, output_ptr,
|
||||||
|
buffer_size_ptr]() {
|
||||||
|
uint64_t image_id = item_id;
|
||||||
|
|
||||||
uint64_t image_id = item_id;
|
uint8_t* data = nullptr;
|
||||||
|
size_t data_len = 0;
|
||||||
|
std::unique_ptr<MappedMemory> mmap;
|
||||||
|
|
||||||
auto type = (XTileType)tile_type.value();
|
if (!output_ptr || !buffer_size_ptr) {
|
||||||
if (type == XTileType::kPersonalGamerTile) {
|
return X_ERROR_FILE_NOT_FOUND;
|
||||||
// TODO: read pic from profile dir, it's stored as a .png file
|
}
|
||||||
// image_id = XUID of profile to retrieve from
|
|
||||||
image_id = (uint64_t)SpaID::Title; // return dash image for now
|
|
||||||
}
|
|
||||||
|
|
||||||
auto gpd = kernel_state()->user_profile()->GetTitleGpd(game_id.value());
|
auto type = (XTileType)tile_type.value();
|
||||||
|
if (kTileFileNames.count(type)) {
|
||||||
|
// image_id = XUID of profile to retrieve from
|
||||||
|
|
||||||
if (!gpd) {
|
auto file_path = kernel_state()->user_profile()->directory();
|
||||||
return X_ERROR_FILE_NOT_FOUND;
|
file_path += kTileFileNames.at(type);
|
||||||
}
|
|
||||||
|
|
||||||
auto entry =
|
mmap = MappedMemory::Open(file_path, MappedMemory::Mode::kRead);
|
||||||
gpd->GetEntry(static_cast<uint16_t>(xdbf::GpdSection::kImage), image_id);
|
if (!mmap) {
|
||||||
|
return X_ERROR_FILE_NOT_FOUND;
|
||||||
|
}
|
||||||
|
data = mmap->data();
|
||||||
|
data_len = mmap->size();
|
||||||
|
} else {
|
||||||
|
auto gpd = kernel_state()->user_profile()->GetTitleGpd(game_id.value());
|
||||||
|
|
||||||
if (!entry) {
|
if (!gpd) {
|
||||||
return X_ERROR_FILE_NOT_FOUND;
|
return X_ERROR_FILE_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto passed_size = *buffer_size_ptr;
|
auto entry = gpd->GetEntry(
|
||||||
*buffer_size_ptr = (uint32_t)entry->data.size();
|
static_cast<uint16_t>(xdbf::GpdSection::kImage), image_id);
|
||||||
|
|
||||||
uint32_t ret_val = X_ERROR_INVALID_PARAMETER;
|
if (!entry) {
|
||||||
|
return X_ERROR_FILE_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
if (passed_size >= *buffer_size_ptr) {
|
data = entry->data.data();
|
||||||
memcpy_s(output_ptr, *buffer_size_ptr, entry->data.data(),
|
data_len = entry->data.size();
|
||||||
entry->data.size());
|
}
|
||||||
ret_val = X_ERROR_SUCCESS;
|
|
||||||
}
|
if (!data || !data_len) {
|
||||||
|
return X_ERROR_FILE_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto passed_size = *buffer_size_ptr;
|
||||||
|
*buffer_size_ptr = (uint32_t)data_len;
|
||||||
|
|
||||||
|
auto ret_val = X_ERROR_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
if (passed_size >= *buffer_size_ptr) {
|
||||||
|
memcpy_s(output_ptr, *buffer_size_ptr, data, data_len);
|
||||||
|
ret_val = X_ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mmap) {
|
||||||
|
mmap->Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret_val;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto retval = main_fn();
|
||||||
|
|
||||||
if (overlapped_ptr) {
|
if (overlapped_ptr) {
|
||||||
kernel_state()->CompleteOverlappedImmediate(overlapped_ptr, ret_val);
|
kernel_state()->CompleteOverlappedImmediate(overlapped_ptr, retval);
|
||||||
return X_ERROR_IO_PENDING;
|
return X_ERROR_IO_PENDING;
|
||||||
}
|
}
|
||||||
return ret_val;
|
return retval;
|
||||||
}
|
}
|
||||||
DECLARE_XAM_EXPORT1(XamReadTile, kUserProfiles, kSketchy);
|
DECLARE_XAM_EXPORT1(XamReadTile, kUserProfiles, kSketchy);
|
||||||
|
|
||||||
dword_result_t XamReadTileEx(dword_t section_id, dword_t game_id,
|
dword_result_t XamReadTileEx(dword_t tile_type, dword_t game_id,
|
||||||
qword_t item_id, dword_t offset, dword_t unk1,
|
qword_t item_id, dword_t offset, dword_t unk1,
|
||||||
dword_t unk2, lpdword_t output_ptr,
|
dword_t unk2, lpdword_t output_ptr,
|
||||||
lpdword_t buffer_size_ptr) {
|
lpdword_t buffer_size_ptr) {
|
||||||
return XamReadTile(section_id, game_id, item_id, offset, output_ptr,
|
return XamReadTile(tile_type, game_id, item_id, offset, output_ptr,
|
||||||
buffer_size_ptr, 0);
|
buffer_size_ptr, 0);
|
||||||
}
|
}
|
||||||
DECLARE_XAM_EXPORT1(XamReadTileEx, kUserProfiles, kSketchy);
|
DECLARE_XAM_EXPORT1(XamReadTileEx, kUserProfiles, kSketchy);
|
||||||
|
|
Loading…
Reference in New Issue