mirror of
https://github.com/jakcron/nstool.git
synced 2025-12-24 20:51:32 +00:00
Merge 544a827a5e into cfb826ca6c
This commit is contained in:
commit
c058c464ec
35
BUILDING.md
35
BUILDING.md
|
|
@ -1,31 +1,52 @@
|
|||
# Building
|
||||
|
||||
## Git Submodules
|
||||
|
||||
This project makes use of git submodules to import dependencies into the source tree.
|
||||
After cloning this repository using git, prior to building NSTool the dependencies need to be downloaded.
|
||||
Run these two commands to initialise and download the dependencies:
|
||||
```
|
||||
|
||||
```bash
|
||||
git submodule init
|
||||
git submodule update
|
||||
```
|
||||
|
||||
## Linux (incl. Windows Subsystem for Linux) & MacOS - Makefile
|
||||
## Linux (including Windows Subsystem for Linux) & MacOS - Makefile
|
||||
|
||||
### Requirements
|
||||
|
||||
* `make`
|
||||
* Terminal access
|
||||
* Typical GNU compatible development tools (e.g. `clang`, `g++`, `c++`, `ar` etc) with __C++11__ support
|
||||
|
||||
### Using Makefile
|
||||
|
||||
* `make` (default) - Compile program
|
||||
* Compiling the program requires local dependencies to be compiled via `make deps` beforehand
|
||||
* Compiling the program requires local dependencies to be compiled via `make deps` beforehand
|
||||
* `make clean` - Remove executable and object files
|
||||
* `make deps` - Compile locally included dependency libraries
|
||||
* `make clean_deps` - Remove compiled library binaries and object files
|
||||
|
||||
## Native Windows - Visual Studio
|
||||
### Requirements
|
||||
* [Visual Studio Community](https://visualstudio.microsoft.com/vs/community/) 2015 / 2017 / 2019
|
||||
|
||||
### Compiling NSTool
|
||||
### Requirements
|
||||
|
||||
* [Visual Studio Community](https://visualstudio.microsoft.com/vs/community/) 2015 / 2017 / 2019 / 2022
|
||||
|
||||
### Compiling using the Visual Studio GUI
|
||||
|
||||
* Open `build/visualstudio/nstool.sln` in Visual Studio
|
||||
* Select Target (e.g `Debug`|`Release` & `x86`|`x64`)
|
||||
* Navigate to `Build`->`Build Solution`
|
||||
* Navigate to `Build`->`Build Solution`
|
||||
|
||||
### Compiling using the command line
|
||||
|
||||
* Open PowerShell
|
||||
* Paste and run the following command after double-checking the paths.
|
||||
|
||||
```bash
|
||||
& "C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\MSBuild\Current\Bin\MSBuild.exe" `
|
||||
"{full path to the cloned repository}\nstool\build\visualstudio\nstool.sln" `
|
||||
/p:Platform=x64 `
|
||||
/p:Configuration=Release
|
||||
```
|
||||
|
|
|
|||
76
README.md
76
README.md
|
|
@ -1,7 +1,9 @@
|
|||
# Nintendo Switch Tool (NSTool) 
|
||||
|
||||
General purpose reading/extraction tool for Nintendo Switch file formats.
|
||||
|
||||
## Supported File Formats
|
||||
|
||||
* PartitionFs (`PFS0`) (.pfs0)
|
||||
* Sha256PartitionFs (`HFS0`) (.hfs0)
|
||||
* RomFs (.romfs)
|
||||
|
|
@ -10,47 +12,58 @@ General purpose reading/extraction tool for Nintendo Switch file formats.
|
|||
* NX GameCard Image (.xci)
|
||||
* Meta (`META`) (.npdm)
|
||||
* Nintendo Application Control Property (.nacp)
|
||||
* Content Metadata (.cnmt)
|
||||
* Content Metadata (.cnmt)
|
||||
* ES Certificate (.cert)
|
||||
* ES Ticket (v2 only) (.tik)
|
||||
* Nintendo Shared Object (`NSO0`) (.nso)
|
||||
* Nintendo Shared Object (`NSO0`) (.nso)
|
||||
* Nintendo Relocatable Object (`NRO0`) (.nro)
|
||||
* Initial Program Bundle (`INI1`) (.ini)
|
||||
* Initial Program (`KIP1`) (.kip)
|
||||
|
||||
# Usage
|
||||
|
||||
## General usage
|
||||
|
||||
The default mode of NSTool is to show general information about a file.
|
||||
|
||||
To display general information the usage is as follows:
|
||||
```
|
||||
|
||||
```bash
|
||||
nstool some_file.bin
|
||||
```
|
||||
|
||||
However not all information is shown in this mode; file-layout, key data and properties set to default values are omitted.
|
||||
|
||||
## Alternative output modes
|
||||
|
||||
To output file-layout information, use the `--showlayout` option:
|
||||
```
|
||||
|
||||
```bash
|
||||
nstool --showlayout some_file.bin
|
||||
```
|
||||
|
||||
To output key data generation and selection, use the `--showkeys` option:
|
||||
```
|
||||
|
||||
```bash
|
||||
nstool --showkeys some_file.bin
|
||||
```
|
||||
|
||||
To output all information, enable the verbose output mode with the `-v` or `--verbose` option:
|
||||
```
|
||||
|
||||
```bash
|
||||
nstool -v some_file.bin
|
||||
```
|
||||
|
||||
## Specify File Type
|
||||
|
||||
NSTool will in most cases correctly identify the file type. However you can override this and manually specify the file type with the `-t` or `--type` option:
|
||||
```
|
||||
|
||||
```bash
|
||||
nstool -t cnmt some_file.bin
|
||||
```
|
||||
|
||||
In that example `cnmt` was selected, NSTool would process the file as `Content Metadata`. See below for a list of supported file type codes:
|
||||
|
||||
| Code | Description |
|
||||
| ----------- | --------------- |
|
||||
| gc, xci | NX GameCard Image |
|
||||
|
|
@ -71,14 +84,17 @@ In that example `cnmt` was selected, NSTool would process the file as `Content M
|
|||
| aset, asset | Homebrew NRO Asset Binary |
|
||||
|
||||
## Validate Input File
|
||||
|
||||
Some file types have signatures/hashes/fields that can be validated by NSTool, but this mode isn't enabled by default.
|
||||
|
||||
To validate files with NSTool, enable the verify mode with the `-y` or `--verify` option:
|
||||
```
|
||||
|
||||
```bash
|
||||
nstool -y some_file.bin
|
||||
```
|
||||
|
||||
See the below table for file types that support optional validation:
|
||||
|
||||
| File Type | Validation | Comments |
|
||||
| --------- | ---------- | -------- |
|
||||
| ES Certificate | Signature | If certificate is part of a certificate chain it will validate it as part of that chain. `Root` signed certificates are verified with user supplied `Root` public key. |
|
||||
|
|
@ -91,17 +107,21 @@ See the below table for file types that support optional validation:
|
|||
* As of NSTool v1.6.0 the public key(s) for `Root Certificate`, `XCI Header`, `ACID` and `NCA Header` are built-in, and will be used if the user does not supply the public key in a key file.
|
||||
|
||||
## DevKit Mode
|
||||
|
||||
Files generated for `Production` use different (for the most part) encryption/signing keys than files generated for `Development`. NSTool will select `Production` encryption/signing keys by default.
|
||||
When handling files intended for developer consoles (e.g. systemupdaters, devtools, test builds, etc), you should enable developer mode with the `-d`, `--dev` option:
|
||||
```
|
||||
|
||||
```bash
|
||||
nstool -d some_file.bin
|
||||
```
|
||||
|
||||
## Extract Files
|
||||
|
||||
Some file types have an internal file system. This can be displayed and extracted.
|
||||
|
||||
To display the file system tree, use the file tree option `--fstree`:
|
||||
```
|
||||
|
||||
```bash
|
||||
nstool --fstree some_file.bin
|
||||
```
|
||||
|
||||
|
|
@ -110,32 +130,29 @@ To extract the file system, use the extract option `-x`, `--extract`. Which has
|
|||
1) Extract the entire file system.
|
||||
|
||||
This extracts the contents of the entire file system to `./extract_dir/`. `extract_dir` will be created if it doesn't exist.
|
||||
```
|
||||
nstool -x ./extract_dir/ some_file.bin
|
||||
|
||||
```bash
|
||||
nstool --extract ./extract_dir/ some_file.bin
|
||||
```
|
||||
|
||||
2) Extract a sub directory.
|
||||
|
||||
This extracts the contents of `/a/sub/directory/` to `./extract_dir/`. `extract_dir` will be created if it doesn't exist.
|
||||
```
|
||||
nstool -x /a/sub/directory/ ./extract_dir/ some_file.bin
|
||||
|
||||
```bash
|
||||
nstool --extract /a/sub/directory/ ./extract_dir/ some_file.bin
|
||||
```
|
||||
|
||||
3) Extract a specific file, preserving the original name.
|
||||
3) Extract a specific file while preserving the original name.
|
||||
|
||||
This extracts `/path/to/a/file.bin` to `./extract_dir/file.bin`.
|
||||
```
|
||||
nstool -x /path/to/a/file.bin ./extract_dir/ some_file.bin
|
||||
```
|
||||
|
||||
4) Extract a specific file with a custom name.
|
||||
|
||||
This extracts `/path/to/a/file.bin` to `./extract_dir/different_name.bin`.
|
||||
```
|
||||
nstool -x /path/to/a/file.bin ./extract_dir/different_name.bin some_file.bin
|
||||
```bash
|
||||
nstool --extract ./extract_dir/ --file filename.bin some_file.bin
|
||||
```
|
||||
|
||||
### Supported File Types
|
||||
|
||||
* PartitionFs
|
||||
* Sha256PartitionFs
|
||||
* RomFs (including RomFs embedded in Homebrew NRO)
|
||||
|
|
@ -144,24 +161,29 @@ nstool -x /path/to/a/file.bin ./extract_dir/different_name.bin some_file.bin
|
|||
* XCI
|
||||
|
||||
## NCA Patches
|
||||
|
||||
Nintendo distributes game patches/updates in the style of a diff to keep file sizes down. This means extracting game patches requires the base version of the game to be able to process patch data. Typically this is only done for the Program NCA.
|
||||
|
||||
If `basegame_v0.nca` is the base Program NCA, and `gamepatch_v13219.nca` is the patch Program NCA, simply specify the base NCA using the base NCA option `--basenca` when processing the patch NCA.
|
||||
|
||||
```
|
||||
```bash
|
||||
nstool --basenca ./basegame_v0.nca -x ./patchdata gamepatch_v13219.nca
|
||||
```
|
||||
|
||||
In the above example the patch NCA is being extracted to `./patchdata`
|
||||
|
||||
## Encrypted Files
|
||||
Some Nintendo Switch files are partially or completely encrypted. These require the user to supply the encryption keys to NSTool so that it can process them.
|
||||
|
||||
Some Nintendo Switch files are partially or completely encrypted. These require the user to supply the encryption keys to NSTool so that it can process them.
|
||||
|
||||
See [SWITCH_KEYS.md](/SWITCH_KEYS.md) for more info.
|
||||
|
||||
# External Keys
|
||||
NSTool doesn't embed any keys that are copyright protected. However keys can be imported via various keyset files.
|
||||
|
||||
NSTool doesn't embed any keys that are copyright protected. However keys can be imported via various keyset files.
|
||||
|
||||
See [SWITCH_KEYS.md](/SWITCH_KEYS.md) for more info.
|
||||
|
||||
# Building
|
||||
See [BUILDING.md](/BUILDING.md).
|
||||
|
||||
See [BUILDING.md](/BUILDING.md).
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ nstool::FsProcess::FsProcess() :
|
|||
mShowFsInfo(false),
|
||||
mProperties(),
|
||||
mShowFsTree(false),
|
||||
mOutputFile(),
|
||||
mFsRootLabel(),
|
||||
mExtractJobs(),
|
||||
mDataCache(0x10000)
|
||||
|
|
@ -39,7 +40,7 @@ void nstool::FsProcess::process()
|
|||
{
|
||||
printFs();
|
||||
}
|
||||
|
||||
|
||||
if (mExtractJobs.empty() == false)
|
||||
{
|
||||
extractFs();
|
||||
|
|
@ -81,6 +82,11 @@ void nstool::FsProcess::setExtractJobs(const std::vector<nstool::ExtractJob>& ex
|
|||
mExtractJobs = extract_jobs;
|
||||
}
|
||||
|
||||
void nstool::FsProcess::setExtractFile(std::string outputFile)
|
||||
{
|
||||
mOutputFile = outputFile;
|
||||
}
|
||||
|
||||
void nstool::FsProcess::printFs()
|
||||
{
|
||||
fmt::print("[{:s}/Tree]\n", (mFsFormatName.isSet() ? mFsFormatName.get() : "FileSystem"));
|
||||
|
|
@ -124,7 +130,7 @@ void nstool::FsProcess::extractFs()
|
|||
|
||||
tc::io::Path file_extract_path = itr->extract_path + itr->virtual_path.back();
|
||||
|
||||
fmt::print("Saving {:s}...\n", file_extract_path.to_string());
|
||||
fmt::print("Extracting file to {:s}...\n", file_extract_path.to_string());
|
||||
|
||||
writeStreamToFile(file_stream, itr->extract_path + itr->virtual_path.back(), mDataCache);
|
||||
|
||||
|
|
@ -142,7 +148,7 @@ void nstool::FsProcess::extractFs()
|
|||
// get path to parent directory
|
||||
tc::io::Path parent_dir_path = itr->extract_path;
|
||||
|
||||
// replace final path element with the current directory alias
|
||||
// replace final path element with the current directory alias
|
||||
parent_dir_path.pop_back(); // remove filename
|
||||
parent_dir_path.push_back("."); // replace with the current dir name alias
|
||||
|
||||
|
|
@ -185,7 +191,7 @@ void nstool::FsProcess::extractFs()
|
|||
|
||||
fmt::print("[WARNING] Failed to extract virtual path: \"{:s}\"\n", itr->virtual_path.to_string());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
void nstool::FsProcess::visitDir(const tc::io::Path& v_path, const tc::io::Path& l_path, bool extract_fs, bool print_fs)
|
||||
|
|
@ -216,17 +222,17 @@ void nstool::FsProcess::visitDir(const tc::io::Path& v_path, const tc::io::Path&
|
|||
std::shared_ptr<tc::io::IStream> out_stream;
|
||||
for (auto itr = info.file_list.begin(); itr != info.file_list.end(); itr++)
|
||||
{
|
||||
// build out path
|
||||
out_path = l_path + *itr;
|
||||
|
||||
if (print_fs)
|
||||
{
|
||||
for (size_t i = 0; i < v_path.size(); i++)
|
||||
fmt::print(" ");
|
||||
fmt::print(" {:s}\n", *itr);
|
||||
}
|
||||
if (extract_fs)
|
||||
if (extract_fs && (mOutputFile == "" || (mOutputFile == *itr)))
|
||||
{
|
||||
// build out path
|
||||
out_path = l_path + *itr;
|
||||
|
||||
fmt::print("Saving {:s}...\n", out_path.to_string());
|
||||
|
||||
// begin export
|
||||
|
|
@ -240,7 +246,7 @@ void nstool::FsProcess::visitDir(const tc::io::Path& v_path, const tc::io::Path&
|
|||
cache_read_len = in_stream->read(mDataCache.data(), mDataCache.size());
|
||||
if (cache_read_len == 0)
|
||||
{
|
||||
throw tc::io::IOException(mModuleLabel, fmt::format("Failed to read from {:s}file.", (mFsFormatName.isSet() ? (mFsFormatName.get() + " ") : "")));
|
||||
throw tc::io::IOException(mModuleLabel, fmt::format("Failed to read from {:s} file.", (mFsFormatName.isSet() ? (mFsFormatName.get() + " ") : "")));
|
||||
}
|
||||
|
||||
out_stream->write(mDataCache.data(), cache_read_len);
|
||||
|
|
@ -250,9 +256,12 @@ void nstool::FsProcess::visitDir(const tc::io::Path& v_path, const tc::io::Path&
|
|||
}
|
||||
}
|
||||
|
||||
// iterate thru child dirs
|
||||
// iterate through child directories
|
||||
for (auto itr = info.dir_list.begin(); itr != info.dir_list.end(); itr++)
|
||||
{
|
||||
visitDir(v_path + *itr, l_path + *itr, extract_fs, print_fs);
|
||||
// When traversing each directory append the directory to the local path only if we're not looking to extract a single file.
|
||||
const tc::io::Path localPath = mOutputFile == "" ? l_path + *itr : l_path;
|
||||
|
||||
visitDir(v_path + *itr, localPath, extract_fs, print_fs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 setExtractFile(std::string outputFile);
|
||||
private:
|
||||
std::string mModuleLabel;
|
||||
|
||||
|
|
@ -37,10 +38,11 @@ private:
|
|||
|
||||
// extract jobs
|
||||
std::vector<nstool::ExtractJob> mExtractJobs;
|
||||
std::string mOutputFile;
|
||||
|
||||
// cache for file extract
|
||||
tc::ByteData mDataCache;
|
||||
|
||||
|
||||
void printFs();
|
||||
void extractFs();
|
||||
|
||||
|
|
|
|||
|
|
@ -46,6 +46,11 @@ void nstool::GameCardProcess::setInputFile(const std::shared_ptr<tc::io::IStream
|
|||
mFile = file;
|
||||
}
|
||||
|
||||
void nstool::GameCardProcess::setOutputFile(const std::string& file)
|
||||
{
|
||||
mOutputFile = file;
|
||||
}
|
||||
|
||||
void nstool::GameCardProcess::setKeyCfg(const KeyBag& keycfg)
|
||||
{
|
||||
mKeyCfg = keycfg;
|
||||
|
|
@ -69,6 +74,7 @@ void nstool::GameCardProcess::setShowFsTree(bool show_fs_tree)
|
|||
void nstool::GameCardProcess::setExtractJobs(const std::vector<nstool::ExtractJob> extract_jobs)
|
||||
{
|
||||
mFsProcess.setExtractJobs(extract_jobs);
|
||||
mFsProcess.setExtractFile(mOutputFile);
|
||||
}
|
||||
|
||||
void nstool::GameCardProcess::importHeader()
|
||||
|
|
@ -81,7 +87,7 @@ void nstool::GameCardProcess::importHeader()
|
|||
{
|
||||
throw tc::NotSupportedException(mModuleName, "Input stream requires read/seek permissions.");
|
||||
}
|
||||
|
||||
|
||||
// check stream is large enough for header
|
||||
if (mFile->length() < tc::io::IOUtil::castSizeToInt64(sizeof(pie::hac::sSdkGcHeader)))
|
||||
{
|
||||
|
|
@ -106,7 +112,7 @@ void nstool::GameCardProcess::importHeader()
|
|||
mIsTrueSdkXci = false;
|
||||
mGcHeaderOffset = 0;
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
throw tc::Exception(mModuleName, "Corrupt GameCard Image: Unexpected magic bytes.");
|
||||
}
|
||||
|
|
@ -115,10 +121,10 @@ void nstool::GameCardProcess::importHeader()
|
|||
|
||||
// generate hash of raw header
|
||||
tc::crypto::GenerateSha2256Hash(mHdrHash.data(), (byte_t*)&hdr_ptr->header, sizeof(pie::hac::sGcHeader));
|
||||
|
||||
|
||||
// save the signature
|
||||
memcpy(mHdrSignature.data(), hdr_ptr->signature.data(), mHdrSignature.size());
|
||||
|
||||
|
||||
// decrypt extended header
|
||||
byte_t xci_header_key_index = hdr_ptr->header.key_flag & 0xf;
|
||||
if (mKeyCfg.xci_header_key.find(xci_header_key_index) != mKeyCfg.xci_header_key.end())
|
||||
|
|
@ -126,7 +132,7 @@ void nstool::GameCardProcess::importHeader()
|
|||
pie::hac::GameCardUtil::decryptXciHeader(&hdr_ptr->header, mKeyCfg.xci_header_key[xci_header_key_index].data());
|
||||
mProccessExtendedHeader = true;
|
||||
}
|
||||
|
||||
|
||||
// deserialise header
|
||||
mHdr.fromBytes((byte_t*)&hdr_ptr->header, sizeof(pie::hac::sGcHeader));
|
||||
}
|
||||
|
|
@ -147,8 +153,8 @@ void nstool::GameCardProcess::displayHeader()
|
|||
{
|
||||
fmt::print(" {:s}\n", pie::hac::GameCardUtil::getHeaderFlagsAsString((pie::hac::gc::HeaderFlags)*itr));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
if (mCliOutputMode.show_extended_info)
|
||||
{
|
||||
fmt::print(" KekIndex: {:s} ({:d})\n", pie::hac::GameCardUtil::getKekIndexAsString((pie::hac::gc::KekIndex)mHdr.getKekIndex()), mHdr.getKekIndex());
|
||||
|
|
@ -197,7 +203,7 @@ void nstool::GameCardProcess::displayHeader()
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (mProccessExtendedHeader)
|
||||
{
|
||||
fmt::print("[GameCard/ExtendedHeader]\n");
|
||||
|
|
@ -252,7 +258,7 @@ void nstool::GameCardProcess::validateXciSignature()
|
|||
fmt::print("[WARNING] GameCard Header Signature: FAIL\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
fmt::print("[WARNING] GameCard Header Signature: FAIL (Failed to load rsa public key.)\n");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ public:
|
|||
|
||||
// generic
|
||||
void setInputFile(const std::shared_ptr<tc::io::IStream>& file);
|
||||
void setOutputFile(const std::string& file);
|
||||
void setKeyCfg(const KeyBag& keycfg);
|
||||
void setCliOutputMode(CliOutputMode type);
|
||||
void setVerifyMode(bool verify);
|
||||
|
|
@ -29,10 +30,11 @@ private:
|
|||
std::string mModuleName;
|
||||
|
||||
std::shared_ptr<tc::io::IStream> mFile;
|
||||
std::string mOutputFile;
|
||||
KeyBag mKeyCfg;
|
||||
CliOutputMode mCliOutputMode;
|
||||
bool mVerify;
|
||||
|
||||
|
||||
bool mIsTrueSdkXci;
|
||||
bool mIsSdkXciEncrypted;
|
||||
size_t mGcHeaderOffset;
|
||||
|
|
@ -40,7 +42,7 @@ private:
|
|||
pie::hac::detail::rsa2048_signature_t mHdrSignature;
|
||||
pie::hac::detail::sha256_hash_t mHdrHash;
|
||||
pie::hac::GameCardHeader mHdr;
|
||||
|
||||
|
||||
// fs processing
|
||||
std::shared_ptr<tc::io::IFileSystem> mFileSystem;
|
||||
FsProcess mFsProcess;
|
||||
|
|
|
|||
|
|
@ -49,6 +49,11 @@ void nstool::NcaProcess::setInputFile(const std::shared_ptr<tc::io::IStream>& fi
|
|||
mFile = file;
|
||||
}
|
||||
|
||||
void nstool::NcaProcess::setOutputFile(const std::string& file)
|
||||
{
|
||||
mOutputFile = file;
|
||||
}
|
||||
|
||||
void nstool::NcaProcess::setBaseNcaPath(const tc::Optional<tc::io::Path>& nca_path)
|
||||
{
|
||||
mBaseNcaPath = nca_path;
|
||||
|
|
@ -82,6 +87,7 @@ void nstool::NcaProcess::setFsRootLabel(const std::string& root_label)
|
|||
void nstool::NcaProcess::setExtractJobs(const std::vector<nstool::ExtractJob>& extract_jobs)
|
||||
{
|
||||
mFsProcess.setExtractJobs(extract_jobs);
|
||||
mFsProcess.setExtractFile(mOutputFile);
|
||||
}
|
||||
|
||||
const std::shared_ptr<tc::io::IFileSystem>& nstool::NcaProcess::getFileSystem() const
|
||||
|
|
@ -127,7 +133,7 @@ void nstool::NcaProcess::generateNcaBodyEncryptionKeys()
|
|||
// create zeros key
|
||||
KeyBag::aes128_key_t zero_aesctr_key;
|
||||
memset(zero_aesctr_key.data(), 0, zero_aesctr_key.size());
|
||||
|
||||
|
||||
// get key data from header
|
||||
byte_t masterkey_rev = pie::hac::AesKeygen::getMasterKeyRevisionFromKeyGeneration(mHdr.getKeyGeneration());
|
||||
byte_t keak_index = mHdr.getKeyAreaEncryptionKeyIndex();
|
||||
|
|
@ -215,7 +221,7 @@ void nstool::NcaProcess::generateNcaBodyEncryptionKeys()
|
|||
mContentKey.aes_ctr = mKeyCfg.fallback_content_key.get();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (mCliOutputMode.show_keydata)
|
||||
{
|
||||
if (mContentKey.aes_ctr.isSet())
|
||||
|
|
@ -276,7 +282,7 @@ void nstool::NcaProcess::generatePartitionConfiguration()
|
|||
throw tc::Exception(mModuleName, fmt::format("NCA FS Header [{:d}] Version({:d}): UNSUPPORTED", partition.header_index, fs_header.version.unwrap()));
|
||||
}
|
||||
|
||||
// setup AES-CTR
|
||||
// setup AES-CTR
|
||||
pie::hac::ContentArchiveUtil::getNcaPartitionAesCtr(&fs_header, info.aes_ctr.data());
|
||||
|
||||
// save partition configinfo
|
||||
|
|
@ -290,14 +296,14 @@ void nstool::NcaProcess::generatePartitionConfiguration()
|
|||
if (info.hash_type == pie::hac::nca::HashType_HierarchicalSha256)
|
||||
{
|
||||
info.hierarchicalsha256_hdr.fromBytes(fs_header.hash_info.data(), fs_header.hash_info.size());
|
||||
}
|
||||
}
|
||||
else if (info.hash_type == pie::hac::nca::HashType_HierarchicalIntegrity)
|
||||
{
|
||||
info.hierarchicalintegrity_hdr.fromBytes(fs_header.hash_info.data(), fs_header.hash_info.size());
|
||||
}
|
||||
|
||||
// create reader
|
||||
try
|
||||
try
|
||||
{
|
||||
// handle partition encryption and partition compaction (sparse layer)
|
||||
if (fs_header.sparse_info.generation.unwrap() != 0)
|
||||
|
|
@ -430,7 +436,7 @@ void nstool::NcaProcess::validateNcaSignatures()
|
|||
{
|
||||
fmt::print("[WARNING] NCA Header Main Signature: FAIL (could not load header key)\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
// validate signature[1]
|
||||
if (mHdr.getContentType() == pie::hac::nca::ContentType_Program)
|
||||
|
|
@ -493,7 +499,7 @@ void nstool::NcaProcess::displayHeader()
|
|||
{
|
||||
fmt::print(" RightsId: {:s}\n", tc::cli::FormatUtil::formatBytesAsString(mHdr.getRightsId().data(), mHdr.getRightsId().size(), true, ""));
|
||||
}
|
||||
|
||||
|
||||
if (mContentKey.kak_list.size() > 0 && mCliOutputMode.show_keydata)
|
||||
{
|
||||
fmt::print(" Key Area:\n");
|
||||
|
|
@ -504,9 +510,9 @@ void nstool::NcaProcess::displayHeader()
|
|||
{
|
||||
std::string enc_key = tc::cli::FormatUtil::formatBytesAsString(mContentKey.kak_list[i].enc.data(), mContentKey.kak_list[i].enc.size(), true, "");
|
||||
std::string dec_key = mContentKey.kak_list[i].decrypted ? tc::cli::FormatUtil::formatBytesAsString(mContentKey.kak_list[i].dec.data(), mContentKey.kak_list[i].dec.size(), true, "") : "<unable to decrypt>";
|
||||
|
||||
|
||||
fmt::print(" | {:3d} | {:32s} | {:32s} |\n", mContentKey.kak_list[i].index, enc_key, dec_key);
|
||||
|
||||
|
||||
}
|
||||
fmt::print(" <--------------------------------------------------------------------------->\n");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ public:
|
|||
|
||||
// generic
|
||||
void setInputFile(const std::shared_ptr<tc::io::IStream>& file);
|
||||
void setOutputFile(const std::string& file);
|
||||
void setKeyCfg(const KeyBag& keycfg);
|
||||
void setCliOutputMode(CliOutputMode type);
|
||||
void setVerifyMode(bool verify);
|
||||
|
|
@ -38,6 +39,7 @@ private:
|
|||
|
||||
// user options
|
||||
std::shared_ptr<tc::io::IStream> mFile;
|
||||
std::string mOutputFile;
|
||||
KeyBag mKeyCfg;
|
||||
CliOutputMode mCliOutputMode;
|
||||
bool mVerify;
|
||||
|
|
@ -121,7 +123,7 @@ private:
|
|||
// sparse metadata
|
||||
SparseInfo sparse_info;
|
||||
};
|
||||
|
||||
|
||||
std::array<sPartitionInfo, pie::hac::nca::kPartitionNum> mPartitions;
|
||||
|
||||
void importHeader();
|
||||
|
|
|
|||
|
|
@ -67,10 +67,10 @@ void nstool::PfsProcess::process()
|
|||
|
||||
// set properties for FsProcess
|
||||
mFsProcess.setFsProperties({
|
||||
fmt::format("Type: {:s}", pie::hac::PartitionFsUtil::getFsTypeAsString(mPfs.getFsType())),
|
||||
fmt::format("Type: {:s}", pie::hac::PartitionFsUtil::getFsTypeAsString(mPfs.getFsType())),
|
||||
fmt::format("FileNum: {:d}", mPfs.getFileList().size())
|
||||
});
|
||||
|
||||
|
||||
mFsProcess.process();
|
||||
}
|
||||
|
||||
|
|
@ -79,6 +79,11 @@ void nstool::PfsProcess::setInputFile(const std::shared_ptr<tc::io::IStream>& fi
|
|||
mFile = file;
|
||||
}
|
||||
|
||||
void nstool::PfsProcess::setOutputFile(const std::string& file)
|
||||
{
|
||||
mOutputFile = file;
|
||||
}
|
||||
|
||||
void nstool::PfsProcess::setCliOutputMode(CliOutputMode type)
|
||||
{
|
||||
mCliOutputMode = type;
|
||||
|
|
@ -103,6 +108,7 @@ void nstool::PfsProcess::setFsRootLabel(const std::string& root_label)
|
|||
void nstool::PfsProcess::setExtractJobs(const std::vector<nstool::ExtractJob>& extract_jobs)
|
||||
{
|
||||
mFsProcess.setExtractJobs(extract_jobs);
|
||||
mFsProcess.setExtractFile(mOutputFile);
|
||||
}
|
||||
|
||||
const pie::hac::PartitionFsHeader& nstool::PfsProcess::getPfsHeader() const
|
||||
|
|
@ -118,6 +124,13 @@ const std::shared_ptr<tc::io::IFileSystem>& nstool::PfsProcess::getFileSystem()
|
|||
size_t nstool::PfsProcess::determineHeaderSize(const pie::hac::sPfsHeader* hdr)
|
||||
{
|
||||
size_t fileEntrySize = 0;
|
||||
|
||||
if (hdr->st_magic.unwrap() == pie::hac::pfs::kPfsStructMagic) {
|
||||
fileEntrySize = sizeof(pie::hac::sPfsFile);
|
||||
} else {
|
||||
fileEntrySize = sizeof(pie::hac::sHashedPfsFile);
|
||||
}
|
||||
|
||||
if (hdr->st_magic.unwrap() == pie::hac::pfs::kPfsStructMagic)
|
||||
fileEntrySize = sizeof(pie::hac::sPfsFile);
|
||||
else
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ public:
|
|||
|
||||
// generic
|
||||
void setInputFile(const std::shared_ptr<tc::io::IStream>& file);
|
||||
void setOutputFile(const std::string& file);
|
||||
void setCliOutputMode(CliOutputMode type);
|
||||
void setVerifyMode(bool verify);
|
||||
|
||||
|
|
@ -33,6 +34,7 @@ private:
|
|||
std::string mModuleName;
|
||||
|
||||
std::shared_ptr<tc::io::IStream> mFile;
|
||||
std::string mOutputFile;
|
||||
CliOutputMode mCliOutputMode;
|
||||
bool mVerify;
|
||||
|
||||
|
|
@ -40,7 +42,7 @@ private:
|
|||
|
||||
std::shared_ptr<tc::io::IFileSystem> mFileSystem;
|
||||
FsProcess mFsProcess;
|
||||
|
||||
|
||||
size_t determineHeaderSize(const pie::hac::sPfsHeader* hdr);
|
||||
bool validateHeaderMagic(const pie::hac::sPfsHeader* hdr);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ void nstool::RomfsProcess::process()
|
|||
|
||||
// set properties for FsProcess
|
||||
mFsProcess.setFsProperties({
|
||||
fmt::format("DirNum: {:d}", mDirNum),
|
||||
fmt::format("DirNum: {:d}", mDirNum),
|
||||
fmt::format("FileNum: {:d}", mFileNum)
|
||||
});
|
||||
|
||||
|
|
@ -126,6 +126,11 @@ void nstool::RomfsProcess::setInputFile(const std::shared_ptr<tc::io::IStream>&
|
|||
mFile = file;
|
||||
}
|
||||
|
||||
void nstool::RomfsProcess::setOutputFile(const std::string& file)
|
||||
{
|
||||
mOutputFile = file;
|
||||
}
|
||||
|
||||
void nstool::RomfsProcess::setCliOutputMode(CliOutputMode type)
|
||||
{
|
||||
mCliOutputMode = type;
|
||||
|
|
@ -145,6 +150,7 @@ void nstool::RomfsProcess::setFsRootLabel(const std::string& root_label)
|
|||
void nstool::RomfsProcess::setExtractJobs(const std::vector<nstool::ExtractJob>& extract_jobs)
|
||||
{
|
||||
mFsProcess.setExtractJobs(extract_jobs);
|
||||
mFsProcess.setExtractFile(mOutputFile);
|
||||
}
|
||||
|
||||
void nstool::RomfsProcess::setShowFsTree(bool list_fs)
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ public:
|
|||
|
||||
// generic
|
||||
void setInputFile(const std::shared_ptr<tc::io::IStream>& file);
|
||||
void setOutputFile(const std::string& file);
|
||||
void setCliOutputMode(CliOutputMode type);
|
||||
void setVerifyMode(bool verify);
|
||||
|
||||
|
|
@ -28,6 +29,7 @@ private:
|
|||
std::string mModuleName;
|
||||
|
||||
std::shared_ptr<tc::io::IStream> mFile;
|
||||
std::string mOutputFile;
|
||||
CliOutputMode mCliOutputMode;
|
||||
bool mVerify;
|
||||
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ private:
|
|||
class DeprecatedOptionHandler : public tc::cli::OptionParser::IOptionHandler
|
||||
{
|
||||
public:
|
||||
DeprecatedOptionHandler(const std::string& warn_message, const std::vector<std::string>& opts) :
|
||||
DeprecatedOptionHandler(const std::string& warn_message, const std::vector<std::string>& opts) :
|
||||
mWarnMessage(warn_message),
|
||||
mOptStrings(opts),
|
||||
mOptRegex()
|
||||
|
|
@ -84,7 +84,7 @@ private:
|
|||
class FlagOptionHandler : public tc::cli::OptionParser::IOptionHandler
|
||||
{
|
||||
public:
|
||||
FlagOptionHandler(bool& flag, const std::vector<std::string>& opts) :
|
||||
FlagOptionHandler(bool& flag, const std::vector<std::string>& opts) :
|
||||
mFlag(flag),
|
||||
mOptStrings(opts),
|
||||
mOptRegex()
|
||||
|
|
@ -118,7 +118,7 @@ private:
|
|||
class SingleParamStringOptionHandler : public tc::cli::OptionParser::IOptionHandler
|
||||
{
|
||||
public:
|
||||
SingleParamStringOptionHandler(tc::Optional<std::string>& param, const std::vector<std::string>& opts) :
|
||||
SingleParamStringOptionHandler(tc::Optional<std::string>& param, const std::vector<std::string>& opts) :
|
||||
mParam(param),
|
||||
mOptStrings(opts),
|
||||
mOptRegex()
|
||||
|
|
@ -152,7 +152,7 @@ private:
|
|||
class SingleParamPathOptionHandler : public tc::cli::OptionParser::IOptionHandler
|
||||
{
|
||||
public:
|
||||
SingleParamPathOptionHandler(tc::Optional<tc::io::Path>& param, const std::vector<std::string>& opts) :
|
||||
SingleParamPathOptionHandler(tc::Optional<tc::io::Path>& param, const std::vector<std::string>& opts) :
|
||||
mParam(param),
|
||||
mOptStrings(opts),
|
||||
mOptRegex()
|
||||
|
|
@ -186,7 +186,7 @@ private:
|
|||
class SingleParamSizetOptionHandler : public tc::cli::OptionParser::IOptionHandler
|
||||
{
|
||||
public:
|
||||
SingleParamSizetOptionHandler(size_t& param, const std::vector<std::string>& opts) :
|
||||
SingleParamSizetOptionHandler(size_t& param, const std::vector<std::string>& opts) :
|
||||
mParam(param),
|
||||
mOptStrings(opts),
|
||||
mOptRegex()
|
||||
|
|
@ -263,7 +263,7 @@ private:
|
|||
class SingleParamPathArrayOptionHandler : public tc::cli::OptionParser::IOptionHandler
|
||||
{
|
||||
public:
|
||||
SingleParamPathArrayOptionHandler(std::vector<tc::io::Path>& param, const std::vector<std::string>& opts) :
|
||||
SingleParamPathArrayOptionHandler(std::vector<tc::io::Path>& param, const std::vector<std::string>& opts) :
|
||||
mParam(param),
|
||||
mOptStrings(opts),
|
||||
mOptRegex()
|
||||
|
|
@ -297,7 +297,7 @@ private:
|
|||
class FileTypeOptionHandler : public tc::cli::OptionParser::IOptionHandler
|
||||
{
|
||||
public:
|
||||
FileTypeOptionHandler(nstool::Settings::FileType& param, const std::vector<std::string>& opts) :
|
||||
FileTypeOptionHandler(nstool::Settings::FileType& param, const std::vector<std::string>& opts) :
|
||||
mParam(param),
|
||||
mOptStrings(opts),
|
||||
mOptRegex()
|
||||
|
|
@ -397,6 +397,40 @@ private:
|
|||
std::vector<std::string> mOptRegex;
|
||||
};
|
||||
|
||||
class SingleFileExtractionHandler : public tc::cli::OptionParser::IOptionHandler
|
||||
{
|
||||
public:
|
||||
SingleFileExtractionHandler(std::string& param, const std::vector<std::string>& opts) :
|
||||
mParam(param),
|
||||
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)
|
||||
{
|
||||
throw tc::ArgumentOutOfRangeException(fmt::format("Option \"{:s}\" requires a parameter. Give the name and extension of the file you want to extract.", option));
|
||||
}
|
||||
|
||||
mParam = params[0];
|
||||
}
|
||||
private:
|
||||
std::string& mParam;
|
||||
std::vector<std::string> mOptStrings;
|
||||
std::vector<std::string> mOptRegex;
|
||||
};
|
||||
|
||||
class InstructionTypeOptionHandler : public tc::cli::OptionParser::IOptionHandler
|
||||
{
|
||||
public:
|
||||
|
|
@ -445,7 +479,7 @@ private:
|
|||
class ExtractDataPathOptionHandler : public tc::cli::OptionParser::IOptionHandler
|
||||
{
|
||||
public:
|
||||
ExtractDataPathOptionHandler(std::vector<nstool::ExtractJob>& jobs, const std::vector<std::string>& opts) :
|
||||
ExtractDataPathOptionHandler(std::vector<nstool::ExtractJob>& jobs, const std::vector<std::string>& opts) :
|
||||
mJobs(jobs),
|
||||
mOptStrings(opts),
|
||||
mOptRegex()
|
||||
|
|
@ -470,7 +504,7 @@ public:
|
|||
else if (params.size() == 2)
|
||||
{
|
||||
mJobs.push_back({tc::io::Path(params[0]), tc::io::Path(params[1])});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw tc::ArgumentOutOfRangeException(fmt::format("Option \"{:s}\" requires parameters in the format \"[<internal path>] <extract path>\".", option));
|
||||
|
|
@ -485,7 +519,7 @@ private:
|
|||
class CustomExtractDataPathOptionHandler : public tc::cli::OptionParser::IOptionHandler
|
||||
{
|
||||
public:
|
||||
CustomExtractDataPathOptionHandler(std::vector<nstool::ExtractJob>& jobs, const std::vector<std::string>& opts, const tc::io::Path& custom_path) :
|
||||
CustomExtractDataPathOptionHandler(std::vector<nstool::ExtractJob>& jobs, const std::vector<std::string>& opts, const tc::io::Path& custom_path) :
|
||||
mJobs(jobs),
|
||||
mOptStrings(opts),
|
||||
mOptRegex(),
|
||||
|
|
@ -519,7 +553,7 @@ public:
|
|||
{
|
||||
fmt::print("Consider using \"-x {:s} {:s}\" instead.\n", mCustomPath.to_string(), params[0]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
mJobs.push_back({mCustomPath, tc::io::Path(params[0])});
|
||||
}
|
||||
|
|
@ -604,7 +638,7 @@ void nstool::SettingsInitializer::parse_args(const std::vector<std::string>& arg
|
|||
usage_text();
|
||||
throw tc::ArgumentException(mModuleLabel, "Not enough arguments.");
|
||||
}
|
||||
|
||||
|
||||
// detect request for help
|
||||
for (auto itr = ++(args.begin()); itr != args.end(); itr++)
|
||||
{
|
||||
|
|
@ -636,6 +670,7 @@ void nstool::SettingsInitializer::parse_args(const std::vector<std::string>& arg
|
|||
|
||||
// process input file type
|
||||
opts.registerOptionHandler(std::shared_ptr<FileTypeOptionHandler>(new FileTypeOptionHandler(infile.filetype, { "-t", "--type" })));
|
||||
opts.registerOptionHandler(std::shared_ptr<SingleFileExtractionHandler>(new SingleFileExtractionHandler(outfile.filename, { "--file" })));
|
||||
|
||||
// get user-provided keydata
|
||||
opts.registerOptionHandler(std::shared_ptr<SingleParamPathOptionHandler>(new SingleParamPathOptionHandler(mKeysetPath, {"-k", "--keyset"})));
|
||||
|
|
@ -671,12 +706,12 @@ void nstool::SettingsInitializer::parse_args(const std::vector<std::string>& arg
|
|||
|
||||
// kip options
|
||||
opts.registerOptionHandler(std::shared_ptr<SingleParamPathOptionHandler>(new SingleParamPathOptionHandler(kip.extract_path, { "--kipdir" })));
|
||||
|
||||
|
||||
// aset options
|
||||
opts.registerOptionHandler(std::shared_ptr<SingleParamPathOptionHandler>(new SingleParamPathOptionHandler(aset.icon_extract_path, { "--icon" })));
|
||||
opts.registerOptionHandler(std::shared_ptr<SingleParamPathOptionHandler>(new SingleParamPathOptionHandler(aset.nacp_extract_path, { "--nacp" })));
|
||||
|
||||
|
||||
|
||||
// process option
|
||||
opts.processOptions(args, 1, args.size() - 2);
|
||||
}
|
||||
|
|
@ -684,7 +719,7 @@ void nstool::SettingsInitializer::parse_args(const std::vector<std::string>& arg
|
|||
void nstool::SettingsInitializer::determine_filetype()
|
||||
{
|
||||
//fmt::print("infile path = \"{}\"\n", infile.path.get().to_string());
|
||||
|
||||
|
||||
auto file = tc::io::StreamSource(std::make_shared<tc::io::FileStream>(tc::io::FileStream(infile.path.get(), tc::io::FileMode::Open, tc::io::FileAccess::Read)));
|
||||
|
||||
auto raw_data = file.pullData(0, 0x5000);
|
||||
|
|
@ -808,11 +843,11 @@ void nstool::SettingsInitializer::usage_text() const
|
|||
fmt::print(" --showlayout Show layout metadata.\n");
|
||||
fmt::print(" -v, --verbose Verbose output.\n");
|
||||
fmt::print("\n PFS0/HFS0 (PartitionFs), RomFs, NSP (Nintendo Submission Package)\n");
|
||||
fmt::print(" {:s} [--fstree] [-x [<virtual path>] <out path>] <file>\n", BIN_NAME);
|
||||
fmt::print(" {:s} [--fstree] [-x <out path> --file <virtual file name>] <file>\n", BIN_NAME);
|
||||
fmt::print(" --fstree Print filesystem tree.\n");
|
||||
fmt::print(" -x, --extract Extract a file or directory to local filesystem.\n");
|
||||
fmt::print("\n XCI (GameCard Image)\n");
|
||||
fmt::print(" {:s} [--fstree] [-x [<virtual path>] <out path>] <.xci file>\n", BIN_NAME);
|
||||
fmt::print(" {:s} [--fstree] [-x <out path> --file <virtual file name>] <.xci file>\n", BIN_NAME);
|
||||
fmt::print(" --fstree Print filesystem tree.\n");
|
||||
fmt::print(" -x, --extract Extract a file or directory to local filesystem.\n");
|
||||
fmt::print(" --update Extract \"update\" partition to directory. (Alias for \"-x /update <out path>\")\n");
|
||||
|
|
@ -820,7 +855,7 @@ void nstool::SettingsInitializer::usage_text() const
|
|||
fmt::print(" --normal Extract \"normal\" partition to directory. (Alias for \"-x /normal <out path>\")\n");
|
||||
fmt::print(" --secure Extract \"secure\" partition to directory. (Alias for \"-x /secure <out path>\")\n");
|
||||
fmt::print("\n NCA (Nintendo Content Archive)\n");
|
||||
fmt::print(" {:s} [--fstree] [-x [<virtual path>] <out path>] [--bodykey <key> --titlekey <key> -tik <tik path> --basenca <.nca file>] <.nca file>\n", BIN_NAME);
|
||||
fmt::print(" {:s} [--fstree] [-x <out path> --file <virtual file name>] [--bodykey <key> --titlekey <key> -tik <tik path> --basenca <.nca file>] <.nca file>\n", BIN_NAME);
|
||||
fmt::print(" --fstree Print filesystem tree.\n");
|
||||
fmt::print(" -x, --extract Extract a file or directory to local filesystem.\n");
|
||||
fmt::print(" --titlekey Specify (encrypted) title key extracted from ticket.\n");
|
||||
|
|
@ -1000,7 +1035,7 @@ void nstool::SettingsInitializer::loadKeyFile(tc::Optional<tc::io::Path>& keyfil
|
|||
|
||||
try {
|
||||
tc::io::FileStream test = tc::io::FileStream(tmp_path, tc::io::FileMode::Open, tc::io::FileAccess::Read);
|
||||
|
||||
|
||||
keyfile_path = tmp_path;
|
||||
}
|
||||
catch (tc::io::FileNotFoundException&) {
|
||||
|
|
@ -1010,7 +1045,7 @@ void nstool::SettingsInitializer::loadKeyFile(tc::Optional<tc::io::Path>& keyfil
|
|||
else {
|
||||
fmt::print("[WARNING] Failed to locate \"{}\" keyfile.{}\n", keyfile_name, cli_hint);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1020,7 +1055,7 @@ bool nstool::SettingsInitializer::determineValidNcaFromSample(const tc::ByteData
|
|||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (opt.keybag.nca_header_key.isNull())
|
||||
{
|
||||
fmt::print("[WARNING] Failed to load NCA Header Key.\n");
|
||||
|
|
|
|||
|
|
@ -37,6 +37,11 @@ struct Settings
|
|||
tc::Optional<tc::io::Path> path;
|
||||
} infile;
|
||||
|
||||
struct OutputFileOptions
|
||||
{
|
||||
std::string filename;
|
||||
} outfile;
|
||||
|
||||
struct Options
|
||||
{
|
||||
CliOutputMode cli_output_mode;
|
||||
|
|
@ -54,7 +59,7 @@ struct Settings
|
|||
} code;
|
||||
|
||||
// Generic FS options
|
||||
struct FsOptions
|
||||
struct FsOptions
|
||||
{
|
||||
bool show_fs_tree;
|
||||
std::vector<ExtractJob> extract_jobs;
|
||||
|
|
@ -97,6 +102,8 @@ struct Settings
|
|||
infile.filetype = FILE_TYPE_ERROR;
|
||||
infile.path = tc::Optional<tc::io::Path>();
|
||||
|
||||
outfile.filename = "";
|
||||
|
||||
opt.cli_output_mode = CliOutputMode();
|
||||
opt.verify = false;
|
||||
opt.is_dev = false;
|
||||
|
|
|
|||
21
src/main.cpp
21
src/main.cpp
|
|
@ -21,25 +21,25 @@
|
|||
|
||||
int umain(const std::vector<std::string>& args, const std::vector<std::string>& env)
|
||||
{
|
||||
try
|
||||
try
|
||||
{
|
||||
nstool::Settings set = nstool::SettingsInitializer(args);
|
||||
|
||||
|
||||
std::shared_ptr<tc::io::IStream> infile_stream = std::make_shared<tc::io::FileStream>(tc::io::FileStream(set.infile.path.get(), tc::io::FileMode::Open, tc::io::FileAccess::Read));
|
||||
|
||||
if (set.infile.filetype == nstool::Settings::FILE_TYPE_GAMECARD)
|
||||
{
|
||||
{
|
||||
nstool::GameCardProcess obj;
|
||||
|
||||
obj.setInputFile(infile_stream);
|
||||
|
||||
obj.setOutputFile(set.outfile.filename);
|
||||
obj.setKeyCfg(set.opt.keybag);
|
||||
obj.setCliOutputMode(set.opt.cli_output_mode);
|
||||
obj.setVerifyMode(set.opt.verify);
|
||||
|
||||
obj.setShowFsTree(set.fs.show_fs_tree);
|
||||
obj.setExtractJobs(set.fs.extract_jobs);
|
||||
|
||||
|
||||
obj.process();
|
||||
}
|
||||
else if (set.infile.filetype == nstool::Settings::FILE_TYPE_PARTITIONFS || set.infile.filetype == nstool::Settings::FILE_TYPE_NSP)
|
||||
|
|
@ -47,21 +47,21 @@ int umain(const std::vector<std::string>& args, const std::vector<std::string>&
|
|||
nstool::PfsProcess obj;
|
||||
|
||||
obj.setInputFile(infile_stream);
|
||||
|
||||
obj.setOutputFile(set.outfile.filename);
|
||||
obj.setCliOutputMode(set.opt.cli_output_mode);
|
||||
obj.setVerifyMode(set.opt.verify);
|
||||
|
||||
obj.setShowFsTree(set.fs.show_fs_tree);
|
||||
obj.setExtractJobs(set.fs.extract_jobs);
|
||||
|
||||
|
||||
obj.process();
|
||||
}
|
||||
|
||||
else if (set.infile.filetype == nstool::Settings::FILE_TYPE_ROMFS)
|
||||
{
|
||||
nstool::RomfsProcess obj;
|
||||
|
||||
obj.setInputFile(infile_stream);
|
||||
obj.setOutputFile(set.outfile.filename);
|
||||
obj.setCliOutputMode(set.opt.cli_output_mode);
|
||||
obj.setVerifyMode(set.opt.verify);
|
||||
|
||||
|
|
@ -75,6 +75,7 @@ int umain(const std::vector<std::string>& args, const std::vector<std::string>&
|
|||
nstool::NcaProcess obj;
|
||||
|
||||
obj.setInputFile(infile_stream);
|
||||
obj.setOutputFile(set.outfile.filename);
|
||||
obj.setBaseNcaPath(set.nca.base_nca_path);
|
||||
obj.setKeyCfg(set.opt.keybag);
|
||||
obj.setCliOutputMode(set.opt.cli_output_mode);
|
||||
|
|
@ -113,7 +114,7 @@ int umain(const std::vector<std::string>& args, const std::vector<std::string>&
|
|||
obj.setInputFile(infile_stream);
|
||||
obj.setCliOutputMode(set.opt.cli_output_mode);
|
||||
obj.setVerifyMode(set.opt.verify);
|
||||
|
||||
|
||||
obj.setIs64BitInstruction(set.code.is_64bit_instruction);
|
||||
obj.setListApi(set.code.list_api);
|
||||
obj.setListSymbols(set.code.list_symbols);
|
||||
|
|
@ -127,7 +128,7 @@ int umain(const std::vector<std::string>& args, const std::vector<std::string>&
|
|||
obj.setInputFile(infile_stream);
|
||||
obj.setCliOutputMode(set.opt.cli_output_mode);
|
||||
obj.setVerifyMode(set.opt.verify);
|
||||
|
||||
|
||||
obj.setIs64BitInstruction(set.code.is_64bit_instruction);
|
||||
obj.setListApi(set.code.list_api);
|
||||
obj.setListSymbols(set.code.list_symbols);
|
||||
|
|
|
|||
Loading…
Reference in a new issue