Fix DLCs not imported correctly, fix progress not reported correctly

This commit is contained in:
zhupengfei
2019-10-04 15:45:39 +08:00
parent 2efa44f751
commit cd5eccd32a
6 changed files with 61 additions and 22 deletions
+5 -1
View File
@@ -49,6 +49,10 @@ std::array<u8, 16> GetFileCTR(const std::string& path) {
} }
} // namespace } // 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, bool SDMCDecryptor::DecryptAndWriteFile(const std::string& source, const std::string& destination,
const QuickDecryptor::ProgressCallback& callback) { const QuickDecryptor::ProgressCallback& callback) {
return quick_decryptor.DecryptAndWriteFile(source, destination, callback); return quick_decryptor.DecryptAndWriteFile(source, destination, callback);
@@ -83,7 +87,7 @@ std::vector<u8> SDMCDecryptor::DecryptFile(const std::string& source) const {
return data; return data;
} }
SDMCFile::SDMCFile() {} SDMCFile::SDMCFile() = default;
SDMCFile::SDMCFile(std::string root_folder, const std::string& filename, const char openmode[], SDMCFile::SDMCFile(std::string root_folder, const std::string& filename, const char openmode[],
int flags) { int flags) {
+8
View File
@@ -41,6 +41,14 @@ public:
*/ */
std::vector<u8> DecryptFile(const std::string& source) const; 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: private:
std::string root_folder; std::string root_folder;
QuickDecryptor quick_decryptor; QuickDecryptor quick_decryptor;
+24 -13
View File
@@ -67,7 +67,7 @@ bool SDMCImporter::ImportContent(const ContentSpecifier& specifier,
case ContentType::Application: case ContentType::Application:
case ContentType::Update: case ContentType::Update:
case ContentType::DLC: case ContentType::DLC:
return ImportTitle(specifier.id, callback); return ImportTitle(specifier, callback);
case ContentType::Savegame: case ContentType::Savegame:
return ImportSavegame(specifier.id, callback); return ImportSavegame(specifier.id, callback);
case ContentType::Extdata: case ContentType::Extdata:
@@ -81,23 +81,34 @@ bool SDMCImporter::ImportContent(const ContentSpecifier& specifier,
} }
} }
bool SDMCImporter::ImportTitle(u64 id, const ProgressCallback& callback) { bool SDMCImporter::ImportTitle(const ContentSpecifier& specifier,
const auto path = fmt::format("title/{:08x}/{:08x}/content/", (id >> 32), (id & 0xFFFFFFFF)); const ProgressCallback& callback) {
return FileUtil::ForeachDirectoryEntry( decryptor->Reset(specifier.maximum_size);
nullptr, config.sdmc_path + path, const FileUtil::DirectoryEntryCallable DirectoryEntryCallback =
[this, &path, callback](u64* /*num_entries_out*/, const std::string& directory, [this, size = config.sdmc_path.size(), callback,
const std::string& virtual_name) { &DirectoryEntryCallback](u64* /*num_entries_out*/, const std::string& directory,
if (FileUtil::IsDirectory(directory + virtual_name)) { const std::string& virtual_name) {
return true; 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( return decryptor->DecryptAndWriteFile(
"/" + path + virtual_name, filepath,
FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir) + FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir) +
"Nintendo " "Nintendo "
"3DS/00000000000000000000000000000000/00000000000000000000000000000000/" + "3DS/00000000000000000000000000000000/00000000000000000000000000000000" +
path + virtual_name, filepath,
callback); 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) { bool SDMCImporter::ImportSavegame(u64 id, [[maybe_unused]] const ProgressCallback& callback) {
+1 -1
View File
@@ -108,7 +108,7 @@ public:
private: private:
bool Init(); 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 ImportSavegame(u64 id, const ProgressCallback& callback);
bool ImportExtdata(u64 id, const ProgressCallback& callback); bool ImportExtdata(u64 id, const ProgressCallback& callback);
bool ImportSystemArchive(u64 id, const ProgressCallback& callback); bool ImportSystemArchive(u64 id, const ProgressCallback& callback);
+14 -7
View File
@@ -74,8 +74,8 @@ bool QuickDecryptor::DecryptAndWriteFile(const std::string& source_,
destination = destination_; destination = destination_;
callback = callback_; callback = callback_;
total_size = FileUtil::GetSize(root_folder + source); current_total_size = FileUtil::GetSize(root_folder + source);
if (total_size == 0) { if (current_total_size == 0) {
LOG_ERROR(Core, "Could not open file {}", root_folder + source); LOG_ERROR(Core, "Could not open file {}", root_folder + source);
return false; return false;
} }
@@ -109,7 +109,7 @@ void QuickDecryptor::DataReadLoop() {
return; return;
} }
std::size_t file_size = total_size; std::size_t file_size = current_total_size;
while (is_running && file_size > 0) { while (is_running && file_size > 0) {
if (is_first_run) { if (is_first_run) {
@@ -140,7 +140,7 @@ void QuickDecryptor::DataDecryptLoop() {
aes.SetKeyWithIV(key.data(), key.size(), ctr.data()); aes.SetKeyWithIV(key.data(), key.size(), ctr.data());
std::size_t current_buffer = 0; 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) { while (is_running && file_size > 0) {
data_read_event[current_buffer].Wait(); data_read_event[current_buffer].Wait();
@@ -166,17 +166,18 @@ void QuickDecryptor::DataWriteLoop() {
return; return;
} }
std::size_t file_size = total_size; std::size_t file_size = current_total_size;
std::size_t iteration = 0; std::size_t iteration = 0;
/// The number of iterations each progress report covers. 32 * 16K = 512K /// The number of iterations each progress report covers. 32 * 16K = 512K
constexpr std::size_t ProgressReportFreq = 32; constexpr std::size_t ProgressReportFreq = 32;
while (is_running && file_size > 0) { while (is_running && file_size > 0) {
iteration++;
if (iteration % ProgressReportFreq == 0) { if (iteration % ProgressReportFreq == 0) {
callback(iteration * BufferSize, total_size); callback(imported_size, total_size);
} }
iteration++;
data_decrypted_event[current_buffer].Wait(); data_decrypted_event[current_buffer].Wait();
const auto bytes_to_write = std::min(BufferSize, file_size); const auto bytes_to_write = std::min(BufferSize, file_size);
@@ -186,6 +187,7 @@ void QuickDecryptor::DataWriteLoop() {
return; return;
} }
file_size -= bytes_to_write; file_size -= bytes_to_write;
imported_size += bytes_to_write;
data_written_event[current_buffer].Set(); data_written_event[current_buffer].Set();
current_buffer = (current_buffer + 1) % buffers.size(); 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 } // namespace Core
+9
View File
@@ -35,13 +35,22 @@ public:
void Abort(); void Abort();
/// Reset the imported_size counter for this content and set a new total_size.
void Reset(std::size_t total_size);
private: private:
static constexpr std::size_t BufferSize = 16 * 1024; // 16 KB static constexpr std::size_t BufferSize = 16 * 1024; // 16 KB
std::string root_folder; std::string root_folder;
std::string source; std::string source;
std::string destination; std::string destination;
// Total size of this content, may consist of multiple files
std::size_t total_size{}; 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<std::array<u8, BufferSize>, 3> buffers;
std::array<Common::Event, 3> data_read_event; std::array<Common::Event, 3> data_read_event;