summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/core/file_sys/patch_manager.cpp16
-rw-r--r--src/core/file_sys/patch_manager.h6
-rw-r--r--src/core/file_sys/romfs_factory.cpp7
-rw-r--r--src/core/file_sys/romfs_factory.h2
-rw-r--r--src/core/file_sys/submission_package.cpp5
-rw-r--r--src/core/hle/service/filesystem/filesystem.cpp9
-rw-r--r--src/core/hle/service/filesystem/filesystem.h1
-rw-r--r--src/core/loader/loader.cpp3
-rw-r--r--src/core/loader/loader.h14
-rw-r--r--src/core/loader/nax.cpp4
-rw-r--r--src/core/loader/nax.h1
-rw-r--r--src/core/loader/nsp.cpp32
-rw-r--r--src/core/loader/nsp.h4
-rw-r--r--src/core/loader/xci.cpp36
-rw-r--r--src/core/loader/xci.h4
-rw-r--r--src/yuzu/game_list_worker.cpp20
16 files changed, 143 insertions, 21 deletions
diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp
index 539698f6e..1ac00ebb0 100644
--- a/src/core/file_sys/patch_manager.cpp
+++ b/src/core/file_sys/patch_manager.cpp
@@ -184,8 +184,8 @@ static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType t
184 romfs = std::move(packed); 184 romfs = std::move(packed);
185} 185}
186 186
187VirtualFile PatchManager::PatchRomFS(VirtualFile romfs, u64 ivfc_offset, 187VirtualFile PatchManager::PatchRomFS(VirtualFile romfs, u64 ivfc_offset, ContentRecordType type,
188 ContentRecordType type) const { 188 VirtualFile update_raw) const {
189 LOG_INFO(Loader, "Patching RomFS for title_id={:016X}, type={:02X}", title_id, 189 LOG_INFO(Loader, "Patching RomFS for title_id={:016X}, type={:02X}", title_id,
190 static_cast<u8>(type)); 190 static_cast<u8>(type));
191 191
@@ -205,6 +205,13 @@ VirtualFile PatchManager::PatchRomFS(VirtualFile romfs, u64 ivfc_offset,
205 FormatTitleVersion(installed->GetEntryVersion(update_tid).get_value_or(0))); 205 FormatTitleVersion(installed->GetEntryVersion(update_tid).get_value_or(0)));
206 romfs = new_nca->GetRomFS(); 206 romfs = new_nca->GetRomFS();
207 } 207 }
208 } else if (update_raw != nullptr) {
209 const auto new_nca = std::make_shared<NCA>(update_raw, romfs, ivfc_offset);
210 if (new_nca->GetStatus() == Loader::ResultStatus::Success &&
211 new_nca->GetRomFS() != nullptr) {
212 LOG_INFO(Loader, " RomFS: Update (PACKED) applied successfully");
213 romfs = new_nca->GetRomFS();
214 }
208 } 215 }
209 216
210 // LayeredFS 217 // LayeredFS
@@ -224,7 +231,8 @@ static bool IsDirValidAndNonEmpty(const VirtualDir& dir) {
224 return dir != nullptr && (!dir->GetFiles().empty() || !dir->GetSubdirectories().empty()); 231 return dir != nullptr && (!dir->GetFiles().empty() || !dir->GetSubdirectories().empty());
225} 232}
226 233
227std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNames() const { 234std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNames(
235 VirtualFile update_raw) const {
228 std::map<std::string, std::string, std::less<>> out; 236 std::map<std::string, std::string, std::less<>> out;
229 const auto installed = Service::FileSystem::GetUnionContents(); 237 const auto installed = Service::FileSystem::GetUnionContents();
230 238
@@ -245,6 +253,8 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam
245 "Update", 253 "Update",
246 FormatTitleVersion(meta_ver.get(), TitleVersionFormat::ThreeElements)); 254 FormatTitleVersion(meta_ver.get(), TitleVersionFormat::ThreeElements));
247 } 255 }
256 } else if (update_raw != nullptr) {
257 out.insert_or_assign("Update", "PACKED");
248 } 258 }
249 } 259 }
250 260
diff --git a/src/core/file_sys/patch_manager.h b/src/core/file_sys/patch_manager.h
index 6a864ec43..2ae9322a1 100644
--- a/src/core/file_sys/patch_manager.h
+++ b/src/core/file_sys/patch_manager.h
@@ -46,11 +46,13 @@ public:
46 // - Game Updates 46 // - Game Updates
47 // - LayeredFS 47 // - LayeredFS
48 VirtualFile PatchRomFS(VirtualFile base, u64 ivfc_offset, 48 VirtualFile PatchRomFS(VirtualFile base, u64 ivfc_offset,
49 ContentRecordType type = ContentRecordType::Program) const; 49 ContentRecordType type = ContentRecordType::Program,
50 VirtualFile update_raw = nullptr) const;
50 51
51 // Returns a vector of pairs between patch names and patch versions. 52 // Returns a vector of pairs between patch names and patch versions.
52 // i.e. Update 3.2.2 will return {"Update", "3.2.2"} 53 // i.e. Update 3.2.2 will return {"Update", "3.2.2"}
53 std::map<std::string, std::string, std::less<>> GetPatchVersionNames() const; 54 std::map<std::string, std::string, std::less<>> GetPatchVersionNames(
55 VirtualFile update_raw = nullptr) const;
54 56
55 // Given title_id of the program, attempts to get the control data of the update and parse it, 57 // Given title_id of the program, attempts to get the control data of the update and parse it,
56 // falling back to the base control data. 58 // falling back to the base control data.
diff --git a/src/core/file_sys/romfs_factory.cpp b/src/core/file_sys/romfs_factory.cpp
index 4994c2532..0b645b106 100644
--- a/src/core/file_sys/romfs_factory.cpp
+++ b/src/core/file_sys/romfs_factory.cpp
@@ -30,12 +30,17 @@ RomFSFactory::RomFSFactory(Loader::AppLoader& app_loader) {
30 30
31RomFSFactory::~RomFSFactory() = default; 31RomFSFactory::~RomFSFactory() = default;
32 32
33void RomFSFactory::SetPackedUpdate(VirtualFile update_raw) {
34 this->update_raw = std::move(update_raw);
35}
36
33ResultVal<VirtualFile> RomFSFactory::OpenCurrentProcess() { 37ResultVal<VirtualFile> RomFSFactory::OpenCurrentProcess() {
34 if (!updatable) 38 if (!updatable)
35 return MakeResult<VirtualFile>(file); 39 return MakeResult<VirtualFile>(file);
36 40
37 const PatchManager patch_manager(Core::CurrentProcess()->GetTitleID()); 41 const PatchManager patch_manager(Core::CurrentProcess()->GetTitleID());
38 return MakeResult<VirtualFile>(patch_manager.PatchRomFS(file, ivfc_offset)); 42 return MakeResult<VirtualFile>(
43 patch_manager.PatchRomFS(file, ivfc_offset, ContentRecordType::Program, update_raw));
39} 44}
40 45
41ResultVal<VirtualFile> RomFSFactory::Open(u64 title_id, StorageId storage, ContentRecordType type) { 46ResultVal<VirtualFile> RomFSFactory::Open(u64 title_id, StorageId storage, ContentRecordType type) {
diff --git a/src/core/file_sys/romfs_factory.h b/src/core/file_sys/romfs_factory.h
index 2cace8180..7724c0b23 100644
--- a/src/core/file_sys/romfs_factory.h
+++ b/src/core/file_sys/romfs_factory.h
@@ -32,11 +32,13 @@ public:
32 explicit RomFSFactory(Loader::AppLoader& app_loader); 32 explicit RomFSFactory(Loader::AppLoader& app_loader);
33 ~RomFSFactory(); 33 ~RomFSFactory();
34 34
35 void SetPackedUpdate(VirtualFile update_raw);
35 ResultVal<VirtualFile> OpenCurrentProcess(); 36 ResultVal<VirtualFile> OpenCurrentProcess();
36 ResultVal<VirtualFile> Open(u64 title_id, StorageId storage, ContentRecordType type); 37 ResultVal<VirtualFile> Open(u64 title_id, StorageId storage, ContentRecordType type);
37 38
38private: 39private:
39 VirtualFile file; 40 VirtualFile file;
41 VirtualFile update_raw;
40 bool updatable; 42 bool updatable;
41 u64 ivfc_offset; 43 u64 ivfc_offset;
42}; 44};
diff --git a/src/core/file_sys/submission_package.cpp b/src/core/file_sys/submission_package.cpp
index 09bf077cd..ab5dc900c 100644
--- a/src/core/file_sys/submission_package.cpp
+++ b/src/core/file_sys/submission_package.cpp
@@ -259,8 +259,11 @@ void NSP::ReadNCAs(const std::vector<VirtualFile>& files) {
259 auto next_nca = std::make_shared<NCA>(next_file); 259 auto next_nca = std::make_shared<NCA>(next_file);
260 if (next_nca->GetType() == NCAContentType::Program) 260 if (next_nca->GetType() == NCAContentType::Program)
261 program_status[cnmt.GetTitleID()] = next_nca->GetStatus(); 261 program_status[cnmt.GetTitleID()] = next_nca->GetStatus();
262 if (next_nca->GetStatus() == Loader::ResultStatus::Success) 262 if (next_nca->GetStatus() == Loader::ResultStatus::Success ||
263 (next_nca->GetStatus() == Loader::ResultStatus::ErrorMissingBKTRBaseRomFS &&
264 (cnmt.GetTitleID() & 0x800) != 0)) {
263 ncas_title[rec.type] = std::move(next_nca); 265 ncas_title[rec.type] = std::move(next_nca);
266 }
264 } 267 }
265 268
266 break; 269 break;
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp
index aed2abb71..439e62d27 100644
--- a/src/core/hle/service/filesystem/filesystem.cpp
+++ b/src/core/hle/service/filesystem/filesystem.cpp
@@ -264,6 +264,15 @@ ResultCode RegisterBIS(std::unique_ptr<FileSys::BISFactory>&& factory) {
264 return RESULT_SUCCESS; 264 return RESULT_SUCCESS;
265} 265}
266 266
267void SetPackedUpdate(FileSys::VirtualFile update_raw) {
268 LOG_TRACE(Service_FS, "Setting packed update for romfs");
269
270 if (romfs_factory == nullptr)
271 return;
272
273 romfs_factory->SetPackedUpdate(std::move(update_raw));
274}
275
267ResultVal<FileSys::VirtualFile> OpenRomFSCurrentProcess() { 276ResultVal<FileSys::VirtualFile> OpenRomFSCurrentProcess() {
268 LOG_TRACE(Service_FS, "Opening RomFS for current process"); 277 LOG_TRACE(Service_FS, "Opening RomFS for current process");
269 278
diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h
index 7039a2247..53b01bb01 100644
--- a/src/core/hle/service/filesystem/filesystem.h
+++ b/src/core/hle/service/filesystem/filesystem.h
@@ -39,6 +39,7 @@ ResultCode RegisterSaveData(std::unique_ptr<FileSys::SaveDataFactory>&& factory)
39ResultCode RegisterSDMC(std::unique_ptr<FileSys::SDMCFactory>&& factory); 39ResultCode RegisterSDMC(std::unique_ptr<FileSys::SDMCFactory>&& factory);
40ResultCode RegisterBIS(std::unique_ptr<FileSys::BISFactory>&& factory); 40ResultCode RegisterBIS(std::unique_ptr<FileSys::BISFactory>&& factory);
41 41
42void SetPackedUpdate(FileSys::VirtualFile update_raw);
42ResultVal<FileSys::VirtualFile> OpenRomFSCurrentProcess(); 43ResultVal<FileSys::VirtualFile> OpenRomFSCurrentProcess();
43ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id, FileSys::StorageId storage_id, 44ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id, FileSys::StorageId storage_id,
44 FileSys::ContentRecordType type); 45 FileSys::ContentRecordType type);
diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp
index f2a183ba1..91659ec17 100644
--- a/src/core/loader/loader.cpp
+++ b/src/core/loader/loader.cpp
@@ -93,7 +93,7 @@ std::string GetFileTypeString(FileType type) {
93 return "unknown"; 93 return "unknown";
94} 94}
95 95
96constexpr std::array<const char*, 58> RESULT_MESSAGES{ 96constexpr std::array<const char*, 59> RESULT_MESSAGES{
97 "The operation completed successfully.", 97 "The operation completed successfully.",
98 "The loader requested to load is already loaded.", 98 "The loader requested to load is already loaded.",
99 "The operation is not implemented.", 99 "The operation is not implemented.",
@@ -152,6 +152,7 @@ constexpr std::array<const char*, 58> RESULT_MESSAGES{
152 "The BKTR-type NCA has a bad Relocation bucket.", 152 "The BKTR-type NCA has a bad Relocation bucket.",
153 "The BKTR-type NCA has a bad Subsection bucket.", 153 "The BKTR-type NCA has a bad Subsection bucket.",
154 "The BKTR-type NCA is missing the base RomFS.", 154 "The BKTR-type NCA is missing the base RomFS.",
155 "The NSP or XCI does not contain an update in addition to the base game.",
155}; 156};
156 157
157std::ostream& operator<<(std::ostream& os, ResultStatus status) { 158std::ostream& operator<<(std::ostream& os, ResultStatus status) {
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h
index 20e66109b..0e0333db5 100644
--- a/src/core/loader/loader.h
+++ b/src/core/loader/loader.h
@@ -114,6 +114,7 @@ enum class ResultStatus : u16 {
114 ErrorBadRelocationBuckets, 114 ErrorBadRelocationBuckets,
115 ErrorBadSubsectionBuckets, 115 ErrorBadSubsectionBuckets,
116 ErrorMissingBKTRBaseRomFS, 116 ErrorMissingBKTRBaseRomFS,
117 ErrorNoPackedUpdate,
117}; 118};
118 119
119std::ostream& operator<<(std::ostream& os, ResultStatus status); 120std::ostream& operator<<(std::ostream& os, ResultStatus status);
@@ -196,10 +197,19 @@ public:
196 /** 197 /**
197 * Get the RomFS of the application 198 * Get the RomFS of the application
198 * Since the RomFS can be huge, we return a file reference instead of copying to a buffer 199 * Since the RomFS can be huge, we return a file reference instead of copying to a buffer
199 * @param dir The directory containing the RomFS 200 * @param file The directory containing the RomFS
200 * @return ResultStatus result of function 201 * @return ResultStatus result of function
201 */ 202 */
202 virtual ResultStatus ReadRomFS(FileSys::VirtualFile& dir) { 203 virtual ResultStatus ReadRomFS(FileSys::VirtualFile& file) {
204 return ResultStatus::ErrorNotImplemented;
205 }
206
207 /**
208 * Get the raw update of the application, should it come packed with one
209 * @param file The raw update NCA file (Program-type
210 * @return ResultStatus result of function
211 */
212 virtual ResultStatus ReadUpdateRaw(FileSys::VirtualFile& file) {
203 return ResultStatus::ErrorNotImplemented; 213 return ResultStatus::ErrorNotImplemented;
204 } 214 }
205 215
diff --git a/src/core/loader/nax.cpp b/src/core/loader/nax.cpp
index 073fb9d2f..42f4a777b 100644
--- a/src/core/loader/nax.cpp
+++ b/src/core/loader/nax.cpp
@@ -72,6 +72,10 @@ ResultStatus AppLoader_NAX::ReadRomFS(FileSys::VirtualFile& dir) {
72 return nca_loader->ReadRomFS(dir); 72 return nca_loader->ReadRomFS(dir);
73} 73}
74 74
75u64 AppLoader_NAX::ReadRomFSIVFCOffset() const {
76 return nca_loader->ReadRomFSIVFCOffset();
77}
78
75ResultStatus AppLoader_NAX::ReadProgramId(u64& out_program_id) { 79ResultStatus AppLoader_NAX::ReadProgramId(u64& out_program_id) {
76 return nca_loader->ReadProgramId(out_program_id); 80 return nca_loader->ReadProgramId(out_program_id);
77} 81}
diff --git a/src/core/loader/nax.h b/src/core/loader/nax.h
index fc3c01876..b4d93bd01 100644
--- a/src/core/loader/nax.h
+++ b/src/core/loader/nax.h
@@ -36,6 +36,7 @@ public:
36 ResultStatus Load(Kernel::Process& process) override; 36 ResultStatus Load(Kernel::Process& process) override;
37 37
38 ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; 38 ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override;
39 u64 ReadRomFSIVFCOffset() const override;
39 ResultStatus ReadProgramId(u64& out_program_id) override; 40 ResultStatus ReadProgramId(u64& out_program_id) override;
40 41
41private: 42private:
diff --git a/src/core/loader/nsp.cpp b/src/core/loader/nsp.cpp
index b7ba77ef4..5534ce01c 100644
--- a/src/core/loader/nsp.cpp
+++ b/src/core/loader/nsp.cpp
@@ -10,8 +10,10 @@
10#include "core/file_sys/control_metadata.h" 10#include "core/file_sys/control_metadata.h"
11#include "core/file_sys/nca_metadata.h" 11#include "core/file_sys/nca_metadata.h"
12#include "core/file_sys/patch_manager.h" 12#include "core/file_sys/patch_manager.h"
13#include "core/file_sys/registered_cache.h"
13#include "core/file_sys/submission_package.h" 14#include "core/file_sys/submission_package.h"
14#include "core/hle/kernel/process.h" 15#include "core/hle/kernel/process.h"
16#include "core/hle/service/filesystem/filesystem.h"
15#include "core/loader/deconstructed_rom_directory.h" 17#include "core/loader/deconstructed_rom_directory.h"
16#include "core/loader/nca.h" 18#include "core/loader/nca.h"
17#include "core/loader/nsp.h" 19#include "core/loader/nsp.h"
@@ -91,13 +93,39 @@ ResultStatus AppLoader_NSP::Load(Kernel::Process& process) {
91 if (result != ResultStatus::Success) 93 if (result != ResultStatus::Success)
92 return result; 94 return result;
93 95
96 FileSys::VirtualFile update_raw;
97 if (ReadUpdateRaw(update_raw) == ResultStatus::Success && update_raw != nullptr)
98 Service::FileSystem::SetPackedUpdate(std::move(update_raw));
99
94 is_loaded = true; 100 is_loaded = true;
95 101
96 return ResultStatus::Success; 102 return ResultStatus::Success;
97} 103}
98 104
99ResultStatus AppLoader_NSP::ReadRomFS(FileSys::VirtualFile& dir) { 105ResultStatus AppLoader_NSP::ReadRomFS(FileSys::VirtualFile& file) {
100 return secondary_loader->ReadRomFS(dir); 106 return secondary_loader->ReadRomFS(file);
107}
108
109u64 AppLoader_NSP::ReadRomFSIVFCOffset() const {
110 return secondary_loader->ReadRomFSIVFCOffset();
111}
112
113ResultStatus AppLoader_NSP::ReadUpdateRaw(FileSys::VirtualFile& file) {
114 if (nsp->IsExtractedType())
115 return ResultStatus::ErrorNoPackedUpdate;
116
117 const auto read =
118 nsp->GetNCAFile(FileSys::GetUpdateTitleID(title_id), FileSys::ContentRecordType::Program);
119
120 if (read == nullptr)
121 return ResultStatus::ErrorNoPackedUpdate;
122 const auto nca_test = std::make_shared<FileSys::NCA>(read);
123
124 if (nca_test->GetStatus() != ResultStatus::ErrorMissingBKTRBaseRomFS)
125 return nca_test->GetStatus();
126
127 file = read;
128 return ResultStatus::Success;
101} 129}
102 130
103ResultStatus AppLoader_NSP::ReadProgramId(u64& out_program_id) { 131ResultStatus AppLoader_NSP::ReadProgramId(u64& out_program_id) {
diff --git a/src/core/loader/nsp.h b/src/core/loader/nsp.h
index eac9b819a..b006594a6 100644
--- a/src/core/loader/nsp.h
+++ b/src/core/loader/nsp.h
@@ -37,7 +37,9 @@ public:
37 37
38 ResultStatus Load(Kernel::Process& process) override; 38 ResultStatus Load(Kernel::Process& process) override;
39 39
40 ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; 40 ResultStatus ReadRomFS(FileSys::VirtualFile& file) override;
41 u64 ReadRomFSIVFCOffset() const override;
42 ResultStatus ReadUpdateRaw(FileSys::VirtualFile& file) override;
41 ResultStatus ReadProgramId(u64& out_program_id) override; 43 ResultStatus ReadProgramId(u64& out_program_id) override;
42 ResultStatus ReadIcon(std::vector<u8>& buffer) override; 44 ResultStatus ReadIcon(std::vector<u8>& buffer) override;
43 ResultStatus ReadTitle(std::string& title) override; 45 ResultStatus ReadTitle(std::string& title) override;
diff --git a/src/core/loader/xci.cpp b/src/core/loader/xci.cpp
index eda67a8c8..ee5452eb9 100644
--- a/src/core/loader/xci.cpp
+++ b/src/core/loader/xci.cpp
@@ -9,7 +9,11 @@
9#include "core/file_sys/content_archive.h" 9#include "core/file_sys/content_archive.h"
10#include "core/file_sys/control_metadata.h" 10#include "core/file_sys/control_metadata.h"
11#include "core/file_sys/patch_manager.h" 11#include "core/file_sys/patch_manager.h"
12#include "core/file_sys/registered_cache.h"
13#include "core/file_sys/romfs.h"
14#include "core/file_sys/submission_package.h"
12#include "core/hle/kernel/process.h" 15#include "core/hle/kernel/process.h"
16#include "core/hle/service/filesystem/filesystem.h"
13#include "core/loader/nca.h" 17#include "core/loader/nca.h"
14#include "core/loader/xci.h" 18#include "core/loader/xci.h"
15 19
@@ -63,13 +67,41 @@ ResultStatus AppLoader_XCI::Load(Kernel::Process& process) {
63 if (result != ResultStatus::Success) 67 if (result != ResultStatus::Success)
64 return result; 68 return result;
65 69
70 FileSys::VirtualFile update_raw;
71 if (ReadUpdateRaw(update_raw) == ResultStatus::Success && update_raw != nullptr)
72 Service::FileSystem::SetPackedUpdate(std::move(update_raw));
73
66 is_loaded = true; 74 is_loaded = true;
67 75
68 return ResultStatus::Success; 76 return ResultStatus::Success;
69} 77}
70 78
71ResultStatus AppLoader_XCI::ReadRomFS(FileSys::VirtualFile& dir) { 79ResultStatus AppLoader_XCI::ReadRomFS(FileSys::VirtualFile& file) {
72 return nca_loader->ReadRomFS(dir); 80 return nca_loader->ReadRomFS(file);
81}
82
83u64 AppLoader_XCI::ReadRomFSIVFCOffset() const {
84 return nca_loader->ReadRomFSIVFCOffset();
85}
86
87ResultStatus AppLoader_XCI::ReadUpdateRaw(FileSys::VirtualFile& file) {
88 u64 program_id{};
89 nca_loader->ReadProgramId(program_id);
90 if (program_id == 0)
91 return ResultStatus::ErrorXCIMissingProgramNCA;
92
93 const auto read = xci->GetSecurePartitionNSP()->GetNCAFile(
94 FileSys::GetUpdateTitleID(program_id), FileSys::ContentRecordType::Program);
95
96 if (read == nullptr)
97 return ResultStatus::ErrorNoPackedUpdate;
98 const auto nca_test = std::make_shared<FileSys::NCA>(read);
99
100 if (nca_test->GetStatus() != ResultStatus::ErrorMissingBKTRBaseRomFS)
101 return nca_test->GetStatus();
102
103 file = read;
104 return ResultStatus::Success;
73} 105}
74 106
75ResultStatus AppLoader_XCI::ReadProgramId(u64& out_program_id) { 107ResultStatus AppLoader_XCI::ReadProgramId(u64& out_program_id) {
diff --git a/src/core/loader/xci.h b/src/core/loader/xci.h
index 17e47b658..770ed1437 100644
--- a/src/core/loader/xci.h
+++ b/src/core/loader/xci.h
@@ -37,7 +37,9 @@ public:
37 37
38 ResultStatus Load(Kernel::Process& process) override; 38 ResultStatus Load(Kernel::Process& process) override;
39 39
40 ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; 40 ResultStatus ReadRomFS(FileSys::VirtualFile& file) override;
41 u64 ReadRomFSIVFCOffset() const override;
42 ResultStatus ReadUpdateRaw(FileSys::VirtualFile& file) override;
41 ResultStatus ReadProgramId(u64& out_program_id) override; 43 ResultStatus ReadProgramId(u64& out_program_id) override;
42 ResultStatus ReadIcon(std::vector<u8>& buffer) override; 44 ResultStatus ReadIcon(std::vector<u8>& buffer) override;
43 ResultStatus ReadTitle(std::string& title) override; 45 ResultStatus ReadTitle(std::string& title) override;
diff --git a/src/yuzu/game_list_worker.cpp b/src/yuzu/game_list_worker.cpp
index 1947bdb93..d2b3de683 100644
--- a/src/yuzu/game_list_worker.cpp
+++ b/src/yuzu/game_list_worker.cpp
@@ -57,16 +57,25 @@ QString FormatGameName(const std::string& physical_name) {
57 return physical_name_as_qstring; 57 return physical_name_as_qstring;
58} 58}
59 59
60QString FormatPatchNameVersions(const FileSys::PatchManager& patch_manager, bool updatable = true) { 60QString FormatPatchNameVersions(const FileSys::PatchManager& patch_manager,
61 Loader::AppLoader& loader, bool updatable = true) {
61 QString out; 62 QString out;
62 for (const auto& kv : patch_manager.GetPatchVersionNames()) { 63 FileSys::VirtualFile update_raw;
64 loader.ReadUpdateRaw(update_raw);
65 for (const auto& kv : patch_manager.GetPatchVersionNames(update_raw)) {
63 if (!updatable && kv.first == "Update") 66 if (!updatable && kv.first == "Update")
64 continue; 67 continue;
65 68
66 if (kv.second.empty()) { 69 if (kv.second.empty()) {
67 out.append(fmt::format("{}\n", kv.first).c_str()); 70 out.append(fmt::format("{}\n", kv.first).c_str());
68 } else { 71 } else {
69 out.append(fmt::format("{} ({})\n", kv.first, kv.second).c_str()); 72 auto ver = kv.second;
73
74 // Display container name for packed updates
75 if (ver == "PACKED" && kv.first == "Update")
76 ver = Loader::GetFileTypeString(loader.GetFileType());
77
78 out.append(fmt::format("{} ({})\n", kv.first, ver).c_str());
70 } 79 }
71 } 80 }
72 81
@@ -116,7 +125,7 @@ void GameListWorker::AddInstalledTitlesToGameList() {
116 QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType())), 125 QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType())),
117 program_id), 126 program_id),
118 new GameListItemCompat(compatibility), 127 new GameListItemCompat(compatibility),
119 new GameListItem(FormatPatchNameVersions(patch)), 128 new GameListItem(FormatPatchNameVersions(patch, *loader)),
120 new GameListItem( 129 new GameListItem(
121 QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType()))), 130 QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType()))),
122 new GameListItemSize(file->GetSize()), 131 new GameListItemSize(file->GetSize()),
@@ -206,7 +215,8 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsign
206 QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType())), 215 QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType())),
207 program_id), 216 program_id),
208 new GameListItemCompat(compatibility), 217 new GameListItemCompat(compatibility),
209 new GameListItem(FormatPatchNameVersions(patch, loader->IsRomFSUpdatable())), 218 new GameListItem(
219 FormatPatchNameVersions(patch, *loader, loader->IsRomFSUpdatable())),
210 new GameListItem( 220 new GameListItem(
211 QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType()))), 221 QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType()))),
212 new GameListItemSize(FileUtil::GetSize(physical_name)), 222 new GameListItemSize(FileUtil::GetSize(physical_name)),