From 162452655bfc20f3b44f750294d29d62bf126674 Mon Sep 17 00:00:00 2001 From: jakcron Date: Tue, 1 Feb 2022 13:16:17 +0800 Subject: [PATCH] Migrate to new extract system (incomplete) + submodule update. --- deps/libfmt | 2 +- deps/libnintendo-hac | 2 +- deps/libtoolchain | 2 +- src/AssetProcess.cpp | 5 ++ src/AssetProcess.h | 1 + src/FsProcess.cpp | 112 +++++++++++++++++++++++++ src/FsProcess.h | 6 ++ src/GameCardProcess.cpp | 38 +++++---- src/GameCardProcess.h | 7 +- src/KipProcess.cpp | 2 +- src/MetaProcess.cpp | 10 +-- src/NcaProcess.cpp | 5 ++ src/NcaProcess.h | 1 + src/NroProcess.cpp | 5 ++ src/NroProcess.h | 1 + src/PfsProcess.cpp | 5 ++ src/PfsProcess.h | 1 + src/RomfsProcess.cpp | 5 ++ src/RomfsProcess.h | 1 + src/Settings.cpp | 177 ++++++++++++++++++++++++++++++++-------- src/Settings.h | 22 ++--- src/main.cpp | 10 +++ src/types.h | 26 ++++++ 23 files changed, 367 insertions(+), 79 deletions(-) diff --git a/deps/libfmt b/deps/libfmt index 53d084c..ae6df0a 160000 --- a/deps/libfmt +++ b/deps/libfmt @@ -1 +1 @@ -Subproject commit 53d084cc0c6ea61bbb535a873299b0ae5ff9a05d +Subproject commit ae6df0aead2fdaae8a0b117524a6eb036c8fa075 diff --git a/deps/libnintendo-hac b/deps/libnintendo-hac index e93b71a..64adf7e 160000 --- a/deps/libnintendo-hac +++ b/deps/libnintendo-hac @@ -1 +1 @@ -Subproject commit e93b71a2d2cebf060df00891fd8268f14288af63 +Subproject commit 64adf7e5ee46355270e370231ea933ed82509915 diff --git a/deps/libtoolchain b/deps/libtoolchain index d7b4802..ec41443 160000 --- a/deps/libtoolchain +++ b/deps/libtoolchain @@ -1 +1 @@ -Subproject commit d7b48027a93ef69b9c6b0d78fe392abc0bce5e68 +Subproject commit ec4144330589b96c53adc10dac36f654821327a0 diff --git a/src/AssetProcess.cpp b/src/AssetProcess.cpp index 6f52bde..a0858fd 100644 --- a/src/AssetProcess.cpp +++ b/src/AssetProcess.cpp @@ -48,6 +48,11 @@ void nstool::AssetProcess::setRomfsShowFsTree(bool show_fs_tree) mRomfs.setShowFsTree(show_fs_tree); } +void nstool::AssetProcess::setRomfsArchiveJobs(const std::vector& jobs) +{ + mRomfs.setArchiveJobs(jobs); +} + void nstool::AssetProcess::setRomfsExtractJobs(const std::vector& extract_jobs) { mRomfs.setExtractJobs(extract_jobs); diff --git a/src/AssetProcess.h b/src/AssetProcess.h index 2ce3d0a..538d8aa 100644 --- a/src/AssetProcess.h +++ b/src/AssetProcess.h @@ -21,6 +21,7 @@ public: void setIconExtractPath(const tc::io::Path& path); void setNacpExtractPath(const tc::io::Path& path); + void setRomfsArchiveJobs(const std::vector& jobs); void setRomfsShowFsTree(bool show_fs_tree); void setRomfsExtractJobs(const std::vector& extract_jobs); private: diff --git a/src/FsProcess.cpp b/src/FsProcess.cpp index 13da38c..3d64edc 100644 --- a/src/FsProcess.cpp +++ b/src/FsProcess.cpp @@ -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& ex mExtractJobs = extract_jobs; } +void nstool::FsProcess::setArchiveJobs(const std::vector& 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 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")); diff --git a/src/FsProcess.h b/src/FsProcess.h index 70fc909..61210eb 100644 --- a/src/FsProcess.h +++ b/src/FsProcess.h @@ -21,6 +21,7 @@ public: void setShowFsTree(bool show_fs_tree); void setFsRootLabel(const std::string& root_label); void setExtractJobs(const std::vector& extract_jobs); + void setArchiveJobs(const std::vector& archive_jobs); private: std::string mModuleLabel; @@ -37,10 +38,15 @@ private: // extract jobs std::vector mExtractJobs; + std::vector 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(); diff --git a/src/GameCardProcess.cpp b/src/GameCardProcess.cpp index 929f720..ed0f3cd 100644 --- a/src/GameCardProcess.cpp +++ b/src/GameCardProcess.cpp @@ -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 extract_jobs) +void nstool::GameCardProcess::setArchiveJobs(const std::vector& 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 extract_jobs) +{ + mFsProcess.setExtractJobs(extract_jobs); } void nstool::GameCardProcess::importHeader() @@ -266,21 +273,16 @@ void nstool::GameCardProcess::processRootPfs() std::shared_ptr gc_fs_raw = std::make_shared(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 gc_vfs = std::make_shared(tc::io::VirtualFileSystem(gc_vfs_meta) ); + mFileSystem = std::make_shared(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(); } \ No newline at end of file diff --git a/src/GameCardProcess.h b/src/GameCardProcess.h index 7e984f5..7fe9f63 100644 --- a/src/GameCardProcess.h +++ b/src/GameCardProcess.h @@ -21,6 +21,7 @@ public: void setVerifyMode(bool verify); // fs specific + void setArchiveJobs(const std::vector& jobs); void setShowFsTree(bool show_fs_tree); void setExtractJobs(const std::vector 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 mExtractJobs; + // fs processing + std::shared_ptr mFileSystem; + FsProcess mFsProcess; void importHeader(); void displayHeader(); diff --git a/src/KipProcess.cpp b/src/KipProcess.cpp index 2b7468b..c17b9c0 100644 --- a/src/KipProcess.cpp +++ b/src/KipProcess.cpp @@ -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()) { diff --git a/src/MetaProcess.cpp b/src/MetaProcess.cpp index c96aa08..cd5305d 100644 --- a/src/MetaProcess.cpp +++ b/src/MetaProcess.cpp @@ -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()) { diff --git a/src/NcaProcess.cpp b/src/NcaProcess.cpp index a4bad7e..7ad3e66 100644 --- a/src/NcaProcess.cpp +++ b/src/NcaProcess.cpp @@ -69,6 +69,11 @@ void nstool::NcaProcess::setVerifyMode(bool verify) mVerify = verify; } +void nstool::NcaProcess::setArchiveJobs(const std::vector& jobs) +{ + mFsProcess.setArchiveJobs(jobs); +} + void nstool::NcaProcess::setShowFsTree(bool show_fs_tree) { mFsProcess.setShowFsTree(show_fs_tree); diff --git a/src/NcaProcess.h b/src/NcaProcess.h index 535a0d8..18bc449 100644 --- a/src/NcaProcess.h +++ b/src/NcaProcess.h @@ -23,6 +23,7 @@ public: void setVerifyMode(bool verify); // fs specific + void setArchiveJobs(const std::vector& jobs); void setShowFsTree(bool show_fs_tree); void setFsRootLabel(const std::string& root_label); void setExtractJobs(const std::vector& extract_jobs); diff --git a/src/NroProcess.cpp b/src/NroProcess.cpp index 66a061c..31d27f8 100644 --- a/src/NroProcess.cpp +++ b/src/NroProcess.cpp @@ -64,6 +64,11 @@ void nstool::NroProcess::setAssetNacpExtractPath(const tc::io::Path& path) mAssetProc.setNacpExtractPath(path); } +void nstool::NroProcess::setAssetRomfsArchiveJobs(const std::vector& jobs) +{ + mAssetProc.setRomfsArchiveJobs(jobs); +} + void nstool::NroProcess::setAssetRomfsShowFsTree(bool show_fs_tree) { mAssetProc.setRomfsShowFsTree(show_fs_tree); diff --git a/src/NroProcess.h b/src/NroProcess.h index ac93711..0a4077c 100644 --- a/src/NroProcess.h +++ b/src/NroProcess.h @@ -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& jobs); void setAssetRomfsShowFsTree(bool show_fs_tree); void setAssetRomfsExtractJobs(const std::vector& extract_jobs); diff --git a/src/PfsProcess.cpp b/src/PfsProcess.cpp index c7be0ac..9f69d2d 100644 --- a/src/PfsProcess.cpp +++ b/src/PfsProcess.cpp @@ -90,6 +90,11 @@ void nstool::PfsProcess::setVerifyMode(bool verify) mVerify = verify; } +void nstool::PfsProcess::setArchiveJobs(const std::vector& jobs) +{ + mFsProcess.setArchiveJobs(jobs); +} + void nstool::PfsProcess::setShowFsTree(bool show_fs_tree) { mFsProcess.setShowFsTree(show_fs_tree); diff --git a/src/PfsProcess.h b/src/PfsProcess.h index e3ff3c5..ca69028 100644 --- a/src/PfsProcess.h +++ b/src/PfsProcess.h @@ -19,6 +19,7 @@ public: void setVerifyMode(bool verify); // fs specific + void setArchiveJobs(const std::vector& jobs); void setShowFsTree(bool show_fs_tree); void setFsRootLabel(const std::string& root_label); void setExtractJobs(const std::vector& extract_jobs); diff --git a/src/RomfsProcess.cpp b/src/RomfsProcess.cpp index 6fb3d7b..2a80bdf 100644 --- a/src/RomfsProcess.cpp +++ b/src/RomfsProcess.cpp @@ -112,6 +112,11 @@ void nstool::RomfsProcess::setVerifyMode(bool verify) mVerify = verify; } +void nstool::RomfsProcess::setArchiveJobs(const std::vector& jobs) +{ + mFsProcess.setArchiveJobs(jobs); +} + void nstool::RomfsProcess::setFsRootLabel(const std::string& root_label) { mFsProcess.setFsRootLabel(root_label); diff --git a/src/RomfsProcess.h b/src/RomfsProcess.h index 9d99609..4597c20 100644 --- a/src/RomfsProcess.h +++ b/src/RomfsProcess.h @@ -19,6 +19,7 @@ public: void setVerifyMode(bool verify); // fs specific + void setArchiveJobs(const std::vector& jobs); void setFsRootLabel(const std::string& root_label); void setExtractJobs(const std::vector& extract_jobs); void setShowFsTree(bool show_fs_tree); diff --git a/src/Settings.cpp b/src/Settings.cpp index 2c211ba..543dcfb 100644 --- a/src/Settings.cpp +++ b/src/Settings.cpp @@ -9,8 +9,6 @@ #include #include - - #include #include #include @@ -42,6 +40,11 @@ public: throw tc::InvalidOperationException("getOptionStrings() not defined for UnkOptionHandler."); } + const std::vector& getOptionRegexPatterns() const + { + throw tc::InvalidOperationException("getOptionRegexPatterns() not defined for UnkOptionHandler."); + } + void processOption(const std::string& option, const std::vector& 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& opts) : mWarnMessage(warn_message), - mOptStrings(opts) + mOptStrings(opts), + mOptRegex() {} const std::vector& getOptionStrings() const @@ -63,6 +67,11 @@ public: return mOptStrings; } + const std::vector& getOptionRegexPatterns() const + { + return mOptRegex; + } + void processOption(const std::string& option, const std::vector& params) { fmt::print("[WARNING] Option \"{}\" is deprecated.{}{}\n", option, (mWarnMessage.empty() ? "" : " "), mWarnMessage); @@ -70,6 +79,7 @@ public: private: std::string mWarnMessage; std::vector mOptStrings; + std::vector 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& opts) : mFlag(flag), - mOptStrings(opts) + mOptStrings(opts), + mOptRegex() {} const std::vector& getOptionStrings() const @@ -85,6 +96,11 @@ public: return mOptStrings; } + const std::vector& getOptionRegexPatterns() const + { + return mOptRegex; + } + void processOption(const std::string& option, const std::vector& params) { if (params.size() != 0) @@ -97,6 +113,7 @@ public: private: bool& mFlag; std::vector mOptStrings; + std::vector mOptRegex; }; class SingleParamStringOptionHandler : public tc::cli::OptionParser::IOptionHandler @@ -104,7 +121,8 @@ class SingleParamStringOptionHandler : public tc::cli::OptionParser::IOptionHand public: SingleParamStringOptionHandler(tc::Optional& param, const std::vector& opts) : mParam(param), - mOptStrings(opts) + mOptStrings(opts), + mOptRegex() {} const std::vector& getOptionStrings() const @@ -112,6 +130,11 @@ public: return mOptStrings; } + const std::vector& getOptionRegexPatterns() const + { + return mOptRegex; + } + void processOption(const std::string& option, const std::vector& params) { if (params.size() != 1) @@ -124,6 +147,7 @@ public: private: tc::Optional& mParam; std::vector mOptStrings; + std::vector mOptRegex; }; class SingleParamPathOptionHandler : public tc::cli::OptionParser::IOptionHandler @@ -131,7 +155,8 @@ class SingleParamPathOptionHandler : public tc::cli::OptionParser::IOptionHandle public: SingleParamPathOptionHandler(tc::Optional& param, const std::vector& opts) : mParam(param), - mOptStrings(opts) + mOptStrings(opts), + mOptRegex() {} const std::vector& getOptionStrings() const @@ -139,6 +164,11 @@ public: return mOptStrings; } + const std::vector& getOptionRegexPatterns() const + { + return mOptRegex; + } + void processOption(const std::string& option, const std::vector& params) { if (params.size() != 1) @@ -151,6 +181,7 @@ public: private: tc::Optional& mParam; std::vector mOptStrings; + std::vector 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& opts) : mParam(param), - mOptStrings(opts) + mOptStrings(opts), + mOptRegex() {} const std::vector& getOptionStrings() const @@ -166,6 +198,11 @@ public: return mOptStrings; } + const std::vector& getOptionRegexPatterns() const + { + return mOptRegex; + } + void processOption(const std::string& option, const std::vector& params) { if (params.size() != 1) @@ -178,6 +215,7 @@ public: private: size_t& mParam; std::vector mOptStrings; + std::vector mOptRegex; }; class SingleParamAesKeyOptionHandler : public tc::cli::OptionParser::IOptionHandler @@ -185,7 +223,8 @@ class SingleParamAesKeyOptionHandler : public tc::cli::OptionParser::IOptionHand public: SingleParamAesKeyOptionHandler(tc::Optional& param, const std::vector& opts) : mParam(param), - mOptStrings(opts) + mOptStrings(opts), + mOptRegex() {} const std::vector& getOptionStrings() const @@ -193,6 +232,11 @@ public: return mOptStrings; } + const std::vector& getOptionRegexPatterns() const + { + return mOptRegex; + } + void processOption(const std::string& option, const std::vector& params) { if (params.size() != 1) @@ -214,6 +258,7 @@ public: private: tc::Optional& mParam; std::vector mOptStrings; + std::vector 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& opts) : mParam(param), - mOptStrings(opts) + mOptStrings(opts), + mOptRegex() {} const std::vector& getOptionStrings() const @@ -229,6 +275,11 @@ public: return mOptStrings; } + const std::vector& getOptionRegexPatterns() const + { + return mOptRegex; + } + void processOption(const std::string& option, const std::vector& params) { if (params.size() != 1) @@ -310,6 +361,7 @@ public: private: nstool::Settings::FileType& mParam; std::vector mOptStrings; + std::vector 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& opts) : mParam(param), - mOptStrings(opts) + mOptStrings(opts), + mOptRegex() {} const std::vector& getOptionStrings() const @@ -325,6 +378,11 @@ public: return mOptStrings; } + const std::vector& getOptionRegexPatterns() const + { + return mOptRegex; + } + void processOption(const std::string& option, const std::vector& params) { if (params.size() != 1) @@ -348,14 +406,16 @@ public: private: bool& mParam; std::vector mOptStrings; + std::vector mOptRegex; }; -class ExtractDataPathOptionHandler : public tc::cli::OptionParser::IOptionHandler +class ListArchiveJobPathOptionHandler : public tc::cli::OptionParser::IOptionHandler { public: - ExtractDataPathOptionHandler(std::vector& jobs, const std::vector& opts) : + ListArchiveJobPathOptionHandler(std::vector& jobs, const std::vector& opts) : mJobs(jobs), - mOptStrings(opts) + mOptStrings(opts), + mOptRegex() {} const std::vector& getOptionStrings() const @@ -363,15 +423,60 @@ public: return mOptStrings; } + const std::vector& getOptionRegexPatterns() const + { + return mOptRegex; + } + + void processOption(const std::string& option, const std::vector& 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} []\".", option, option)); + } + } +private: + std::vector& mJobs; + std::vector mOptStrings; + std::vector mOptRegex; +}; + +class ExtractArchiveJobPathOptionHandler : public tc::cli::OptionParser::IOptionHandler +{ +public: + ExtractArchiveJobPathOptionHandler(std::vector& jobs, const std::vector& opts) : + mJobs(jobs), + mOptStrings(opts), + mOptRegex() + {} + + const std::vector& getOptionStrings() const + { + return mOptStrings; + } + + const std::vector& getOptionRegexPatterns() const + { + return mOptRegex; + } + void processOption(const std::string& option, const std::vector& 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& mJobs; + std::vector& mJobs; std::vector mOptStrings; + std::vector mOptRegex; }; -class CustomExtractDataPathOptionHandler : public tc::cli::OptionParser::IOptionHandler +class CustomExtractArchiveJobPathOptionHandler : public tc::cli::OptionParser::IOptionHandler { public: - CustomExtractDataPathOptionHandler(std::vector& jobs, const std::vector& opts, const tc::io::Path& custom_path) : + CustomExtractArchiveJobPathOptionHandler(std::vector& jobs, const std::vector& 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& getOptionRegexPatterns() const + { + return mOptRegex; + } + void processOption(const std::string& option, const std::vector& params) { if (params.size() != 1) @@ -417,13 +529,13 @@ 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& mJobs; + std::vector& mJobs; std::vector mOptStrings; + std::vector mOptRegex; tc::io::Path mCustomPath; }; @@ -536,6 +648,7 @@ void nstool::SettingsInitializer::parse_args(const std::vector& arg // register handler for deprecated options DeprecatedOptionHandler // none just yet + //opts.registerOptionHandler(std::shared_ptr(new DeprecatedOptionHandler("warning message here", {"--dep-option"}))); // get option flags opts.registerOptionHandler(std::shared_ptr(new FlagOptionHandler(mShowLayout, {"--showlayout"}))); @@ -560,21 +673,21 @@ void nstool::SettingsInitializer::parse_args(const std::vector& arg opts.registerOptionHandler(std::shared_ptr(new InstructionTypeOptionHandler(code.is_64bit_instruction, { "--insttype" }))); // fs options - opts.registerOptionHandler(std::shared_ptr(new FlagOptionHandler(fs.show_fs_tree, { "--fstree", "--listfs" }))); - opts.registerOptionHandler(std::shared_ptr(new ExtractDataPathOptionHandler(fs.extract_jobs, { "-x", "--extract" }))); - opts.registerOptionHandler(std::shared_ptr(new CustomExtractDataPathOptionHandler(fs.extract_jobs, { "--fsdir" }, tc::io::Path("/")))); + opts.registerOptionHandler(std::shared_ptr(new ListArchiveJobPathOptionHandler(fs.archive_jobs, { "--fstree", "--listfs" }))); + opts.registerOptionHandler(std::shared_ptr(new ExtractArchiveJobPathOptionHandler(fs.archive_jobs, { "-x", "--extract" }))); + opts.registerOptionHandler(std::shared_ptr(new CustomExtractArchiveJobPathOptionHandler(fs.archive_jobs, { "--fsdir" }, tc::io::Path("/")))); // xci options - opts.registerOptionHandler(std::shared_ptr(new CustomExtractDataPathOptionHandler(fs.extract_jobs, { "--update" }, tc::io::Path("/update/")))); - opts.registerOptionHandler(std::shared_ptr(new CustomExtractDataPathOptionHandler(fs.extract_jobs, { "--normal" }, tc::io::Path("/normal/")))); - opts.registerOptionHandler(std::shared_ptr(new CustomExtractDataPathOptionHandler(fs.extract_jobs, { "--secure" }, tc::io::Path("/secure/")))); - opts.registerOptionHandler(std::shared_ptr(new CustomExtractDataPathOptionHandler(fs.extract_jobs, { "--logo" }, tc::io::Path("/logo/")))); + opts.registerOptionHandler(std::shared_ptr(new CustomExtractArchiveJobPathOptionHandler(fs.archive_jobs, { "--update" }, tc::io::Path("/update/")))); + opts.registerOptionHandler(std::shared_ptr(new CustomExtractArchiveJobPathOptionHandler(fs.archive_jobs, { "--normal" }, tc::io::Path("/normal/")))); + opts.registerOptionHandler(std::shared_ptr(new CustomExtractArchiveJobPathOptionHandler(fs.archive_jobs, { "--secure" }, tc::io::Path("/secure/")))); + opts.registerOptionHandler(std::shared_ptr(new CustomExtractArchiveJobPathOptionHandler(fs.archive_jobs, { "--logo" }, tc::io::Path("/logo/")))); // nca options - opts.registerOptionHandler(std::shared_ptr(new CustomExtractDataPathOptionHandler(fs.extract_jobs, { "--part0" }, tc::io::Path("/0/")))); - opts.registerOptionHandler(std::shared_ptr(new CustomExtractDataPathOptionHandler(fs.extract_jobs, { "--part1" }, tc::io::Path("/1/")))); - opts.registerOptionHandler(std::shared_ptr(new CustomExtractDataPathOptionHandler(fs.extract_jobs, { "--part2" }, tc::io::Path("/2/")))); - opts.registerOptionHandler(std::shared_ptr(new CustomExtractDataPathOptionHandler(fs.extract_jobs, { "--part3" }, tc::io::Path("/3/")))); + opts.registerOptionHandler(std::shared_ptr(new CustomExtractArchiveJobPathOptionHandler(fs.archive_jobs, { "--part0" }, tc::io::Path("/0/")))); + opts.registerOptionHandler(std::shared_ptr(new CustomExtractArchiveJobPathOptionHandler(fs.archive_jobs, { "--part1" }, tc::io::Path("/1/")))); + opts.registerOptionHandler(std::shared_ptr(new CustomExtractArchiveJobPathOptionHandler(fs.archive_jobs, { "--part2" }, tc::io::Path("/2/")))); + opts.registerOptionHandler(std::shared_ptr(new CustomExtractArchiveJobPathOptionHandler(fs.archive_jobs, { "--part3" }, tc::io::Path("/3/")))); // kip options opts.registerOptionHandler(std::shared_ptr(new SingleParamPathOptionHandler(kip.extract_path, { "--kipdir" }))); diff --git a/src/Settings.h b/src/Settings.h index 2406f54..d321d05 100644 --- a/src/Settings.h +++ b/src/Settings.h @@ -56,27 +56,14 @@ struct Settings // Generic FS options struct FsOptions { + // legacy bool show_fs_tree; std::vector extract_jobs; + + // new + std::vector archive_jobs; } fs; - // XCI options - struct XciOptions - { - tc::Optional update_extract_path; - tc::Optional logo_extract_path; - tc::Optional normal_extract_path; - tc::Optional secure_extract_path; - } xci; - - // NCA options - struct NcaOptions - { - tc::Optional part0_extract_path; - tc::Optional part1_extract_path; - tc::Optional part2_extract_path; - tc::Optional part3_extract_path; - } nca; // KIP options struct KipOptions @@ -107,6 +94,7 @@ struct Settings fs.show_fs_tree = false; fs.extract_jobs = std::vector(); + fs.archive_jobs = std::vector(); kip.extract_path = tc::Optional(); diff --git a/src/main.cpp b/src/main.cpp index 7e400ea..68bdce5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -37,6 +37,8 @@ int umain(const std::vector& args, const std::vector& 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& args, const std::vector& 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& args, const std::vector& 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& args, const std::vector& 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& args, const std::vector& 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); diff --git a/src/types.h b/src/types.h index f11c14d..da448d5 100644 --- a/src/types.h +++ b/src/types.h @@ -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;