file_sys/title_metadata: Allow loading from both files, FileBackends, and data

This commit is contained in:
shinyquagsire23 2017-10-21 16:52:48 -06:00
parent b3e87d01fb
commit ce806dcdf6
3 changed files with 56 additions and 36 deletions

View file

@ -29,47 +29,70 @@ static u32 GetSignatureSize(u32 signature_type) {
case EcdsaSha256:
return 0x3C;
}
return 0;
}
Loader::ResultStatus TitleMetadata::Load() {
FileUtil::IOFile file(filepath, "rb");
Loader::ResultStatus TitleMetadata::Load(const std::string& file_path) {
FileUtil::IOFile file(file_path, "rb");
if (!file.IsOpen())
return Loader::ResultStatus::Error;
if (!file.ReadBytes(&signature_type, sizeof(u32_be)))
std::vector<u8> file_data(file.GetSize());
if (!file.ReadBytes(file_data.data(), file.GetSize()))
return Loader::ResultStatus::Error;
Loader::ResultStatus result = Load(file_data);
if (result != Loader::ResultStatus::Success)
LOG_ERROR(Service_FS, "Failed to load TMD from file %s!", file_path.c_str());
return result;
}
Loader::ResultStatus TitleMetadata::Load(const std::vector<u8> file_data, size_t offset) {
size_t total_size = static_cast<size_t>(file_data.size() - offset);
if (total_size < sizeof(u32_be))
return Loader::ResultStatus::Error;
memcpy(&signature_type, &file_data[offset], sizeof(u32_be));
// Signature lengths are variable, and the body follows the signature
u32 signature_size = GetSignatureSize(signature_type);
tmd_signature.resize(signature_size);
if (!file.ReadBytes(&tmd_signature[0], signature_size))
return Loader::ResultStatus::Error;
// The TMD body start position is rounded to the nearest 0x40 after the signature
size_t body_start = Common::AlignUp(signature_size + sizeof(u32), 0x40);
file.Seek(body_start, SEEK_SET);
size_t body_end = body_start + sizeof(Body);
// Read our TMD body, then load the amount of ContentChunks specified
if (file.ReadBytes(&tmd_body, sizeof(TitleMetadata::Body)) != sizeof(TitleMetadata::Body))
if (total_size < body_end)
return Loader::ResultStatus::Error;
// Read signature + TMD body, then load the amount of ContentChunks specified
tmd_signature.resize(signature_size);
memcpy(tmd_signature.data(), &file_data[offset + sizeof(u32_be)], signature_size);
memcpy(&tmd_body, &file_data[offset + body_start], sizeof(TitleMetadata::Body));
size_t expected_size =
body_start + sizeof(Body) + tmd_body.content_count * sizeof(ContentChunk);
if (total_size < expected_size) {
LOG_ERROR(Service_FS, "Malformed TMD, expected size 0x%zx, got 0x%zx!", expected_size,
total_size);
return Loader::ResultStatus::ErrorInvalidFormat;
}
for (u16 i = 0; i < tmd_body.content_count; i++) {
ContentChunk chunk;
if (file.ReadBytes(&chunk, sizeof(ContentChunk)) == sizeof(ContentChunk)) {
tmd_chunks.push_back(chunk);
} else {
LOG_ERROR(Service_FS, "Malformed TMD %s, failed to load content chunk index %u!",
filepath.c_str(), i);
return Loader::ResultStatus::ErrorInvalidFormat;
}
memcpy(&chunk, &file_data[offset + body_end + (i * sizeof(ContentChunk))],
sizeof(ContentChunk));
tmd_chunks.push_back(chunk);
}
return Loader::ResultStatus::Success;
}
Loader::ResultStatus TitleMetadata::Save() {
FileUtil::IOFile file(filepath, "wb");
Loader::ResultStatus TitleMetadata::Save(const std::string& file_path) {
FileUtil::IOFile file(file_path, "wb");
if (!file.IsOpen())
return Loader::ResultStatus::Error;
@ -186,8 +209,7 @@ void TitleMetadata::AddContentChunk(const ContentChunk& chunk) {
}
void TitleMetadata::Print() const {
LOG_DEBUG(Service_FS, "%s - %u chunks", filepath.c_str(),
static_cast<u32>(tmd_body.content_count));
LOG_DEBUG(Service_FS, "%u chunks", static_cast<u32>(tmd_body.content_count));
// Content info describes ranges of content chunks
LOG_DEBUG(Service_FS, "Content info:");

View file

@ -92,9 +92,9 @@ public:
#pragma pack(pop)
explicit TitleMetadata(std::string& path) : filepath(std::move(path)) {}
Loader::ResultStatus Load();
Loader::ResultStatus Save();
Loader::ResultStatus Load(const std::string& file_path);
Loader::ResultStatus Load(const std::vector<u8> file_data, size_t offset = 0);
Loader::ResultStatus Save(const std::string& file_path);
u64 GetTitleID() const;
u32 GetTitleType() const;
@ -121,8 +121,6 @@ private:
u32_be signature_type;
std::vector<u8> tmd_signature;
std::vector<ContentChunk> tmd_chunks;
std::string filepath;
};
} // namespace FileSys

View file

@ -98,8 +98,8 @@ std::string GetTitleContentPath(Service::FS::MediaType media_type, u64 tid, u16
std::string tmd_path = GetTitleMetadataPath(media_type, tid);
u32 content_id = 0;
FileSys::TitleMetadata tmd(tmd_path);
if (tmd.Load() == Loader::ResultStatus::Success) {
FileSys::TitleMetadata tmd;
if (tmd.LoadFromFile(tmd_path) == Loader::ResultStatus::Success) {
content_id = tmd.GetContentIDByIndex(index);
// TODO(shinyquagsire23): how does DLC actually get this folder on hardware?
@ -199,8 +199,8 @@ void FindContentInfos(Service::Interface* self) {
std::string tmd_path = GetTitleMetadataPath(media_type, title_id);
u32 content_read = 0;
FileSys::TitleMetadata tmd(tmd_path);
if (tmd.Load() == Loader::ResultStatus::Success) {
FileSys::TitleMetadata tmd;
if (tmd.LoadFromFile(tmd_path) == Loader::ResultStatus::Success) {
// Get info for each content index requested
for (size_t i = 0; i < content_count; i++) {
std::shared_ptr<FileUtil::IOFile> romfs_file;
@ -238,8 +238,8 @@ void ListContentInfos(Service::Interface* self) {
std::string tmd_path = GetTitleMetadataPath(media_type, title_id);
u32 copied = 0;
FileSys::TitleMetadata tmd(tmd_path);
if (tmd.Load() == Loader::ResultStatus::Success) {
FileSys::TitleMetadata tmd;
if (tmd.LoadFromFile(tmd_path) == Loader::ResultStatus::Success) {
copied = std::min(content_count, static_cast<u32>(tmd.GetContentCount()));
for (u32 i = start_index; i < copied; i++) {
std::shared_ptr<FileUtil::IOFile> romfs_file;
@ -313,8 +313,8 @@ ResultCode GetTitleInfoFromList(const std::vector<u64>& title_id_list,
TitleInfo title_info = {};
title_info.tid = title_id_list[i];
FileSys::TitleMetadata tmd(tmd_path);
if (tmd.Load() == Loader::ResultStatus::Success) {
FileSys::TitleMetadata tmd;
if (tmd.LoadFromFile(tmd_path) == Loader::ResultStatus::Success) {
// TODO(shinyquagsire23): This is the total size of all files this process owns,
// including savefiles and other content. This comes close but is off.
title_info.size = tmd.GetContentSizeByIndex(FileSys::TMDContentIndex::Main);
@ -462,8 +462,8 @@ void GetNumContentInfos(Service::Interface* self) {
std::string tmd_path = GetTitleMetadataPath(media_type, title_id);
FileSys::TitleMetadata tmd(tmd_path);
if (tmd.Load() == Loader::ResultStatus::Success) {
FileSys::TitleMetadata tmd;
if (tmd.LoadFromFile(tmd_path) == Loader::ResultStatus::Success)
rb.Push<u32>(tmd.GetContentCount());
} else {
rb.Push<u32>(1); // Number of content infos plus one