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
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) {
+8
View File
@@ -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
View File
@@ -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
View File
@@ -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);
+14 -7
View File
@@ -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
+9
View File
@@ -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;