Unify ProgressCallbacks to a Common::ProgressCallback

This commit is contained in:
Pengfei
2021-06-28 22:50:16 +08:00
parent 5a4bf7daff
commit 2575e7fdde
15 changed files with 69 additions and 46 deletions
+1
View File
@@ -10,6 +10,7 @@ add_library(common STATIC
logging/log.cpp logging/log.cpp
logging/log.h logging/log.h
misc.cpp misc.cpp
progress_callback.h
scope_exit.h scope_exit.h
string_util.cpp string_util.cpp
string_util.h string_util.h
+14
View File
@@ -0,0 +1,14 @@
// Copyright 2021 threeSD Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <functional>
namespace Common {
// (current_size, total_size)
using ProgressCallback = std::function<void(std::size_t, std::size_t)>;
} // namespace Common
+1 -1
View File
@@ -53,7 +53,7 @@ void SDMCDecryptor::Reset(std::size_t 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 ProgressCallback& callback) { const Common::ProgressCallback& callback) {
if (!FileUtil::CreateFullPath(destination)) { if (!FileUtil::CreateFullPath(destination)) {
LOG_ERROR(Core, "Could not create path {}", destination); LOG_ERROR(Core, "Could not create path {}", destination);
return false; return false;
+1 -1
View File
@@ -33,7 +33,7 @@ public:
*/ */
bool DecryptAndWriteFile( bool DecryptAndWriteFile(
const std::string& source, const std::string& destination, const std::string& source, const std::string& destination,
const ProgressCallback& callback = [](std::size_t, std::size_t) {}); const Common::ProgressCallback& callback = [](std::size_t, std::size_t) {});
void Abort(); void Abort();
+17 -11
View File
@@ -69,7 +69,7 @@ void SDMCImporter::AbortImporting() {
} }
bool SDMCImporter::ImportContent(const ContentSpecifier& specifier, bool SDMCImporter::ImportContent(const ContentSpecifier& specifier,
const ProgressCallback& callback) { const Common::ProgressCallback& callback) {
switch (specifier.type) { switch (specifier.type) {
case ContentType::Application: case ContentType::Application:
case ContentType::Update: case ContentType::Update:
@@ -130,7 +130,7 @@ bool ImportTitleGeneric(Dec& decryptor, const std::string& base_path,
} // namespace } // namespace
bool SDMCImporter::ImportTitle(const ContentSpecifier& specifier, bool SDMCImporter::ImportTitle(const ContentSpecifier& specifier,
const ProgressCallback& callback) { const Common::ProgressCallback& callback) {
return ImportTitleGeneric( return ImportTitleGeneric(
*decryptor, config.sdmc_path, specifier, [this, &callback](const std::string& filepath) { *decryptor, config.sdmc_path, specifier, [this, &callback](const std::string& filepath) {
return decryptor->DecryptAndWriteFile( return decryptor->DecryptAndWriteFile(
@@ -144,7 +144,7 @@ bool SDMCImporter::ImportTitle(const ContentSpecifier& specifier,
} }
bool SDMCImporter::ImportNandTitle(const ContentSpecifier& specifier, bool SDMCImporter::ImportNandTitle(const ContentSpecifier& specifier,
const ProgressCallback& callback) { const Common::ProgressCallback& callback) {
const auto base_path = const auto base_path =
config.system_titles_path.substr(0, config.system_titles_path.size() - 6); config.system_titles_path.substr(0, config.system_titles_path.size() - 6);
@@ -167,7 +167,8 @@ bool SDMCImporter::ImportNandTitle(const ContentSpecifier& specifier,
}); });
} }
bool SDMCImporter::ImportSavegame(u64 id, [[maybe_unused]] const ProgressCallback& callback) { bool SDMCImporter::ImportSavegame(u64 id,
[[maybe_unused]] const Common::ProgressCallback& callback) {
const auto path = fmt::format("title/{:08x}/{:08x}/data/", (id >> 32), (id & 0xFFFFFFFF)); const auto path = fmt::format("title/{:08x}/{:08x}/data/", (id >> 32), (id & 0xFFFFFFFF));
DataContainer container(decryptor->DecryptFile(fmt::format("/{}00000001.sav", path))); DataContainer container(decryptor->DecryptFile(fmt::format("/{}00000001.sav", path)));
@@ -190,7 +191,8 @@ bool SDMCImporter::ImportSavegame(u64 id, [[maybe_unused]] const ProgressCallbac
"Nintendo 3DS/00000000000000000000000000000000/00000000000000000000000000000000/" + path); "Nintendo 3DS/00000000000000000000000000000000/00000000000000000000000000000000/" + path);
} }
bool SDMCImporter::ImportNandSavegame(u64 id, [[maybe_unused]] const ProgressCallback& callback) { bool SDMCImporter::ImportNandSavegame(u64 id,
[[maybe_unused]] const Common::ProgressCallback& callback) {
const auto path = fmt::format("sysdata/{:08x}/00000000", (id & 0xFFFFFFFF)); const auto path = fmt::format("sysdata/{:08x}/00000000", (id & 0xFFFFFFFF));
FileUtil::IOFile file(config.nand_data_path + path, "rb"); FileUtil::IOFile file(config.nand_data_path + path, "rb");
@@ -216,7 +218,8 @@ bool SDMCImporter::ImportNandSavegame(u64 id, [[maybe_unused]] const ProgressCal
1); 1);
} }
bool SDMCImporter::ImportExtdata(u64 id, [[maybe_unused]] const ProgressCallback& callback) { bool SDMCImporter::ImportExtdata(u64 id,
[[maybe_unused]] const Common::ProgressCallback& callback) {
const auto path = fmt::format("extdata/{:08x}/{:08x}/", (id >> 32), (id & 0xFFFFFFFF)); const auto path = fmt::format("extdata/{:08x}/{:08x}/", (id >> 32), (id & 0xFFFFFFFF));
SDExtdata extdata("/" + path, *decryptor); SDExtdata extdata("/" + path, *decryptor);
if (!extdata.IsGood()) { if (!extdata.IsGood()) {
@@ -228,7 +231,8 @@ bool SDMCImporter::ImportExtdata(u64 id, [[maybe_unused]] const ProgressCallback
"Nintendo 3DS/00000000000000000000000000000000/00000000000000000000000000000000/" + path); "Nintendo 3DS/00000000000000000000000000000000/00000000000000000000000000000000/" + path);
} }
bool SDMCImporter::ImportNandExtdata(u64 id, [[maybe_unused]] const ProgressCallback& callback) { bool SDMCImporter::ImportNandExtdata(u64 id,
[[maybe_unused]] const Common::ProgressCallback& callback) {
const auto path = fmt::format("extdata/{:08x}/{:08x}/", (id >> 32), (id & 0xFFFFFFFF)); const auto path = fmt::format("extdata/{:08x}/{:08x}/", (id >> 32), (id & 0xFFFFFFFF));
SDExtdata extdata(config.nand_data_path + path); SDExtdata extdata(config.nand_data_path + path);
if (!extdata.IsGood()) { if (!extdata.IsGood()) {
@@ -239,7 +243,8 @@ bool SDMCImporter::ImportNandExtdata(u64 id, [[maybe_unused]] const ProgressCall
"data/00000000000000000000000000000000/" + path); "data/00000000000000000000000000000000/" + path);
} }
bool SDMCImporter::ImportSystemArchive(u64 id, [[maybe_unused]] const ProgressCallback& callback) { bool SDMCImporter::ImportSystemArchive(u64 id,
[[maybe_unused]] const Common::ProgressCallback& callback) {
const auto path = fmt::format("{}{:08x}/{:08x}.app", config.system_archives_path, (id >> 32), const auto path = fmt::format("{}{:08x}/{:08x}.app", config.system_archives_path, (id >> 32),
(id & 0xFFFFFFFF)); (id & 0xFFFFFFFF));
FileUtil::IOFile file(path, "rb"); FileUtil::IOFile file(path, "rb");
@@ -273,7 +278,8 @@ bool SDMCImporter::ImportSystemArchive(u64 id, [[maybe_unused]] const ProgressCa
return true; return true;
} }
bool SDMCImporter::ImportSysdata(u64 id, [[maybe_unused]] const ProgressCallback& callback) { bool SDMCImporter::ImportSysdata(u64 id,
[[maybe_unused]] const Common::ProgressCallback& callback) {
switch (id) { switch (id) {
case 0: { // boot9.bin case 0: { // boot9.bin
const auto target_path = FileUtil::GetUserPath(FileUtil::UserPath::SysDataDir) + BOOTROM9; const auto target_path = FileUtil::GetUserPath(FileUtil::UserPath::SysDataDir) + BOOTROM9;
@@ -500,7 +506,7 @@ TitleData LoadTitleData(NCCHContainer& ncch) {
} }
bool SDMCImporter::DumpCXI(const ContentSpecifier& specifier, const std::string& destination, bool SDMCImporter::DumpCXI(const ContentSpecifier& specifier, const std::string& destination,
const ProgressCallback& callback) { const Common::ProgressCallback& callback) {
if (specifier.type != ContentType::Application) { if (specifier.type != ContentType::Application) {
LOG_ERROR(Core, "Unsupported specifier type {}", static_cast<int>(specifier.type)); LOG_ERROR(Core, "Unsupported specifier type {}", static_cast<int>(specifier.type));
@@ -534,7 +540,7 @@ void SDMCImporter::AbortDumpCXI() {
} }
bool SDMCImporter::BuildCIA(const ContentSpecifier& specifier, const std::string& destination, bool SDMCImporter::BuildCIA(const ContentSpecifier& specifier, const std::string& destination,
const ProgressCallback& callback) { const Common::ProgressCallback& callback) {
if (config.certs_db_path.empty()) { if (config.certs_db_path.empty()) {
LOG_ERROR(Core, "Missing certs.db"); LOG_ERROR(Core, "Missing certs.db");
+13 -14
View File
@@ -9,6 +9,7 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include "common/common_types.h" #include "common/common_types.h"
#include "common/progress_callback.h"
namespace Core { namespace Core {
@@ -96,9 +97,6 @@ class NCCHContainer;
class SDMCImporter { class SDMCImporter {
public: public:
/// (current_size, total_size)
using ProgressCallback = std::function<void(std::size_t, std::size_t)>;
/** /**
* Initializes the importer. * Initializes the importer.
* @param root_folder Path to the "Nintendo 3DS/<ID0>/<ID1>" folder. * @param root_folder Path to the "Nintendo 3DS/<ID0>/<ID1>" folder.
@@ -114,7 +112,7 @@ public:
*/ */
bool ImportContent( bool ImportContent(
const ContentSpecifier& specifier, const ContentSpecifier& specifier,
const ProgressCallback& callback = [](std::size_t, std::size_t) {}); const Common::ProgressCallback& callback = [](std::size_t, std::size_t) {});
/** /**
* Aborts current importing. * Aborts current importing.
@@ -128,7 +126,7 @@ public:
*/ */
bool DumpCXI( bool DumpCXI(
const ContentSpecifier& specifier, const std::string& destination, const ContentSpecifier& specifier, const std::string& destination,
const ProgressCallback& callback = [](std::size_t, std::size_t) {}); const Common::ProgressCallback& callback = [](std::size_t, std::size_t) {});
/** /**
* Aborts current CXI dumping. * Aborts current CXI dumping.
@@ -142,7 +140,7 @@ public:
*/ */
bool BuildCIA( bool BuildCIA(
const ContentSpecifier& specifier, const std::string& destination, const ContentSpecifier& specifier, const std::string& destination,
const ProgressCallback& callback = [](std::size_t, std::size_t) {}); const Common::ProgressCallback& callback = [](std::size_t, std::size_t) {});
/** /**
* Aborts current CIA building * Aborts current CIA building
@@ -168,14 +166,15 @@ public:
private: private:
bool Init(); bool Init();
bool ImportTitle(const ContentSpecifier& specifier, const ProgressCallback& callback); bool ImportTitle(const ContentSpecifier& specifier, const Common::ProgressCallback& callback);
bool ImportNandTitle(const ContentSpecifier& specifier, const ProgressCallback& callback); bool ImportNandTitle(const ContentSpecifier& specifier,
bool ImportSavegame(u64 id, const ProgressCallback& callback); const Common::ProgressCallback& callback);
bool ImportNandSavegame(u64 id, const ProgressCallback& callback); bool ImportSavegame(u64 id, const Common::ProgressCallback& callback);
bool ImportExtdata(u64 id, const ProgressCallback& callback); bool ImportNandSavegame(u64 id, const Common::ProgressCallback& callback);
bool ImportNandExtdata(u64 id, const ProgressCallback& callback); bool ImportExtdata(u64 id, const Common::ProgressCallback& callback);
bool ImportSystemArchive(u64 id, const ProgressCallback& callback); bool ImportNandExtdata(u64 id, const Common::ProgressCallback& callback);
bool ImportSysdata(u64 id, const ProgressCallback& callback); bool ImportSystemArchive(u64 id, const Common::ProgressCallback& callback);
bool ImportSysdata(u64 id, const Common::ProgressCallback& callback);
void ListTitle(std::vector<ContentSpecifier>& out) const; void ListTitle(std::vector<ContentSpecifier>& out) const;
void ListNandTitle(std::vector<ContentSpecifier>& out) const; void ListNandTitle(std::vector<ContentSpecifier>& out) const;
+1 -1
View File
@@ -45,7 +45,7 @@ CIABuilder::~CIABuilder() = default;
bool CIABuilder::Init(const std::string& destination, TitleMetadata tmd_, bool CIABuilder::Init(const std::string& destination, TitleMetadata tmd_,
const std::string& certs_db_path, std::size_t total_size_, const std::string& certs_db_path, std::size_t total_size_,
const ProgressCallback& callback_) { const Common::ProgressCallback& callback_) {
header = {}; header = {};
meta = {}; meta = {};
+3 -2
View File
@@ -8,6 +8,7 @@
#include <mutex> #include <mutex>
#include <string> #include <string>
#include "common/file_util.h" #include "common/file_util.h"
#include "common/progress_callback.h"
#include "common/swap.h" #include "common/swap.h"
#include "core/ncch/ncch_container.h" #include "core/ncch/ncch_container.h"
#include "core/ncch/title_metadata.h" #include "core/ncch/title_metadata.h"
@@ -33,7 +34,7 @@ public:
* @return true on success, false otherwise * @return true on success, false otherwise
*/ */
bool Init(const std::string& destination, TitleMetadata tmd, const std::string& certs_db_path, bool Init(const std::string& destination, TitleMetadata tmd, const std::string& certs_db_path,
std::size_t total_size, const ProgressCallback& callback); std::size_t total_size, const Common::ProgressCallback& callback);
/** /**
* Adds an NCCH content to the CIA. * Adds an NCCH content to the CIA.
@@ -103,7 +104,7 @@ private:
std::shared_ptr<HashedFile> file; std::shared_ptr<HashedFile> file;
std::size_t written{}; // size written (with alignment) std::size_t written{}; // size written (with alignment)
std::size_t total_size{}; std::size_t total_size{};
ProgressCallback callback; Common::ProgressCallback callback;
// The NCCH to abort on // The NCCH to abort on
std::mutex abort_ncch_mutex; std::mutex abort_ncch_mutex;
+1 -1
View File
@@ -423,7 +423,7 @@ ResultStatus NCCHContainer::ReadSeedCrypto(bool& used) {
} }
ResultStatus NCCHContainer::DecryptToFile(std::shared_ptr<FileUtil::IOFile> dest_file, ResultStatus NCCHContainer::DecryptToFile(std::shared_ptr<FileUtil::IOFile> dest_file,
const ProgressCallback& callback) { const Common::ProgressCallback& callback) {
ResultStatus result = Load(); ResultStatus result = Load();
if (result != ResultStatus::Success) if (result != ResultStatus::Success)
return result; return result;
+2 -1
View File
@@ -11,6 +11,7 @@
#include "common/bit_field.h" #include "common/bit_field.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "common/file_util.h" #include "common/file_util.h"
#include "common/progress_callback.h"
#include "common/swap.h" #include "common/swap.h"
#include "core/decryptor.h" #include "core/decryptor.h"
#include "core/result_status.h" #include "core/result_status.h"
@@ -274,7 +275,7 @@ public:
*/ */
ResultStatus DecryptToFile( ResultStatus DecryptToFile(
std::shared_ptr<FileUtil::IOFile> dest_file, std::shared_ptr<FileUtil::IOFile> dest_file,
const ProgressCallback& callback = [](std::size_t, std::size_t) {}); const Common::ProgressCallback& callback = [](std::size_t, std::size_t) {});
/** /**
* Aborts DecryptToFile. Simply aborts the decryptor. * Aborts DecryptToFile. Simply aborts the decryptor.
+1 -1
View File
@@ -23,7 +23,7 @@ QuickDecryptor::~QuickDecryptor() = default;
bool QuickDecryptor::DecryptAndWriteFile(std::shared_ptr<FileUtil::IOFile> source_, bool QuickDecryptor::DecryptAndWriteFile(std::shared_ptr<FileUtil::IOFile> source_,
std::size_t size, std::size_t size,
std::shared_ptr<FileUtil::IOFile> destination_, std::shared_ptr<FileUtil::IOFile> destination_,
const ProgressCallback& callback_, bool decrypt_, const Common::ProgressCallback& callback_, bool decrypt_,
Core::Key::AESKey key_, Core::Key::AESKey ctr_, Core::Key::AESKey key_, Core::Key::AESKey ctr_,
std::size_t aes_seek_pos_) { std::size_t aes_seek_pos_) {
if (is_running) { if (is_running) {
+5 -6
View File
@@ -9,14 +9,12 @@
#include <memory> #include <memory>
#include <string> #include <string>
#include "common/common_types.h" #include "common/common_types.h"
#include "common/progress_callback.h"
#include "common/thread.h" #include "common/thread.h"
#include "core/key/key.h" #include "core/key/key.h"
namespace Core { namespace Core {
/// (current_size, total_size)
using ProgressCallback = std::function<void(std::size_t, std::size_t)>;
/** /**
* Helper that reads, decrypts and writes data. This uses three threads to process the data * Helper that reads, decrypts and writes data. This uses three threads to process the data
* and call progress callbacks occasionally. * and call progress callbacks occasionally.
@@ -41,8 +39,9 @@ public:
bool DecryptAndWriteFile( bool DecryptAndWriteFile(
std::shared_ptr<FileUtil::IOFile> source, std::size_t size, std::shared_ptr<FileUtil::IOFile> source, std::size_t size,
std::shared_ptr<FileUtil::IOFile> destination, std::shared_ptr<FileUtil::IOFile> destination,
const ProgressCallback& callback = [](std::size_t, std::size_t) {}, bool decrypt = false, const Common::ProgressCallback& callback = [](std::size_t, std::size_t) {},
Core::Key::AESKey key = {}, Core::Key::AESKey ctr = {}, std::size_t aes_seek_pos = 0); bool decrypt = false, Core::Key::AESKey key = {}, Core::Key::AESKey ctr = {},
std::size_t aes_seek_pos = 0);
void DataReadLoop(); void DataReadLoop();
void DataDecryptLoop(); void DataDecryptLoop();
@@ -79,7 +78,7 @@ private:
std::unique_ptr<std::thread> decrypt_thread; std::unique_ptr<std::thread> decrypt_thread;
std::unique_ptr<std::thread> write_thread; std::unique_ptr<std::thread> write_thread;
ProgressCallback callback; Common::ProgressCallback callback;
Common::Event completion_event; Common::Event completion_event;
bool is_good{true}; bool is_good{true};
+2 -1
View File
@@ -7,6 +7,7 @@
#include <atomic> #include <atomic>
#include <functional> #include <functional>
#include <QThread> #include <QThread>
#include "common/progress_callback.h"
#include "core/importer.h" #include "core/importer.h"
class MultiJob : public QThread { class MultiJob : public QThread {
@@ -14,7 +15,7 @@ class MultiJob : public QThread {
public: public:
using ExecuteFunc = std::function<bool(Core::SDMCImporter&, const Core::ContentSpecifier&, using ExecuteFunc = std::function<bool(Core::SDMCImporter&, const Core::ContentSpecifier&,
const Core::SDMCImporter::ProgressCallback&)>; const Common::ProgressCallback&)>;
using DeleteFunc = std::function<void(Core::SDMCImporter&, const Core::ContentSpecifier&)>; using DeleteFunc = std::function<void(Core::SDMCImporter&, const Core::ContentSpecifier&)>;
using AbortFunc = std::function<void(Core::SDMCImporter&)>; using AbortFunc = std::function<void(Core::SDMCImporter&)>;
+2 -2
View File
@@ -7,6 +7,7 @@
#include <functional> #include <functional>
#include <QThread> #include <QThread>
#include "common/common_types.h" #include "common/common_types.h"
#include "common/progress_callback.h"
/** /**
* Lightweight wrapper around QThread, for easy use with progressive jobs. * Lightweight wrapper around QThread, for easy use with progressive jobs.
@@ -15,8 +16,7 @@ class SimpleJob : public QThread {
Q_OBJECT Q_OBJECT
public: public:
using ProgressCallback = std::function<void(std::size_t, std::size_t)>; using ExecuteFunc = std::function<bool(const Common::ProgressCallback&)>;
using ExecuteFunc = std::function<bool(const ProgressCallback&)>;
using AbortFunc = std::function<void()>; using AbortFunc = std::function<void()>;
explicit SimpleJob(QObject* parent, ExecuteFunc execute, AbortFunc abort); explicit SimpleJob(QObject* parent, ExecuteFunc execute, AbortFunc abort);
+5 -4
View File
@@ -21,6 +21,7 @@
#include <QtConcurrent/QtConcurrentRun> #include <QtConcurrent/QtConcurrentRun>
#include "common/assert.h" #include "common/assert.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/progress_callback.h"
#include "common/scope_exit.h" #include "common/scope_exit.h"
#include "frontend/helpers/multi_job.h" #include "frontend/helpers/multi_job.h"
#include "frontend/helpers/simple_job.h" #include "frontend/helpers/simple_job.h"
@@ -726,7 +727,7 @@ void ImportDialog::StartDumpingCXISingle(const Core::ContentSpecifier& specifier
auto* job = new SimpleJob( auto* job = new SimpleJob(
this, this,
[this, specifier, path](const SimpleJob::ProgressCallback& callback) { [this, specifier, path](const Common::ProgressCallback& callback) {
if (!importer.DumpCXI(specifier, path.toStdString(), callback)) { if (!importer.DumpCXI(specifier, path.toStdString(), callback)) {
FileUtil::Delete(path.toStdString()); FileUtil::Delete(path.toStdString());
return false; return false;
@@ -789,7 +790,7 @@ void ImportDialog::StartBatchDumpingCXI() {
auto* job = new MultiJob( auto* job = new MultiJob(
this, importer, std::move(to_import), this, importer, std::move(to_import),
[path](Core::SDMCImporter& importer, const Core::ContentSpecifier& specifier, [path](Core::SDMCImporter& importer, const Core::ContentSpecifier& specifier,
const Core::SDMCImporter::ProgressCallback& callback) { const Common::ProgressCallback& callback) {
return importer.DumpCXI(specifier, path.toStdString() + GetCXIFileName(specifier), return importer.DumpCXI(specifier, path.toStdString() + GetCXIFileName(specifier),
callback); callback);
}, },
@@ -812,7 +813,7 @@ void ImportDialog::StartBuildingCIASingle(const Core::ContentSpecifier& specifie
auto* job = new SimpleJob( auto* job = new SimpleJob(
this, this,
[this, specifier, path](const SimpleJob::ProgressCallback& callback) { [this, specifier, path](const Common::ProgressCallback& callback) {
if (!importer.BuildCIA(specifier, path.toStdString(), callback)) { if (!importer.BuildCIA(specifier, path.toStdString(), callback)) {
FileUtil::Delete(path.toStdString()); FileUtil::Delete(path.toStdString());
return false; return false;
@@ -878,7 +879,7 @@ void ImportDialog::StartBatchBuildingCIA() {
auto* job = new MultiJob( auto* job = new MultiJob(
this, importer, std::move(to_import), this, importer, std::move(to_import),
[path](Core::SDMCImporter& importer, const Core::ContentSpecifier& specifier, [path](Core::SDMCImporter& importer, const Core::ContentSpecifier& specifier,
const Core::SDMCImporter::ProgressCallback& callback) { const Common::ProgressCallback& callback) {
return importer.BuildCIA(specifier, path.toStdString() + GetCIAFileName(specifier), return importer.BuildCIA(specifier, path.toStdString() + GetCIAFileName(specifier),
callback); callback);
}, },