Migrate to new extract system (incomplete) + submodule update.

This commit is contained in:
jakcron 2022-02-01 13:16:17 +08:00
parent 71452fcf50
commit 162452655b
23 changed files with 367 additions and 79 deletions

2
deps/libfmt vendored

@ -1 +1 @@
Subproject commit 53d084cc0c6ea61bbb535a873299b0ae5ff9a05d
Subproject commit ae6df0aead2fdaae8a0b117524a6eb036c8fa075

@ -1 +1 @@
Subproject commit e93b71a2d2cebf060df00891fd8268f14288af63
Subproject commit 64adf7e5ee46355270e370231ea933ed82509915

2
deps/libtoolchain vendored

@ -1 +1 @@
Subproject commit d7b48027a93ef69b9c6b0d78fe392abc0bce5e68
Subproject commit ec4144330589b96c53adc10dac36f654821327a0

View file

@ -48,6 +48,11 @@ void nstool::AssetProcess::setRomfsShowFsTree(bool show_fs_tree)
mRomfs.setShowFsTree(show_fs_tree);
}
void nstool::AssetProcess::setRomfsArchiveJobs(const std::vector<nstool::ArchiveJob>& jobs)
{
mRomfs.setArchiveJobs(jobs);
}
void nstool::AssetProcess::setRomfsExtractJobs(const std::vector<nstool::ExtractJob>& extract_jobs)
{
mRomfs.setExtractJobs(extract_jobs);

View file

@ -21,6 +21,7 @@ public:
void setIconExtractPath(const tc::io::Path& path);
void setNacpExtractPath(const tc::io::Path& path);
void setRomfsArchiveJobs(const std::vector<nstool::ArchiveJob>& jobs);
void setRomfsShowFsTree(bool show_fs_tree);
void setRomfsExtractJobs(const std::vector<nstool::ExtractJob>& extract_jobs);
private:

View file

@ -14,6 +14,7 @@ nstool::FsProcess::FsProcess() :
mShowFsTree(false),
mFsRootLabel(),
mExtractJobs(),
mArchiveJobs(),
mDataCache(0x10000)
{
@ -26,6 +27,8 @@ void nstool::FsProcess::process()
throw tc::InvalidOperationException(mModuleLabel, "No input filesystem");
}
processArchiveJobs();
if (mShowFsInfo)
{
fmt::print("[{:s}]\n", mFsFormatName.isSet() ? mFsFormatName.get() : "FileSystem/Info");
@ -81,6 +84,115 @@ void nstool::FsProcess::setExtractJobs(const std::vector<nstool::ExtractJob>& ex
mExtractJobs = extract_jobs;
}
void nstool::FsProcess::setArchiveJobs(const std::vector<nstool::ArchiveJob>& archive_jobs)
{
mArchiveJobs = archive_jobs;
}
void nstool::FsProcess::processArchiveJobs()
{
for (auto itr = mArchiveJobs.begin(); itr != mArchiveJobs.end(); itr++)
{
/*
std::string archive_path_str, extract_base_path_str;
tc::io::PathUtil::pathToUnixUTF8(itr->archive_path, archive_path_str);
tc::io::PathUtil::pathToUnixUTF8(itr->extract_base_path, extract_base_path_str);
*/
// Qualify Archive Path
tc::io::Path qualified_archive_path;
bool is_dir = false, is_file = false;
if (!qualifyArchivePath(itr->archive_path, qualified_archive_path, is_dir, is_file))
{
std::string archive_path_str;
tc::io::PathUtil::pathToUnixUTF8(itr->archive_path, archive_path_str);
fmt::print("Path \"{}\" did not exist for this archive.\n", archive_path_str);
continue;
}
// print
{
std::string qualified_archive_path_str;
tc::io::PathUtil::pathToUnixUTF8(qualified_archive_path, qualified_archive_path_str);
fmt::print("Path \"{}\" was valid, is_dir={}, is_file={}.\n", qualified_archive_path_str, is_dir, is_file);
}
if (itr->job_action == ArchiveJob::JobAction::DoNothing)
{
fmt::print("DoNothing\n");
continue;
}
else if (itr->job_action == ArchiveJob::JobAction::ListFileTree)
{
fmt::print("ListFileTree\n");
}
else if (itr->job_action == ArchiveJob::JobAction::Extract)
{
fmt::print("Extract\n");
}
else
{
fmt::print("Unsupported ArchiveJob::JobAction\n");
}
}
}
bool nstool::FsProcess::qualifyArchivePath(const tc::io::Path& path, tc::io::Path& qualified_path, bool& is_dir, bool& is_file)
{
// test if the path is for a directory
try {
tc::io::sDirectoryListing dir_listing;
// getDirectoryListing will throw if this is not a directory
mInputFs->getDirectoryListing(path, dir_listing);
// set state and return
qualified_path = dir_listing.abs_path;
is_dir = true;
is_file = false;
return true;
} catch (tc::io::DirectoryNotFoundException&) {
// acceptable exception, just means directory didn't exist
}
// test if the path is for a file
try {
// opening the file will throw if the file doesn't exist
std::shared_ptr<tc::io::IStream> file_stream;
mInputFs->openFile(path, tc::io::FileMode::Open, tc::io::FileAccess::Read, file_stream);
// breakup the path into the parent directory path and file name
tc::io::Path parent_dir_path = path;
parent_dir_path.pop_back(); // remove the last element, which should be the file name (which should exist because opening the file worked)
std::string file_name = path.back();
// get the qualified file path
tc::io::sDirectoryListing dir_listing;
// getDirectoryListing will throw if this is not a directory
mInputFs->getDirectoryListing(parent_dir_path, dir_listing);
// set state
qualified_path = dir_listing.abs_path + file_name;
is_dir = false;
is_file = true;
return true;
} catch (tc::io::FileNotFoundException&) {
// acceptable exception, just means file didn't exist
}
qualified_path = tc::io::Path();
is_dir = false;
is_file = false;
return false;
}
void nstool::FsProcess::printFs()
{
fmt::print("[{:s}/Tree]\n", (mFsFormatName.isSet() ? mFsFormatName.get() : "FileSystem"));

View file

@ -21,6 +21,7 @@ public:
void setShowFsTree(bool show_fs_tree);
void setFsRootLabel(const std::string& root_label);
void setExtractJobs(const std::vector<nstool::ExtractJob>& extract_jobs);
void setArchiveJobs(const std::vector<nstool::ArchiveJob>& archive_jobs);
private:
std::string mModuleLabel;
@ -37,10 +38,15 @@ private:
// extract jobs
std::vector<nstool::ExtractJob> mExtractJobs;
std::vector<nstool::ArchiveJob> mArchiveJobs;
// cache for file extract
tc::ByteData mDataCache;
void processArchiveJobs();
bool qualifyArchivePath(const tc::io::Path& path, tc::io::Path& qualified_path, bool& is_dir, bool& is_file);
void printFs();
void extractFs();

View file

@ -16,10 +16,12 @@ nstool::GameCardProcess::GameCardProcess() :
mFile(),
mCliOutputMode(true, false, false, false),
mVerify(false),
mListFs(false),
mIsTrueSdkXci(false),
mIsSdkXciEncrypted(false),
mGcHeaderOffset(0),
mProccessExtendedHeader(false),
mRootPfs(),
mExtractJobs()
mFileSystem(),
mFsProcess()
{
}
@ -59,14 +61,19 @@ void nstool::GameCardProcess::setVerifyMode(bool verify)
mVerify = verify;
}
void nstool::GameCardProcess::setExtractJobs(const std::vector<nstool::ExtractJob> extract_jobs)
void nstool::GameCardProcess::setArchiveJobs(const std::vector<nstool::ArchiveJob>& jobs)
{
mExtractJobs = extract_jobs;
mFsProcess.setArchiveJobs(jobs);
}
void nstool::GameCardProcess::setShowFsTree(bool show_fs_tree)
{
mListFs = show_fs_tree;
mFsProcess.setShowFsTree(show_fs_tree);
}
void nstool::GameCardProcess::setExtractJobs(const std::vector<nstool::ExtractJob> extract_jobs)
{
mFsProcess.setExtractJobs(extract_jobs);
}
void nstool::GameCardProcess::importHeader()
@ -266,21 +273,16 @@ void nstool::GameCardProcess::processRootPfs()
std::shared_ptr<tc::io::IStream> gc_fs_raw = std::make_shared<tc::io::SubStream>(tc::io::SubStream(mFile, mHdr.getPartitionFsAddress(), nn::hac::GameCardUtil::blockToAddr(mHdr.getValidDataEndPage()+1) - mHdr.getPartitionFsAddress()));
auto gc_vfs_meta = nn::hac::GameCardFsMetaGenerator(gc_fs_raw, mHdr.getPartitionFsSize(), mVerify ? nn::hac::GameCardFsMetaGenerator::ValidationMode_Warn : nn::hac::GameCardFsMetaGenerator::ValidationMode_None);
std::shared_ptr<tc::io::IStorage> gc_vfs = std::make_shared<tc::io::VirtualFileSystem>(tc::io::VirtualFileSystem(gc_vfs_meta) );
mFileSystem = std::make_shared<tc::io::VirtualFileSystem>(tc::io::VirtualFileSystem(gc_vfs_meta) );
FsProcess fs_proc;
fs_proc.setInputFileSystem(gc_vfs);
fs_proc.setFsFormatName("PartitionFs");
fs_proc.setFsProperties({
mFsProcess.setInputFileSystem(mFileSystem);
mFsProcess.setFsFormatName("PartitionFs");
mFsProcess.setFsProperties({
fmt::format("Type: Nested HFS0"),
fmt::format("DirNum: {:d}", gc_vfs_meta.dir_entries.empty() ? 0 : gc_vfs_meta.dir_entries.size() - 1), // -1 to not include root directory
fmt::format("FileNum: {:d}", gc_vfs_meta.file_entries.size())
});
fs_proc.setShowFsInfo(mCliOutputMode.show_basic_info);
fs_proc.setShowFsTree(mListFs);
fs_proc.setFsRootLabel(kXciMountPointName);
fs_proc.setExtractJobs(mExtractJobs);
fs_proc.process();
mFsProcess.setShowFsInfo(mCliOutputMode.show_basic_info);
mFsProcess.setFsRootLabel(kXciMountPointName);
mFsProcess.process();
}

View file

@ -21,6 +21,7 @@ public:
void setVerifyMode(bool verify);
// fs specific
void setArchiveJobs(const std::vector<nstool::ArchiveJob>& jobs);
void setShowFsTree(bool show_fs_tree);
void setExtractJobs(const std::vector<nstool::ExtractJob> extract_jobs);
private:
@ -32,7 +33,6 @@ private:
KeyBag mKeyCfg;
CliOutputMode mCliOutputMode;
bool mVerify;
bool mListFs;
bool mIsTrueSdkXci;
bool mIsSdkXciEncrypted;
@ -42,8 +42,9 @@ private:
nn::hac::detail::sha256_hash_t mHdrHash;
nn::hac::GameCardHeader mHdr;
PfsProcess mRootPfs;
std::vector<nstool::ExtractJob> mExtractJobs;
// fs processing
std::shared_ptr<tc::io::IStorage> mFileSystem;
FsProcess mFsProcess;
void importHeader();
void displayHeader();

View file

@ -243,7 +243,7 @@ void nstool::KipProcess::displayKernelCap(const nn::hac::KernelCapabilityControl
}
if (kern.getMiscParams().isSet())
{
fmt::print(" ProgramType: {:s} ({:d})\n", nn::hac::KernelCapabilityUtil::getProgramTypeAsString(kern.getMiscParams().getProgramType()), kern.getMiscParams().getProgramType());
fmt::print(" ProgramType: {:s} ({:d})\n", nn::hac::KernelCapabilityUtil::getProgramTypeAsString(kern.getMiscParams().getProgramType()), (uint32_t)kern.getMiscParams().getProgramType());
}
if (kern.getKernelVersion().isSet())
{

View file

@ -169,7 +169,7 @@ void nstool::MetaProcess::validateAciFromAcid(const nn::hac::AccessControlInfo&
if (rightFound == false)
{
fmt::print("[WARNING] ACI/FAC SaveDataOwnerId: FAIL (0x{:016x} ({:d}) not permitted)\n", aci.getFileSystemAccessControl().getSaveDataOwnerIdList()[i].id, aci.getFileSystemAccessControl().getSaveDataOwnerIdList()[i].access_type);
fmt::print("[WARNING] ACI/FAC SaveDataOwnerId: FAIL (0x{:016x} ({:d}) not permitted)\n", aci.getFileSystemAccessControl().getSaveDataOwnerIdList()[i].id, (uint32_t)aci.getFileSystemAccessControl().getSaveDataOwnerIdList()[i].access_type);
}
}
@ -268,7 +268,7 @@ void nstool::MetaProcess::validateAciFromAcid(const nn::hac::AccessControlInfo&
// check misc params
if (aci.getKernelCapabilities().getMiscParams().getProgramType() != acid.getKernelCapabilities().getMiscParams().getProgramType())
{
fmt::print("[WARNING] ACI/KC ProgramType: FAIL ({:d} not permitted)\n", aci.getKernelCapabilities().getMiscParams().getProgramType());
fmt::print("[WARNING] ACI/KC ProgramType: FAIL ({:d} not permitted)\n", (uint32_t)aci.getKernelCapabilities().getMiscParams().getProgramType());
}
// check kernel version
uint32_t aciKernelVersion = (uint32_t)aci.getKernelCapabilities().getKernelVersion().getVerMajor() << 16 | (uint32_t)aci.getKernelCapabilities().getKernelVersion().getVerMinor();
@ -328,7 +328,7 @@ void nstool::MetaProcess::displayAciDescHdr(const nn::hac::AccessControlInfoDesc
fmt::print(" Flags: \n");
fmt::print(" Production: {}\n", acid.getProductionFlag());
fmt::print(" Unqualified Approval: {}\n", acid.getUnqualifiedApprovalFlag());
fmt::print(" Memory Region: {:s} ({:d})\n", nn::hac::AccessControlInfoUtil::getMemoryRegionAsString(acid.getMemoryRegion()), acid.getMemoryRegion());
fmt::print(" Memory Region: {:s} ({:d})\n", nn::hac::AccessControlInfoUtil::getMemoryRegionAsString(acid.getMemoryRegion()), (uint32_t)acid.getMemoryRegion());
fmt::print(" ProgramID Restriction\n");
fmt::print(" Min: 0x{:016x}\n", acid.getProgramIdRestrict().min);
fmt::print(" Max: 0x{:016x}\n", acid.getProgramIdRestrict().max);
@ -347,7 +347,7 @@ void nstool::MetaProcess::displayFac(const nn::hac::FileSystemAccessControl& fac
std::string flag_string = nn::hac::FileSystemAccessUtil::getFsAccessFlagAsString(nn::hac::fac::FsAccessFlag(*itr));
if (mCliOutputMode.show_extended_info)
{
fs_access_str_list.push_back(fmt::format("{:s} (bit {:d})", flag_string, *itr));
fs_access_str_list.push_back(fmt::format("{:s} (bit {:d})", flag_string, (uint32_t)*itr));
}
else
{
@ -445,7 +445,7 @@ void nstool::MetaProcess::displayKernelCap(const nn::hac::KernelCapabilityContro
}
if (kern.getMiscParams().isSet())
{
fmt::print(" ProgramType: {:s} ({:d})\n", nn::hac::KernelCapabilityUtil::getProgramTypeAsString(kern.getMiscParams().getProgramType()), kern.getMiscParams().getProgramType());
fmt::print(" ProgramType: {:s} ({:d})\n", nn::hac::KernelCapabilityUtil::getProgramTypeAsString(kern.getMiscParams().getProgramType()), (uint32_t)kern.getMiscParams().getProgramType());
}
if (kern.getKernelVersion().isSet())
{

View file

@ -69,6 +69,11 @@ void nstool::NcaProcess::setVerifyMode(bool verify)
mVerify = verify;
}
void nstool::NcaProcess::setArchiveJobs(const std::vector<nstool::ArchiveJob>& jobs)
{
mFsProcess.setArchiveJobs(jobs);
}
void nstool::NcaProcess::setShowFsTree(bool show_fs_tree)
{
mFsProcess.setShowFsTree(show_fs_tree);

View file

@ -23,6 +23,7 @@ public:
void setVerifyMode(bool verify);
// fs specific
void setArchiveJobs(const std::vector<nstool::ArchiveJob>& jobs);
void setShowFsTree(bool show_fs_tree);
void setFsRootLabel(const std::string& root_label);
void setExtractJobs(const std::vector<nstool::ExtractJob>& extract_jobs);

View file

@ -64,6 +64,11 @@ void nstool::NroProcess::setAssetNacpExtractPath(const tc::io::Path& path)
mAssetProc.setNacpExtractPath(path);
}
void nstool::NroProcess::setAssetRomfsArchiveJobs(const std::vector<nstool::ArchiveJob>& jobs)
{
mAssetProc.setRomfsArchiveJobs(jobs);
}
void nstool::NroProcess::setAssetRomfsShowFsTree(bool show_fs_tree)
{
mAssetProc.setRomfsShowFsTree(show_fs_tree);

View file

@ -25,6 +25,7 @@ public:
// for homebrew NROs with Asset blobs appended
void setAssetIconExtractPath(const tc::io::Path& path);
void setAssetNacpExtractPath(const tc::io::Path& path);
void setAssetRomfsArchiveJobs(const std::vector<nstool::ArchiveJob>& jobs);
void setAssetRomfsShowFsTree(bool show_fs_tree);
void setAssetRomfsExtractJobs(const std::vector<nstool::ExtractJob>& extract_jobs);

View file

@ -90,6 +90,11 @@ void nstool::PfsProcess::setVerifyMode(bool verify)
mVerify = verify;
}
void nstool::PfsProcess::setArchiveJobs(const std::vector<nstool::ArchiveJob>& jobs)
{
mFsProcess.setArchiveJobs(jobs);
}
void nstool::PfsProcess::setShowFsTree(bool show_fs_tree)
{
mFsProcess.setShowFsTree(show_fs_tree);

View file

@ -19,6 +19,7 @@ public:
void setVerifyMode(bool verify);
// fs specific
void setArchiveJobs(const std::vector<nstool::ArchiveJob>& jobs);
void setShowFsTree(bool show_fs_tree);
void setFsRootLabel(const std::string& root_label);
void setExtractJobs(const std::vector<nstool::ExtractJob>& extract_jobs);

View file

@ -112,6 +112,11 @@ void nstool::RomfsProcess::setVerifyMode(bool verify)
mVerify = verify;
}
void nstool::RomfsProcess::setArchiveJobs(const std::vector<nstool::ArchiveJob>& jobs)
{
mFsProcess.setArchiveJobs(jobs);
}
void nstool::RomfsProcess::setFsRootLabel(const std::string& root_label)
{
mFsProcess.setFsRootLabel(root_label);

View file

@ -19,6 +19,7 @@ public:
void setVerifyMode(bool verify);
// fs specific
void setArchiveJobs(const std::vector<nstool::ArchiveJob>& jobs);
void setFsRootLabel(const std::string& root_label);
void setExtractJobs(const std::vector<nstool::ExtractJob>& extract_jobs);
void setShowFsTree(bool show_fs_tree);

View file

@ -9,8 +9,6 @@
#include <tc/io/FileStream.h>
#include <tc/io/StreamSource.h>
#include <nn/hac/ContentArchiveUtil.h>
#include <nn/hac/AesKeygen.h>
#include <nn/hac/define/gc.h>
@ -42,6 +40,11 @@ public:
throw tc::InvalidOperationException("getOptionStrings() not defined for UnkOptionHandler.");
}
const std::vector<std::string>& getOptionRegexPatterns() const
{
throw tc::InvalidOperationException("getOptionRegexPatterns() not defined for UnkOptionHandler.");
}
void processOption(const std::string& option, const std::vector<std::string>& params)
{
throw tc::Exception(mModuleLabel, "Unrecognized option: \"" + option + "\"");
@ -55,7 +58,8 @@ class DeprecatedOptionHandler : public tc::cli::OptionParser::IOptionHandler
public:
DeprecatedOptionHandler(const std::string& warn_message, const std::vector<std::string>& opts) :
mWarnMessage(warn_message),
mOptStrings(opts)
mOptStrings(opts),
mOptRegex()
{}
const std::vector<std::string>& getOptionStrings() const
@ -63,6 +67,11 @@ public:
return mOptStrings;
}
const std::vector<std::string>& getOptionRegexPatterns() const
{
return mOptRegex;
}
void processOption(const std::string& option, const std::vector<std::string>& params)
{
fmt::print("[WARNING] Option \"{}\" is deprecated.{}{}\n", option, (mWarnMessage.empty() ? "" : " "), mWarnMessage);
@ -70,6 +79,7 @@ public:
private:
std::string mWarnMessage;
std::vector<std::string> mOptStrings;
std::vector<std::string> mOptRegex;
};
class FlagOptionHandler : public tc::cli::OptionParser::IOptionHandler
@ -77,7 +87,8 @@ class FlagOptionHandler : public tc::cli::OptionParser::IOptionHandler
public:
FlagOptionHandler(bool& flag, const std::vector<std::string>& opts) :
mFlag(flag),
mOptStrings(opts)
mOptStrings(opts),
mOptRegex()
{}
const std::vector<std::string>& getOptionStrings() const
@ -85,6 +96,11 @@ public:
return mOptStrings;
}
const std::vector<std::string>& getOptionRegexPatterns() const
{
return mOptRegex;
}
void processOption(const std::string& option, const std::vector<std::string>& params)
{
if (params.size() != 0)
@ -97,6 +113,7 @@ public:
private:
bool& mFlag;
std::vector<std::string> mOptStrings;
std::vector<std::string> mOptRegex;
};
class SingleParamStringOptionHandler : public tc::cli::OptionParser::IOptionHandler
@ -104,7 +121,8 @@ class SingleParamStringOptionHandler : public tc::cli::OptionParser::IOptionHand
public:
SingleParamStringOptionHandler(tc::Optional<std::string>& param, const std::vector<std::string>& opts) :
mParam(param),
mOptStrings(opts)
mOptStrings(opts),
mOptRegex()
{}
const std::vector<std::string>& getOptionStrings() const
@ -112,6 +130,11 @@ public:
return mOptStrings;
}
const std::vector<std::string>& getOptionRegexPatterns() const
{
return mOptRegex;
}
void processOption(const std::string& option, const std::vector<std::string>& params)
{
if (params.size() != 1)
@ -124,6 +147,7 @@ public:
private:
tc::Optional<std::string>& mParam;
std::vector<std::string> mOptStrings;
std::vector<std::string> mOptRegex;
};
class SingleParamPathOptionHandler : public tc::cli::OptionParser::IOptionHandler
@ -131,7 +155,8 @@ class SingleParamPathOptionHandler : public tc::cli::OptionParser::IOptionHandle
public:
SingleParamPathOptionHandler(tc::Optional<tc::io::Path>& param, const std::vector<std::string>& opts) :
mParam(param),
mOptStrings(opts)
mOptStrings(opts),
mOptRegex()
{}
const std::vector<std::string>& getOptionStrings() const
@ -139,6 +164,11 @@ public:
return mOptStrings;
}
const std::vector<std::string>& getOptionRegexPatterns() const
{
return mOptRegex;
}
void processOption(const std::string& option, const std::vector<std::string>& params)
{
if (params.size() != 1)
@ -151,6 +181,7 @@ public:
private:
tc::Optional<tc::io::Path>& mParam;
std::vector<std::string> mOptStrings;
std::vector<std::string> mOptRegex;
};
class SingleParamSizetOptionHandler : public tc::cli::OptionParser::IOptionHandler
@ -158,7 +189,8 @@ class SingleParamSizetOptionHandler : public tc::cli::OptionParser::IOptionHandl
public:
SingleParamSizetOptionHandler(size_t& param, const std::vector<std::string>& opts) :
mParam(param),
mOptStrings(opts)
mOptStrings(opts),
mOptRegex()
{}
const std::vector<std::string>& getOptionStrings() const
@ -166,6 +198,11 @@ public:
return mOptStrings;
}
const std::vector<std::string>& getOptionRegexPatterns() const
{
return mOptRegex;
}
void processOption(const std::string& option, const std::vector<std::string>& params)
{
if (params.size() != 1)
@ -178,6 +215,7 @@ public:
private:
size_t& mParam;
std::vector<std::string> mOptStrings;
std::vector<std::string> mOptRegex;
};
class SingleParamAesKeyOptionHandler : public tc::cli::OptionParser::IOptionHandler
@ -185,7 +223,8 @@ class SingleParamAesKeyOptionHandler : public tc::cli::OptionParser::IOptionHand
public:
SingleParamAesKeyOptionHandler(tc::Optional<nstool::KeyBag::aes128_key_t>& param, const std::vector<std::string>& opts) :
mParam(param),
mOptStrings(opts)
mOptStrings(opts),
mOptRegex()
{}
const std::vector<std::string>& getOptionStrings() const
@ -193,6 +232,11 @@ public:
return mOptStrings;
}
const std::vector<std::string>& getOptionRegexPatterns() const
{
return mOptRegex;
}
void processOption(const std::string& option, const std::vector<std::string>& params)
{
if (params.size() != 1)
@ -214,6 +258,7 @@ public:
private:
tc::Optional<nstool::KeyBag::aes128_key_t>& mParam;
std::vector<std::string> mOptStrings;
std::vector<std::string> mOptRegex;
};
class FileTypeOptionHandler : public tc::cli::OptionParser::IOptionHandler
@ -221,7 +266,8 @@ class FileTypeOptionHandler : public tc::cli::OptionParser::IOptionHandler
public:
FileTypeOptionHandler(nstool::Settings::FileType& param, const std::vector<std::string>& opts) :
mParam(param),
mOptStrings(opts)
mOptStrings(opts),
mOptRegex()
{}
const std::vector<std::string>& getOptionStrings() const
@ -229,6 +275,11 @@ public:
return mOptStrings;
}
const std::vector<std::string>& getOptionRegexPatterns() const
{
return mOptRegex;
}
void processOption(const std::string& option, const std::vector<std::string>& params)
{
if (params.size() != 1)
@ -310,6 +361,7 @@ public:
private:
nstool::Settings::FileType& mParam;
std::vector<std::string> mOptStrings;
std::vector<std::string> mOptRegex;
};
class InstructionTypeOptionHandler : public tc::cli::OptionParser::IOptionHandler
@ -317,7 +369,8 @@ class InstructionTypeOptionHandler : public tc::cli::OptionParser::IOptionHandle
public:
InstructionTypeOptionHandler(bool& param, const std::vector<std::string>& opts) :
mParam(param),
mOptStrings(opts)
mOptStrings(opts),
mOptRegex()
{}
const std::vector<std::string>& getOptionStrings() const
@ -325,6 +378,11 @@ public:
return mOptStrings;
}
const std::vector<std::string>& getOptionRegexPatterns() const
{
return mOptRegex;
}
void processOption(const std::string& option, const std::vector<std::string>& params)
{
if (params.size() != 1)
@ -348,14 +406,16 @@ public:
private:
bool& mParam;
std::vector<std::string> mOptStrings;
std::vector<std::string> mOptRegex;
};
class ExtractDataPathOptionHandler : public tc::cli::OptionParser::IOptionHandler
class ListArchiveJobPathOptionHandler : public tc::cli::OptionParser::IOptionHandler
{
public:
ExtractDataPathOptionHandler(std::vector<nstool::ExtractJob>& jobs, const std::vector<std::string>& opts) :
ListArchiveJobPathOptionHandler(std::vector<nstool::ArchiveJob>& jobs, const std::vector<std::string>& opts) :
mJobs(jobs),
mOptStrings(opts)
mOptStrings(opts),
mOptRegex()
{}
const std::vector<std::string>& getOptionStrings() const
@ -363,15 +423,60 @@ public:
return mOptStrings;
}
const std::vector<std::string>& getOptionRegexPatterns() const
{
return mOptRegex;
}
void processOption(const std::string& option, const std::vector<std::string>& params)
{
if (params.size() == 0)
{
mJobs.push_back({nstool::ArchiveJob::JobAction::ListFileTree, tc::io::Path("/"), tc::io::Path(), false});
}
else if (params.size() == 1)
{
mJobs.push_back({nstool::ArchiveJob::JobAction::ListFileTree, tc::io::Path(params[0]), tc::io::Path(), false});
}
else
{
throw tc::ArgumentOutOfRangeException(fmt::format("Option \"{:s}\" requires one parameter in the format \"{:s} [<internal path>]\".", option, option));
}
}
private:
std::vector<nstool::ArchiveJob>& mJobs;
std::vector<std::string> mOptStrings;
std::vector<std::string> mOptRegex;
};
class ExtractArchiveJobPathOptionHandler : public tc::cli::OptionParser::IOptionHandler
{
public:
ExtractArchiveJobPathOptionHandler(std::vector<nstool::ArchiveJob>& jobs, const std::vector<std::string>& opts) :
mJobs(jobs),
mOptStrings(opts),
mOptRegex()
{}
const std::vector<std::string>& getOptionStrings() const
{
return mOptStrings;
}
const std::vector<std::string>& getOptionRegexPatterns() const
{
return mOptRegex;
}
void processOption(const std::string& option, const std::vector<std::string>& params)
{
if (params.size() == 1)
{
mJobs.push_back({tc::io::Path("/"), tc::io::Path(params[0])});
mJobs.push_back({nstool::ArchiveJob::JobAction::Extract, tc::io::Path("/"), tc::io::Path(params[0]), false});
}
else if (params.size() == 2)
{
mJobs.push_back({tc::io::Path(params[0]), tc::io::Path(params[1])});
mJobs.push_back({nstool::ArchiveJob::JobAction::Extract, tc::io::Path(params[0]), tc::io::Path(params[1]), false});
}
else
{
@ -379,16 +484,18 @@ public:
}
}
private:
std::vector<nstool::ExtractJob>& mJobs;
std::vector<nstool::ArchiveJob>& mJobs;
std::vector<std::string> mOptStrings;
std::vector<std::string> mOptRegex;
};
class CustomExtractDataPathOptionHandler : public tc::cli::OptionParser::IOptionHandler
class CustomExtractArchiveJobPathOptionHandler : public tc::cli::OptionParser::IOptionHandler
{
public:
CustomExtractDataPathOptionHandler(std::vector<nstool::ExtractJob>& jobs, const std::vector<std::string>& opts, const tc::io::Path& custom_path) :
CustomExtractArchiveJobPathOptionHandler(std::vector<nstool::ArchiveJob>& jobs, const std::vector<std::string>& opts, const tc::io::Path& custom_path) :
mJobs(jobs),
mOptStrings(opts),
mOptRegex(),
mCustomPath(custom_path)
{}
@ -397,6 +504,11 @@ public:
return mOptStrings;
}
const std::vector<std::string>& getOptionRegexPatterns() const
{
return mOptRegex;
}
void processOption(const std::string& option, const std::vector<std::string>& params)
{
if (params.size() != 1)
@ -418,12 +530,12 @@ public:
fmt::print("Consider using \"-x {:s} {:s}\" instead.\n", custom_path_str, params[0]);
}
mJobs.push_back({mCustomPath, tc::io::Path(params[0])});
mJobs.push_back({nstool::ArchiveJob::JobAction::Extract, mCustomPath, tc::io::Path(params[0]), false});
}
private:
std::vector<nstool::ExtractJob>& mJobs;
std::vector<nstool::ArchiveJob>& mJobs;
std::vector<std::string> mOptStrings;
std::vector<std::string> mOptRegex;
tc::io::Path mCustomPath;
};
@ -536,6 +648,7 @@ void nstool::SettingsInitializer::parse_args(const std::vector<std::string>& arg
// register handler for deprecated options DeprecatedOptionHandler
// none just yet
//opts.registerOptionHandler(std::shared_ptr<DeprecatedOptionHandler>(new DeprecatedOptionHandler("warning message here", {"--dep-option"})));
// get option flags
opts.registerOptionHandler(std::shared_ptr<FlagOptionHandler>(new FlagOptionHandler(mShowLayout, {"--showlayout"})));
@ -560,21 +673,21 @@ void nstool::SettingsInitializer::parse_args(const std::vector<std::string>& arg
opts.registerOptionHandler(std::shared_ptr<InstructionTypeOptionHandler>(new InstructionTypeOptionHandler(code.is_64bit_instruction, { "--insttype" })));
// fs options
opts.registerOptionHandler(std::shared_ptr<FlagOptionHandler>(new FlagOptionHandler(fs.show_fs_tree, { "--fstree", "--listfs" })));
opts.registerOptionHandler(std::shared_ptr<ExtractDataPathOptionHandler>(new ExtractDataPathOptionHandler(fs.extract_jobs, { "-x", "--extract" })));
opts.registerOptionHandler(std::shared_ptr<CustomExtractDataPathOptionHandler>(new CustomExtractDataPathOptionHandler(fs.extract_jobs, { "--fsdir" }, tc::io::Path("/"))));
opts.registerOptionHandler(std::shared_ptr<ListArchiveJobPathOptionHandler>(new ListArchiveJobPathOptionHandler(fs.archive_jobs, { "--fstree", "--listfs" })));
opts.registerOptionHandler(std::shared_ptr<ExtractArchiveJobPathOptionHandler>(new ExtractArchiveJobPathOptionHandler(fs.archive_jobs, { "-x", "--extract" })));
opts.registerOptionHandler(std::shared_ptr<CustomExtractArchiveJobPathOptionHandler>(new CustomExtractArchiveJobPathOptionHandler(fs.archive_jobs, { "--fsdir" }, tc::io::Path("/"))));
// xci options
opts.registerOptionHandler(std::shared_ptr<CustomExtractDataPathOptionHandler>(new CustomExtractDataPathOptionHandler(fs.extract_jobs, { "--update" }, tc::io::Path("/update/"))));
opts.registerOptionHandler(std::shared_ptr<CustomExtractDataPathOptionHandler>(new CustomExtractDataPathOptionHandler(fs.extract_jobs, { "--normal" }, tc::io::Path("/normal/"))));
opts.registerOptionHandler(std::shared_ptr<CustomExtractDataPathOptionHandler>(new CustomExtractDataPathOptionHandler(fs.extract_jobs, { "--secure" }, tc::io::Path("/secure/"))));
opts.registerOptionHandler(std::shared_ptr<CustomExtractDataPathOptionHandler>(new CustomExtractDataPathOptionHandler(fs.extract_jobs, { "--logo" }, tc::io::Path("/logo/"))));
opts.registerOptionHandler(std::shared_ptr<CustomExtractArchiveJobPathOptionHandler>(new CustomExtractArchiveJobPathOptionHandler(fs.archive_jobs, { "--update" }, tc::io::Path("/update/"))));
opts.registerOptionHandler(std::shared_ptr<CustomExtractArchiveJobPathOptionHandler>(new CustomExtractArchiveJobPathOptionHandler(fs.archive_jobs, { "--normal" }, tc::io::Path("/normal/"))));
opts.registerOptionHandler(std::shared_ptr<CustomExtractArchiveJobPathOptionHandler>(new CustomExtractArchiveJobPathOptionHandler(fs.archive_jobs, { "--secure" }, tc::io::Path("/secure/"))));
opts.registerOptionHandler(std::shared_ptr<CustomExtractArchiveJobPathOptionHandler>(new CustomExtractArchiveJobPathOptionHandler(fs.archive_jobs, { "--logo" }, tc::io::Path("/logo/"))));
// nca options
opts.registerOptionHandler(std::shared_ptr<CustomExtractDataPathOptionHandler>(new CustomExtractDataPathOptionHandler(fs.extract_jobs, { "--part0" }, tc::io::Path("/0/"))));
opts.registerOptionHandler(std::shared_ptr<CustomExtractDataPathOptionHandler>(new CustomExtractDataPathOptionHandler(fs.extract_jobs, { "--part1" }, tc::io::Path("/1/"))));
opts.registerOptionHandler(std::shared_ptr<CustomExtractDataPathOptionHandler>(new CustomExtractDataPathOptionHandler(fs.extract_jobs, { "--part2" }, tc::io::Path("/2/"))));
opts.registerOptionHandler(std::shared_ptr<CustomExtractDataPathOptionHandler>(new CustomExtractDataPathOptionHandler(fs.extract_jobs, { "--part3" }, tc::io::Path("/3/"))));
opts.registerOptionHandler(std::shared_ptr<CustomExtractArchiveJobPathOptionHandler>(new CustomExtractArchiveJobPathOptionHandler(fs.archive_jobs, { "--part0" }, tc::io::Path("/0/"))));
opts.registerOptionHandler(std::shared_ptr<CustomExtractArchiveJobPathOptionHandler>(new CustomExtractArchiveJobPathOptionHandler(fs.archive_jobs, { "--part1" }, tc::io::Path("/1/"))));
opts.registerOptionHandler(std::shared_ptr<CustomExtractArchiveJobPathOptionHandler>(new CustomExtractArchiveJobPathOptionHandler(fs.archive_jobs, { "--part2" }, tc::io::Path("/2/"))));
opts.registerOptionHandler(std::shared_ptr<CustomExtractArchiveJobPathOptionHandler>(new CustomExtractArchiveJobPathOptionHandler(fs.archive_jobs, { "--part3" }, tc::io::Path("/3/"))));
// kip options
opts.registerOptionHandler(std::shared_ptr<SingleParamPathOptionHandler>(new SingleParamPathOptionHandler(kip.extract_path, { "--kipdir" })));

View file

@ -56,27 +56,14 @@ struct Settings
// Generic FS options
struct FsOptions
{
// legacy
bool show_fs_tree;
std::vector<ExtractJob> extract_jobs;
// new
std::vector<ArchiveJob> archive_jobs;
} fs;
// XCI options
struct XciOptions
{
tc::Optional<tc::io::Path> update_extract_path;
tc::Optional<tc::io::Path> logo_extract_path;
tc::Optional<tc::io::Path> normal_extract_path;
tc::Optional<tc::io::Path> secure_extract_path;
} xci;
// NCA options
struct NcaOptions
{
tc::Optional<tc::io::Path> part0_extract_path;
tc::Optional<tc::io::Path> part1_extract_path;
tc::Optional<tc::io::Path> part2_extract_path;
tc::Optional<tc::io::Path> part3_extract_path;
} nca;
// KIP options
struct KipOptions
@ -107,6 +94,7 @@ struct Settings
fs.show_fs_tree = false;
fs.extract_jobs = std::vector<ExtractJob>();
fs.archive_jobs = std::vector<ArchiveJob>();
kip.extract_path = tc::Optional<tc::io::Path>();

View file

@ -37,6 +37,8 @@ int umain(const std::vector<std::string>& args, const std::vector<std::string>&
obj.setCliOutputMode(set.opt.cli_output_mode);
obj.setVerifyMode(set.opt.verify);
obj.setArchiveJobs(set.fs.archive_jobs);
obj.setShowFsTree(set.fs.show_fs_tree);
obj.setExtractJobs(set.fs.extract_jobs);
@ -51,6 +53,8 @@ int umain(const std::vector<std::string>& args, const std::vector<std::string>&
obj.setCliOutputMode(set.opt.cli_output_mode);
obj.setVerifyMode(set.opt.verify);
obj.setArchiveJobs(set.fs.archive_jobs);
obj.setShowFsTree(set.fs.show_fs_tree);
obj.setExtractJobs(set.fs.extract_jobs);
@ -65,6 +69,8 @@ int umain(const std::vector<std::string>& args, const std::vector<std::string>&
obj.setCliOutputMode(set.opt.cli_output_mode);
obj.setVerifyMode(set.opt.verify);
obj.setArchiveJobs(set.fs.archive_jobs);
obj.setShowFsTree(set.fs.show_fs_tree);
obj.setExtractJobs(set.fs.extract_jobs);
@ -79,6 +85,8 @@ int umain(const std::vector<std::string>& args, const std::vector<std::string>&
obj.setCliOutputMode(set.opt.cli_output_mode);
obj.setVerifyMode(set.opt.verify);
obj.setArchiveJobs(set.fs.archive_jobs);
obj.setShowFsTree(set.fs.show_fs_tree);
obj.setExtractJobs(set.fs.extract_jobs);
@ -136,6 +144,8 @@ int umain(const std::vector<std::string>& args, const std::vector<std::string>&
if (set.aset.nacp_extract_path.isSet())
obj.setAssetNacpExtractPath(set.aset.nacp_extract_path.get());
obj.setAssetRomfsArchiveJobs(set.fs.archive_jobs);
obj.setAssetRomfsShowFsTree(set.fs.show_fs_tree);
obj.setAssetRomfsExtractJobs(set.fs.extract_jobs);

View file

@ -24,6 +24,32 @@ struct CliOutputMode
{}
};
struct ArchiveJob
{
/* Common Job Properties */
enum class JobAction {
DoNothing,
ListFileTree,
Extract
};
JobAction job_action; // action taken by job processor
tc::io::Path archive_path; // path within archive to process
/* Extract Job Properties */
tc::io::Path extract_base_path; // path to base directory to extract
bool preserve_archive_path; // recreate archive path when extracting
ArchiveJob() : job_action(JobAction::DoNothing), archive_path(), extract_base_path(), preserve_archive_path(false)
{}
ArchiveJob(JobAction job_action, const tc::io::Path& archive_path, const tc::io::Path& extract_base_path, bool preserve_archive_path) :
job_action(job_action),
archive_path(archive_path),
extract_base_path(extract_base_path),
preserve_archive_path(preserve_archive_path)
{}
};
struct ExtractJob {
tc::io::Path virtual_path;
tc::io::Path extract_path;