mirror of
https://github.com/Dark98/threeSD.git
synced 2026-07-02 16:49:04 +00:00
Fix DLCs not imported correctly, fix progress not reported correctly
This commit is contained in:
@@ -49,6 +49,10 @@ std::array<u8, 16> GetFileCTR(const std::string& path) {
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void SDMCDecryptor::Reset(std::size_t total_size) {
|
||||
quick_decryptor.Reset(total_size);
|
||||
}
|
||||
|
||||
bool SDMCDecryptor::DecryptAndWriteFile(const std::string& source, const std::string& destination,
|
||||
const QuickDecryptor::ProgressCallback& callback) {
|
||||
return quick_decryptor.DecryptAndWriteFile(source, destination, callback);
|
||||
@@ -83,7 +87,7 @@ std::vector<u8> SDMCDecryptor::DecryptFile(const std::string& source) const {
|
||||
return data;
|
||||
}
|
||||
|
||||
SDMCFile::SDMCFile() {}
|
||||
SDMCFile::SDMCFile() = default;
|
||||
|
||||
SDMCFile::SDMCFile(std::string root_folder, const std::string& filename, const char openmode[],
|
||||
int flags) {
|
||||
|
||||
@@ -41,6 +41,14 @@ public:
|
||||
*/
|
||||
std::vector<u8> DecryptFile(const std::string& source) const;
|
||||
|
||||
/**
|
||||
* Marks the beginning of a new content, resetting imported_size counter, and setting an new
|
||||
* total_size for the next content.
|
||||
* This doesn't affect at all how the contents will be imported, but will make sure the callback
|
||||
* is properly invoked.
|
||||
*/
|
||||
void Reset(std::size_t total_size);
|
||||
|
||||
private:
|
||||
std::string root_folder;
|
||||
QuickDecryptor quick_decryptor;
|
||||
|
||||
+24
-13
@@ -67,7 +67,7 @@ bool SDMCImporter::ImportContent(const ContentSpecifier& specifier,
|
||||
case ContentType::Application:
|
||||
case ContentType::Update:
|
||||
case ContentType::DLC:
|
||||
return ImportTitle(specifier.id, callback);
|
||||
return ImportTitle(specifier, callback);
|
||||
case ContentType::Savegame:
|
||||
return ImportSavegame(specifier.id, callback);
|
||||
case ContentType::Extdata:
|
||||
@@ -81,23 +81,34 @@ bool SDMCImporter::ImportContent(const ContentSpecifier& specifier,
|
||||
}
|
||||
}
|
||||
|
||||
bool SDMCImporter::ImportTitle(u64 id, const ProgressCallback& callback) {
|
||||
const auto path = fmt::format("title/{:08x}/{:08x}/content/", (id >> 32), (id & 0xFFFFFFFF));
|
||||
return FileUtil::ForeachDirectoryEntry(
|
||||
nullptr, config.sdmc_path + path,
|
||||
[this, &path, callback](u64* /*num_entries_out*/, const std::string& directory,
|
||||
const std::string& virtual_name) {
|
||||
if (FileUtil::IsDirectory(directory + virtual_name)) {
|
||||
return true;
|
||||
bool SDMCImporter::ImportTitle(const ContentSpecifier& specifier,
|
||||
const ProgressCallback& callback) {
|
||||
decryptor->Reset(specifier.maximum_size);
|
||||
const FileUtil::DirectoryEntryCallable DirectoryEntryCallback =
|
||||
[this, size = config.sdmc_path.size(), callback,
|
||||
&DirectoryEntryCallback](u64* /*num_entries_out*/, const std::string& directory,
|
||||
const std::string& virtual_name) {
|
||||
if (FileUtil::IsDirectory(directory + virtual_name + "/")) {
|
||||
if (virtual_name == "cmd") {
|
||||
return true; // Skip cmd (not used in Citra)
|
||||
}
|
||||
// Recursive call (necessary for DLCs)
|
||||
return FileUtil::ForeachDirectoryEntry(nullptr, directory + virtual_name + "/",
|
||||
DirectoryEntryCallback);
|
||||
}
|
||||
const auto filepath = (directory + virtual_name).substr(size - 1);
|
||||
return decryptor->DecryptAndWriteFile(
|
||||
"/" + path + virtual_name,
|
||||
filepath,
|
||||
FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir) +
|
||||
"Nintendo "
|
||||
"3DS/00000000000000000000000000000000/00000000000000000000000000000000/" +
|
||||
path + virtual_name,
|
||||
"3DS/00000000000000000000000000000000/00000000000000000000000000000000" +
|
||||
filepath,
|
||||
callback);
|
||||
});
|
||||
};
|
||||
const auto path = fmt::format("title/{:08x}/{:08x}/content/", (specifier.id >> 32),
|
||||
(specifier.id & 0xFFFFFFFF));
|
||||
return FileUtil::ForeachDirectoryEntry(nullptr, config.sdmc_path + path,
|
||||
DirectoryEntryCallback);
|
||||
}
|
||||
|
||||
bool SDMCImporter::ImportSavegame(u64 id, [[maybe_unused]] const ProgressCallback& callback) {
|
||||
|
||||
+1
-1
@@ -108,7 +108,7 @@ public:
|
||||
private:
|
||||
bool Init();
|
||||
|
||||
bool ImportTitle(u64 id, const ProgressCallback& callback);
|
||||
bool ImportTitle(const ContentSpecifier& specifier, const ProgressCallback& callback);
|
||||
bool ImportSavegame(u64 id, const ProgressCallback& callback);
|
||||
bool ImportExtdata(u64 id, const ProgressCallback& callback);
|
||||
bool ImportSystemArchive(u64 id, const ProgressCallback& callback);
|
||||
|
||||
@@ -74,8 +74,8 @@ bool QuickDecryptor::DecryptAndWriteFile(const std::string& source_,
|
||||
destination = destination_;
|
||||
callback = callback_;
|
||||
|
||||
total_size = FileUtil::GetSize(root_folder + source);
|
||||
if (total_size == 0) {
|
||||
current_total_size = FileUtil::GetSize(root_folder + source);
|
||||
if (current_total_size == 0) {
|
||||
LOG_ERROR(Core, "Could not open file {}", root_folder + source);
|
||||
return false;
|
||||
}
|
||||
@@ -109,7 +109,7 @@ void QuickDecryptor::DataReadLoop() {
|
||||
return;
|
||||
}
|
||||
|
||||
std::size_t file_size = total_size;
|
||||
std::size_t file_size = current_total_size;
|
||||
|
||||
while (is_running && file_size > 0) {
|
||||
if (is_first_run) {
|
||||
@@ -140,7 +140,7 @@ void QuickDecryptor::DataDecryptLoop() {
|
||||
aes.SetKeyWithIV(key.data(), key.size(), ctr.data());
|
||||
|
||||
std::size_t current_buffer = 0;
|
||||
std::size_t file_size = total_size;
|
||||
std::size_t file_size = current_total_size;
|
||||
|
||||
while (is_running && file_size > 0) {
|
||||
data_read_event[current_buffer].Wait();
|
||||
@@ -166,17 +166,18 @@ void QuickDecryptor::DataWriteLoop() {
|
||||
return;
|
||||
}
|
||||
|
||||
std::size_t file_size = total_size;
|
||||
std::size_t file_size = current_total_size;
|
||||
std::size_t iteration = 0;
|
||||
/// The number of iterations each progress report covers. 32 * 16K = 512K
|
||||
constexpr std::size_t ProgressReportFreq = 32;
|
||||
|
||||
while (is_running && file_size > 0) {
|
||||
iteration++;
|
||||
if (iteration % ProgressReportFreq == 0) {
|
||||
callback(iteration * BufferSize, total_size);
|
||||
callback(imported_size, total_size);
|
||||
}
|
||||
|
||||
iteration++;
|
||||
|
||||
data_decrypted_event[current_buffer].Wait();
|
||||
|
||||
const auto bytes_to_write = std::min(BufferSize, file_size);
|
||||
@@ -186,6 +187,7 @@ void QuickDecryptor::DataWriteLoop() {
|
||||
return;
|
||||
}
|
||||
file_size -= bytes_to_write;
|
||||
imported_size += bytes_to_write;
|
||||
|
||||
data_written_event[current_buffer].Set();
|
||||
current_buffer = (current_buffer + 1) % buffers.size();
|
||||
@@ -201,4 +203,9 @@ void QuickDecryptor::Abort() {
|
||||
}
|
||||
}
|
||||
|
||||
void QuickDecryptor::Reset(std::size_t total_size_) {
|
||||
total_size = total_size_;
|
||||
imported_size = 0;
|
||||
}
|
||||
|
||||
} // namespace Core
|
||||
|
||||
@@ -35,13 +35,22 @@ public:
|
||||
|
||||
void Abort();
|
||||
|
||||
/// Reset the imported_size counter for this content and set a new total_size.
|
||||
void Reset(std::size_t total_size);
|
||||
|
||||
private:
|
||||
static constexpr std::size_t BufferSize = 16 * 1024; // 16 KB
|
||||
|
||||
std::string root_folder;
|
||||
std::string source;
|
||||
std::string destination;
|
||||
|
||||
// Total size of this content, may consist of multiple files
|
||||
std::size_t total_size{};
|
||||
// Total size of the current file to process
|
||||
std::size_t current_total_size{};
|
||||
// Total imported size for this content
|
||||
std::size_t imported_size{};
|
||||
|
||||
std::array<std::array<u8, BufferSize>, 3> buffers;
|
||||
std::array<Common::Event, 3> data_read_event;
|
||||
|
||||
Reference in New Issue
Block a user