From 2f5a4d9c237678744a51676e9fb5f09ee3a967fc Mon Sep 17 00:00:00 2001 From: jakcron Date: Mon, 18 Jun 2018 23:30:19 +0800 Subject: [PATCH] [nstool] Refactor logic for managing output mode. --- programs/nstool/source/AssetProcess.cpp | 15 +- programs/nstool/source/AssetProcess.h | 4 +- programs/nstool/source/CnmtProcess.cpp | 10 +- programs/nstool/source/CnmtProcess.h | 4 +- programs/nstool/source/NacpProcess.cpp | 39 ++--- programs/nstool/source/NacpProcess.h | 4 +- programs/nstool/source/NcaProcess.cpp | 184 ++++++++++++------------ programs/nstool/source/NcaProcess.h | 4 +- programs/nstool/source/NpdmProcess.cpp | 76 ++++------ programs/nstool/source/NpdmProcess.h | 4 +- programs/nstool/source/NroProcess.cpp | 83 ++++++----- programs/nstool/source/NroProcess.h | 4 +- programs/nstool/source/NsoProcess.cpp | 137 +++++++++--------- programs/nstool/source/NsoProcess.h | 4 +- programs/nstool/source/PfsProcess.cpp | 22 +-- programs/nstool/source/PfsProcess.h | 4 +- programs/nstool/source/RomfsProcess.cpp | 21 +-- programs/nstool/source/RomfsProcess.h | 4 +- programs/nstool/source/UserSettings.cpp | 49 ++++--- programs/nstool/source/UserSettings.h | 7 +- programs/nstool/source/XciProcess.cpp | 138 ++++++++++-------- programs/nstool/source/XciProcess.h | 4 +- programs/nstool/source/main.cpp | 20 +-- programs/nstool/source/nstool.h | 11 +- 24 files changed, 436 insertions(+), 416 deletions(-) diff --git a/programs/nstool/source/AssetProcess.cpp b/programs/nstool/source/AssetProcess.cpp index ed2023d..a818c59 100644 --- a/programs/nstool/source/AssetProcess.cpp +++ b/programs/nstool/source/AssetProcess.cpp @@ -7,7 +7,7 @@ AssetProcess::AssetProcess() : mFile(nullptr), mOwnIFile(false), - mCliOutputType(OUTPUT_NORMAL), + mCliOutputMode(_BIT(OUTPUT_BASIC)), mVerify(false) { @@ -29,7 +29,8 @@ void AssetProcess::process() } importHeader(); - displayHeader(); + if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) + displayHeader(); processSections(); } @@ -39,9 +40,9 @@ void AssetProcess::setInputFile(fnd::IFile* file, bool ownIFile) mOwnIFile = ownIFile; } -void AssetProcess::setCliOutputMode(CliOutputType type) +void AssetProcess::setCliOutputMode(CliOutputMode type) { - mCliOutputType = type; + mCliOutputMode = type; } void AssetProcess::setVerifyMode(bool verify) @@ -117,7 +118,7 @@ void AssetProcess::processSections() } mNacp.setInputFile(new OffsetAdjustedIFile(mFile, false, mHdr.getNacpInfo().offset, mHdr.getNacpInfo().size), true); - mNacp.setCliOutputMode(mCliOutputType); + mNacp.setCliOutputMode(mCliOutputMode); mNacp.setVerifyMode(mVerify); mNacp.process(); @@ -129,7 +130,7 @@ void AssetProcess::processSections() throw fnd::Exception(kModuleName, "ASET geometry for romfs beyond file size"); mRomfs.setInputFile(new OffsetAdjustedIFile(mFile, false, mHdr.getRomfsInfo().offset, mHdr.getRomfsInfo().size), true); - mRomfs.setCliOutputMode(mCliOutputType); + mRomfs.setCliOutputMode(mCliOutputMode); mRomfs.setVerifyMode(mVerify); mRomfs.process(); @@ -138,7 +139,7 @@ void AssetProcess::processSections() void AssetProcess::displayHeader() { - if (mCliOutputType >= OUTPUT_NORMAL) + if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT)) { printf("[ASET Header]\n"); printf(" Icon:\n"); diff --git a/programs/nstool/source/AssetProcess.h b/programs/nstool/source/AssetProcess.h index d9cd9b6..4e1b707 100644 --- a/programs/nstool/source/AssetProcess.h +++ b/programs/nstool/source/AssetProcess.h @@ -17,7 +17,7 @@ public: void process(); void setInputFile(fnd::IFile* file, bool ownIFile); - void setCliOutputMode(CliOutputType type); + void setCliOutputMode(CliOutputMode type); void setVerifyMode(bool verify); void setListFs(bool list); @@ -32,7 +32,7 @@ private: fnd::IFile* mFile; bool mOwnIFile; - CliOutputType mCliOutputType; + CliOutputMode mCliOutputMode; bool mVerify; sOptional mIconExtractPath; diff --git a/programs/nstool/source/CnmtProcess.cpp b/programs/nstool/source/CnmtProcess.cpp index 69b4869..8795c20 100644 --- a/programs/nstool/source/CnmtProcess.cpp +++ b/programs/nstool/source/CnmtProcess.cpp @@ -145,7 +145,7 @@ void CnmtProcess::displayCmnt() CnmtProcess::CnmtProcess() : mFile(nullptr), mOwnIFile(false), - mCliOutputType(OUTPUT_NORMAL), + mCliOutputMode(_BIT(OUTPUT_BASIC)), mVerify(false) { } @@ -172,10 +172,8 @@ void CnmtProcess::process() mCnmt.importBinary(scratch.getBytes(), scratch.getSize()); - if (mCliOutputType >= OUTPUT_NORMAL) - { + if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) displayCmnt(); - } } void CnmtProcess::setInputFile(fnd::IFile* file, bool ownIFile) @@ -184,9 +182,9 @@ void CnmtProcess::setInputFile(fnd::IFile* file, bool ownIFile) mOwnIFile = ownIFile; } -void CnmtProcess::setCliOutputMode(CliOutputType type) +void CnmtProcess::setCliOutputMode(CliOutputMode type) { - mCliOutputType = type; + mCliOutputMode = type; } void CnmtProcess::setVerifyMode(bool verify) diff --git a/programs/nstool/source/CnmtProcess.h b/programs/nstool/source/CnmtProcess.h index f3b0367..7fbd65a 100644 --- a/programs/nstool/source/CnmtProcess.h +++ b/programs/nstool/source/CnmtProcess.h @@ -15,7 +15,7 @@ public: void process(); void setInputFile(fnd::IFile* file, bool ownIFile); - void setCliOutputMode(CliOutputType type); + void setCliOutputMode(CliOutputMode type); void setVerifyMode(bool verify); const nx::ContentMetaBinary& getContentMetaBinary() const; @@ -25,7 +25,7 @@ private: fnd::IFile* mFile; bool mOwnIFile; - CliOutputType mCliOutputType; + CliOutputMode mCliOutputMode; bool mVerify; nx::ContentMetaBinary mCnmt; diff --git a/programs/nstool/source/NacpProcess.cpp b/programs/nstool/source/NacpProcess.cpp index d2fdb44..ce7dc66 100644 --- a/programs/nstool/source/NacpProcess.cpp +++ b/programs/nstool/source/NacpProcess.cpp @@ -426,7 +426,7 @@ std::string getSaveDataSizeStr(int64_t size) NacpProcess::NacpProcess() : mFile(nullptr), mOwnIFile(false), - mCliOutputType(OUTPUT_NORMAL), + mCliOutputMode(_BIT(OUTPUT_BASIC)), mVerify(false) { } @@ -453,10 +453,8 @@ void NacpProcess::process() mNacp.importBinary(scratch.getBytes(), scratch.getSize()); - if (mCliOutputType >= OUTPUT_NORMAL) - { + if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) displayNacp(); - } } void NacpProcess::setInputFile(fnd::IFile* file, bool ownIFile) @@ -465,9 +463,9 @@ void NacpProcess::setInputFile(fnd::IFile* file, bool ownIFile) mOwnIFile = ownIFile; } -void NacpProcess::setCliOutputMode(CliOutputType type) +void NacpProcess::setCliOutputMode(CliOutputMode type) { - mCliOutputType = type; + mCliOutputMode = type; } void NacpProcess::setVerifyMode(bool verify) @@ -485,7 +483,7 @@ void NacpProcess::displayNacp() printf("[ApplicationControlProperty]\n"); printf(" Menu Description:\n"); printf(" DisplayVersion: %s\n", mNacp.getDisplayVersion().c_str()); - if (mNacp.getIsbn().empty() == false) + if (mNacp.getIsbn().empty() == false || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) printf(" ISBN: %s\n", mNacp.getIsbn().c_str()); for (size_t i = 0; i < mNacp.getTitle().getSize(); i++) { @@ -520,7 +518,7 @@ void NacpProcess::displayNacp() printf(" Age: %d\n", mNacp.getRatingAge()[i].age); } - if (mNacp.getBcatPassphase().empty() == false) + if (mNacp.getBcatPassphase().empty() == false || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) { printf(" BCAT:\n"); printf(" BcatPassphase: %s\n", mNacp.getBcatPassphase().c_str()); @@ -537,35 +535,35 @@ void NacpProcess::displayNacp() } printf(" SaveData:\n"); printf(" SaveDatawOwnerId: 0x%016" PRIx64 "\n", mNacp.getSaveDatawOwnerId()); - if (mNacp.getUserAccountSaveDataSize().journal_size > 0) + if (mNacp.getUserAccountSaveDataSize().journal_size > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) { printf(" UserAccountSaveData:\n"); printf(" Size: %s\n", getSaveDataSizeStr(mNacp.getUserAccountSaveDataSize().size).c_str()); printf(" JournalSize: %s\n", getSaveDataSizeStr(mNacp.getUserAccountSaveDataSize().journal_size).c_str()); } - if (mNacp.getDeviceSaveDataSize().journal_size > 0) + if (mNacp.getDeviceSaveDataSize().journal_size > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) { printf(" DeviceSaveData:\n"); printf(" Size: %s\n", getSaveDataSizeStr(mNacp.getDeviceSaveDataSize().size).c_str()); printf(" JournalSize: %s\n", getSaveDataSizeStr(mNacp.getDeviceSaveDataSize().journal_size).c_str()); } - if (mNacp.getUserAccountSaveDataMax().journal_size > 0) + if (mNacp.getUserAccountSaveDataMax().journal_size > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) { printf(" UserAccountSaveDataMax:\n"); printf(" Size: %s\n", getSaveDataSizeStr(mNacp.getUserAccountSaveDataMax().size).c_str()); printf(" JournalSize: %s\n", getSaveDataSizeStr(mNacp.getUserAccountSaveDataMax().journal_size).c_str()); } - if (mNacp.getDeviceSaveDataMax().journal_size > 0) + if (mNacp.getDeviceSaveDataMax().journal_size > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) { printf(" DeviceSaveDataMax:\n"); printf(" Size: %s\n", getSaveDataSizeStr(mNacp.getDeviceSaveDataMax().size).c_str()); printf(" JournalSize: %s\n", getSaveDataSizeStr(mNacp.getDeviceSaveDataMax().journal_size).c_str()); } - if (mNacp.getTemporaryStorageSize() > 0) + if (mNacp.getTemporaryStorageSize() > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) { printf(" TemporaryStorageSize: %s\n", getSaveDataSizeStr(mNacp.getTemporaryStorageSize()).c_str()); } - if (mNacp.getCacheStorageSize().journal_size > 0) + if (mNacp.getCacheStorageSize().journal_size > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) { printf(" CacheStorage:\n"); printf(" Size: %s\n", getSaveDataSizeStr(mNacp.getCacheStorageSize().size).c_str()); @@ -575,7 +573,10 @@ void NacpProcess::displayNacp() } printf(" Other Flags:\n"); printf(" StartupUserAccount: %s\n", getStartupUserAccountStr(mNacp.getStartupUserAccount())); - //printf(" TouchScreenUsageMode: %s\n", getTouchScreenUsageModeStr(mNacp.getTouchScreenUsageMode())); + if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + { + printf(" TouchScreenUsageMode: %s\n", getTouchScreenUsageModeStr(mNacp.getTouchScreenUsageMode())); + } printf(" AttributeFlag: %s\n", getAttributeFlagStr(mNacp.getAttributeFlag())); printf(" CrashReportMode: %s\n", getCrashReportModeStr(mNacp.getCrashReportMode())); printf(" HDCP: %s\n", getHdcpStr(mNacp.getHdcp())); @@ -584,16 +585,16 @@ void NacpProcess::displayNacp() printf(" DataLossConfirmation: %s\n", getDataLossConfirmationStr(mNacp.getDataLossConfirmation())); printf(" RepairFlag: %s\n", getRepairFlagStr(mNacp.getRepairFlag())); printf(" ProgramIndex: 0x%02x\n", mNacp.getProgramIndex()); - if (mNacp.getApplicationErrorCodeCategory().empty() == false) + if (mNacp.getApplicationErrorCodeCategory().empty() == false || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) { printf(" ApplicationErrorCodeCategory: %s\n", mNacp.getApplicationErrorCodeCategory().c_str()); } - if (mNacp.getSeedForPsuedoDeviceId() > 0 || mNacp.getPresenceGroupId() > 0) + if (mNacp.getSeedForPsuedoDeviceId() > 0 || mNacp.getPresenceGroupId() > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) { printf(" Other Ids:\n"); - if (mNacp.getSeedForPsuedoDeviceId() > 0) + if (mNacp.getSeedForPsuedoDeviceId() > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) printf(" SeedForPsuedoDeviceId: 0x%016" PRIx64 "\n", mNacp.getSeedForPsuedoDeviceId()); - if (mNacp.getPresenceGroupId() > 0) + if (mNacp.getPresenceGroupId() > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) printf(" PresenceGroupId: 0x%016" PRIx64 "\n", mNacp.getPresenceGroupId()); } } diff --git a/programs/nstool/source/NacpProcess.h b/programs/nstool/source/NacpProcess.h index 174d12f..bd7dc82 100644 --- a/programs/nstool/source/NacpProcess.h +++ b/programs/nstool/source/NacpProcess.h @@ -15,7 +15,7 @@ public: void process(); void setInputFile(fnd::IFile* file, bool ownIFile); - void setCliOutputMode(CliOutputType type); + void setCliOutputMode(CliOutputMode type); void setVerifyMode(bool verify); const nx::ApplicationControlPropertyBinary& getApplicationControlPropertyBinary() const; @@ -25,7 +25,7 @@ private: fnd::IFile* mFile; bool mOwnIFile; - CliOutputType mCliOutputType; + CliOutputMode mCliOutputMode; bool mVerify; nx::ApplicationControlPropertyBinary mNacp; diff --git a/programs/nstool/source/NcaProcess.cpp b/programs/nstool/source/NcaProcess.cpp index 7b11e13..c90ebff 100644 --- a/programs/nstool/source/NcaProcess.cpp +++ b/programs/nstool/source/NcaProcess.cpp @@ -224,7 +224,7 @@ NcaProcess::NcaProcess() : mFile(nullptr), mOwnIFile(false), mKeyset(nullptr), - mCliOutputType(OUTPUT_NORMAL), + mCliOutputMode(_BIT(OUTPUT_BASIC)), mVerify(false), mListFs(false) { @@ -283,7 +283,7 @@ void NcaProcess::process() validateNcaSignatures(); // display header - if (mCliOutputType >= OUTPUT_NORMAL) + if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) displayHeader(); // process partition @@ -322,9 +322,9 @@ void NcaProcess::setKeyset(const sKeyset* keyset) mKeyset = keyset; } -void NcaProcess::setCliOutputMode(CliOutputType type) +void NcaProcess::setCliOutputMode(CliOutputMode type) { - mCliOutputType = type; + mCliOutputMode = type; } void NcaProcess::setVerifyMode(bool verify) @@ -458,21 +458,27 @@ void NcaProcess::generateNcaBodyEncryptionKeys() { mBodyKeys.aes_xts = mKeyset->nca.manual_body_key_aesxts; } - /* - if (mBodyKeys.aes_ctr.isSet) + + if (_HAS_BIT(mCliOutputMode, OUTPUT_KEY_DATA)) { - printf("AES-CTR Key: "); - fnd::SimpleTextOutput::hexDump(mBodyKeys.aes_ctr.var.key, sizeof(mBodyKeys.aes_ctr.var)); + if (mBodyKeys.aes_ctr.isSet) + { + printf("[NCA Body Key]\n"); + printf(" AES-CTR Key: "); + fnd::SimpleTextOutput::hexDump(mBodyKeys.aes_ctr.var.key, sizeof(mBodyKeys.aes_ctr.var)); + } + + if (mBodyKeys.aes_xts.isSet) + { + printf("[NCA Body Key]\n"); + printf(" AES-XTS Key0: "); + fnd::SimpleTextOutput::hexDump(mBodyKeys.aes_xts.var.key[0], sizeof(mBodyKeys.aes_ctr.var)); + printf(" AES-XTS Key1: "); + fnd::SimpleTextOutput::hexDump(mBodyKeys.aes_xts.var.key[1], sizeof(mBodyKeys.aes_ctr.var)); + } } - if (mBodyKeys.aes_xts.isSet) - { - printf("AES-XTS Key0: "); - fnd::SimpleTextOutput::hexDump(mBodyKeys.aes_xts.var.key[0], sizeof(mBodyKeys.aes_ctr.var)); - printf("AES-XTS Key1: "); - fnd::SimpleTextOutput::hexDump(mBodyKeys.aes_xts.var.key[1], sizeof(mBodyKeys.aes_ctr.var)); - } - */ + } void NcaProcess::generatePartitionConfiguration() @@ -590,9 +596,7 @@ void NcaProcess::validateNcaSignatures() // validate signature[0] if (crypto::rsa::pss::rsaVerify(mKeyset->nca.header_sign_key, crypto::sha::HASH_SHA256, mHdrHash.bytes, mHdrBlock.signature_main) != 0) { - // this is minimal even though it's a warning because it's a validation method - if (mCliOutputType >= OUTPUT_MINIMAL) - printf("[WARNING] NCA Header Main Signature: FAIL \n"); + printf("[WARNING] NCA Header Main Signature: FAIL \n"); } // validate signature[1] @@ -604,7 +608,7 @@ void NcaProcess::validateNcaSignatures() { PfsProcess exefs; exefs.setInputFile(mPartitions[nx::nca::PARTITION_CODE].reader, SHARED_IFILE); - exefs.setCliOutputMode(OUTPUT_MINIMAL); + exefs.setCliOutputMode(0); exefs.process(); // open main.npdm @@ -614,38 +618,30 @@ void NcaProcess::validateNcaSignatures() NpdmProcess npdm; npdm.setInputFile(new OffsetAdjustedIFile(mPartitions[nx::nca::PARTITION_CODE].reader, SHARED_IFILE, file.offset, file.size), OWN_IFILE); - npdm.setCliOutputMode(OUTPUT_MINIMAL); + npdm.setCliOutputMode(0); npdm.process(); if (crypto::rsa::pss::rsaVerify(npdm.getNpdmBinary().getAcid().getNcaHeader2RsaKey(), crypto::sha::HASH_SHA256, mHdrHash.bytes, mHdrBlock.signature_acid) != 0) { - // this is minimal even though it's a warning because it's a validation method - if (mCliOutputType >= OUTPUT_MINIMAL) - printf("[WARNING] NCA Header ACID Signature: FAIL \n"); + printf("[WARNING] NCA Header ACID Signature: FAIL \n"); } } else { - // this is minimal even though it's a warning because it's a validation method - if (mCliOutputType >= OUTPUT_MINIMAL) - printf("[WARNING] NCA Header ACID Signature: FAIL (\"%s\" not present in ExeFs)\n", kNpdmExefsPath.c_str()); + printf("[WARNING] NCA Header ACID Signature: FAIL (\"%s\" not present in ExeFs)\n", kNpdmExefsPath.c_str()); } } else { - // this is minimal even though it's a warning because it's a validation method - if (mCliOutputType >= OUTPUT_MINIMAL) - printf("[WARNING] NCA Header ACID Signature: FAIL (ExeFs unreadable)\n"); + printf("[WARNING] NCA Header ACID Signature: FAIL (ExeFs unreadable)\n"); } } else { - // this is minimal even though it's a warning because it's a validation method - if (mCliOutputType >= OUTPUT_MINIMAL) - printf("[WARNING] NCA Header ACID Signature: FAIL (No ExeFs partition)\n"); + printf("[WARNING] NCA Header ACID Signature: FAIL (No ExeFs partition)\n"); } } } @@ -674,7 +670,7 @@ void NcaProcess::displayHeader() } - if (mBodyKeys.keak_list.getSize() > 0) + if (mBodyKeys.keak_list.getSize() > 0 && _HAS_BIT(mCliOutputMode, OUTPUT_KEY_DATA)) { printf(" Key Area: \n"); printf(" <--------------------------------------------------------------------------->\n"); @@ -699,70 +695,74 @@ void NcaProcess::displayHeader() printf(" <--------------------------------------------------------------------------->\n"); } - printf(" Partitions:\n"); - for (size_t i = 0; i < mHdr.getPartitions().getSize(); i++) + if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT)) { - sPartitionInfo& info = mPartitions[i]; + printf(" Partitions:\n"); + for (size_t i = 0; i < mHdr.getPartitions().getSize(); i++) + { + sPartitionInfo& info = mPartitions[i]; - printf(" %d:\n", (int)i); - printf(" Offset: 0x%" PRIx64 "\n", (uint64_t)info.offset); - printf(" Size: 0x%" PRIx64 "\n", (uint64_t)info.size); - printf(" Format Type: %s\n", getFormatTypeStr(info.format_type)); - printf(" Hash Type: %s\n", getHashTypeStr(info.hash_type)); - printf(" Enc. Type: %s\n", getEncryptionTypeStr(info.enc_type)); - if (info.enc_type == nx::nca::CRYPT_AESCTR) - { - printf(" AES-CTR: "); - crypto::aes::sAesIvCtr ctr; - crypto::aes::AesIncrementCounter(info.aes_ctr.iv, info.offset>>4, ctr.iv); - fnd::SimpleTextOutput::hexDump(ctr.iv, sizeof(crypto::aes::sAesIvCtr)); - } - if (info.hash_type == nx::nca::HASH_HIERARCHICAL_INTERGRITY) - { - HashTreeMeta& hash_hdr = info.hash_tree_meta; - printf(" HierarchicalIntegrity Header:\n"); - //printf(" TypeId: 0x%x\n", hash_hdr.type_id.get()); - //printf(" MasterHashSize: 0x%x\n", hash_hdr.master_hash_size.get()); - //printf(" LayerNum: %d\n", hash_hdr.getLayerInfo().getSize()); - for (size_t j = 0; j < hash_hdr.getHashLayerInfo().getSize(); j++) + printf(" %d:\n", (int)i); + printf(" Offset: 0x%" PRIx64 "\n", (uint64_t)info.offset); + printf(" Size: 0x%" PRIx64 "\n", (uint64_t)info.size); + printf(" Format Type: %s\n", getFormatTypeStr(info.format_type)); + printf(" Hash Type: %s\n", getHashTypeStr(info.hash_type)); + printf(" Enc. Type: %s\n", getEncryptionTypeStr(info.enc_type)); + if (info.enc_type == nx::nca::CRYPT_AESCTR) { - printf(" Hash Layer %d:\n", (int)j); - printf(" Offset: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getHashLayerInfo()[j].offset); - printf(" Size: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getHashLayerInfo()[j].size); - printf(" BlockSize: 0x%" PRIx32 "\n", (uint32_t)hash_hdr.getHashLayerInfo()[j].block_size); + printf(" AES-CTR: "); + crypto::aes::sAesIvCtr ctr; + crypto::aes::AesIncrementCounter(info.aes_ctr.iv, info.offset>>4, ctr.iv); + fnd::SimpleTextOutput::hexDump(ctr.iv, sizeof(crypto::aes::sAesIvCtr)); } + if (info.hash_type == nx::nca::HASH_HIERARCHICAL_INTERGRITY) + { + HashTreeMeta& hash_hdr = info.hash_tree_meta; + printf(" HierarchicalIntegrity Header:\n"); + //printf(" TypeId: 0x%x\n", hash_hdr.type_id.get()); + //printf(" MasterHashSize: 0x%x\n", hash_hdr.master_hash_size.get()); + //printf(" LayerNum: %d\n", hash_hdr.getLayerInfo().getSize()); + for (size_t j = 0; j < hash_hdr.getHashLayerInfo().getSize(); j++) + { + printf(" Hash Layer %d:\n", (int)j); + printf(" Offset: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getHashLayerInfo()[j].offset); + printf(" Size: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getHashLayerInfo()[j].size); + printf(" BlockSize: 0x%" PRIx32 "\n", (uint32_t)hash_hdr.getHashLayerInfo()[j].block_size); + } - printf(" Data Layer:\n"); - printf(" Offset: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getDataLayer().offset); - printf(" Size: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getDataLayer().size); - printf(" BlockSize: 0x%" PRIx32 "\n", (uint32_t)hash_hdr.getDataLayer().block_size); - for (size_t j = 0; j < hash_hdr.getMasterHashList().getSize(); j++) - { - printf(" Master Hash %d: ", (int)j); - fnd::SimpleTextOutput::hexDump(hash_hdr.getMasterHashList()[j].bytes, sizeof(crypto::sha::sSha256Hash)); + printf(" Data Layer:\n"); + printf(" Offset: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getDataLayer().offset); + printf(" Size: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getDataLayer().size); + printf(" BlockSize: 0x%" PRIx32 "\n", (uint32_t)hash_hdr.getDataLayer().block_size); + for (size_t j = 0; j < hash_hdr.getMasterHashList().getSize(); j++) + { + printf(" Master Hash %d: ", (int)j); + fnd::SimpleTextOutput::hexDump(hash_hdr.getMasterHashList()[j].bytes, sizeof(crypto::sha::sSha256Hash)); + } } + else if (info.hash_type == nx::nca::HASH_HIERARCHICAL_SHA256) + { + HashTreeMeta& hash_hdr = info.hash_tree_meta; + printf(" HierarchicalSha256 Header:\n"); + printf(" Master Hash: "); + fnd::SimpleTextOutput::hexDump(hash_hdr.getMasterHashList()[0].bytes, sizeof(crypto::sha::sSha256Hash)); + printf(" HashBlockSize: 0x%" PRIx32 "\n", (uint32_t)hash_hdr.getDataLayer().block_size); + //printf(" LayerNum: %d\n", hash_hdr.getLayerInfo().getSize()); + printf(" Hash Layer:\n"); + printf(" Offset: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getHashLayerInfo()[0].offset); + printf(" Size: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getHashLayerInfo()[0].size); + printf(" Data Layer:\n"); + printf(" Offset: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getDataLayer().offset); + printf(" Size: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getDataLayer().size); + } + //else + //{ + // printf(" Hash Superblock:\n"); + // fnd::SimpleTextOutput::hxdStyleDump(fs_header.hash_superblock, nx::nca::kFsHeaderHashSuperblockLen); + //} } - else if (info.hash_type == nx::nca::HASH_HIERARCHICAL_SHA256) - { - HashTreeMeta& hash_hdr = info.hash_tree_meta; - printf(" HierarchicalSha256 Header:\n"); - printf(" Master Hash: "); - fnd::SimpleTextOutput::hexDump(hash_hdr.getMasterHashList()[0].bytes, sizeof(crypto::sha::sSha256Hash)); - printf(" HashBlockSize: 0x%" PRIx32 "\n", (uint32_t)hash_hdr.getDataLayer().block_size); - //printf(" LayerNum: %d\n", hash_hdr.getLayerInfo().getSize()); - printf(" Hash Layer:\n"); - printf(" Offset: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getHashLayerInfo()[0].offset); - printf(" Size: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getHashLayerInfo()[0].size); - printf(" Data Layer:\n"); - printf(" Offset: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getDataLayer().offset); - printf(" Size: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getDataLayer().size); - } - //else - //{ - // printf(" Hash Superblock:\n"); - // fnd::SimpleTextOutput::hxdStyleDump(fs_header.hash_superblock, nx::nca::kFsHeaderHashSuperblockLen); - //} } + #undef _HEXDUMP_U #undef _HEXDUMP_L } @@ -791,7 +791,7 @@ void NcaProcess::processPartitions() { PfsProcess pfs; pfs.setInputFile(partition.reader, SHARED_IFILE); - pfs.setCliOutputMode(mCliOutputType); + pfs.setCliOutputMode(mCliOutputMode); pfs.setListFs(mListFs); if (mHdr.getContentType() == nx::nca::TYPE_PROGRAM) { @@ -812,7 +812,7 @@ void NcaProcess::processPartitions() { RomfsProcess romfs; romfs.setInputFile(partition.reader, SHARED_IFILE); - romfs.setCliOutputMode(mCliOutputType); + romfs.setCliOutputMode(mCliOutputMode); romfs.setListFs(mListFs); if (mHdr.getContentType() == nx::nca::TYPE_PROGRAM) { diff --git a/programs/nstool/source/NcaProcess.h b/programs/nstool/source/NcaProcess.h index 38029db..dd5033c 100644 --- a/programs/nstool/source/NcaProcess.h +++ b/programs/nstool/source/NcaProcess.h @@ -19,7 +19,7 @@ public: // generic void setInputFile(fnd::IFile* file, bool ownIFile); void setKeyset(const sKeyset* keyset); - void setCliOutputMode(CliOutputType type); + void setCliOutputMode(CliOutputMode type); void setVerifyMode(bool verify); // nca specfic @@ -37,7 +37,7 @@ private: fnd::IFile* mFile; bool mOwnIFile; const sKeyset* mKeyset; - CliOutputType mCliOutputType; + CliOutputMode mCliOutputMode; bool mVerify; struct sExtract diff --git a/programs/nstool/source/NpdmProcess.cpp b/programs/nstool/source/NpdmProcess.cpp index 36d36c0..2686511 100644 --- a/programs/nstool/source/NpdmProcess.cpp +++ b/programs/nstool/source/NpdmProcess.cpp @@ -4,7 +4,7 @@ NpdmProcess::NpdmProcess() : mFile(nullptr), mOwnIFile(false), mKeyset(nullptr), - mCliOutputType(OUTPUT_NORMAL), + mCliOutputMode(_BIT(OUTPUT_BASIC)), mVerify(false) { } @@ -37,7 +37,7 @@ void NpdmProcess::process() validateAciFromAcid(mNpdm.getAci(), mNpdm.getAcid()); } - if (mCliOutputType >= OUTPUT_NORMAL) + if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) { // npdm binary displayNpdmHeader(mNpdm); @@ -67,9 +67,9 @@ void NpdmProcess::setKeyset(const sKeyset* keyset) mKeyset = keyset; } -void NpdmProcess::setCliOutputMode(CliOutputType type) +void NpdmProcess::setCliOutputMode(CliOutputMode type) { - mCliOutputType = type; + mCliOutputMode = type; } void NpdmProcess::setVerifyMode(bool verify) @@ -296,9 +296,7 @@ void NpdmProcess::validateAcidSignature(const nx::AcidBinary& acid) acid.verifyBinary(mKeyset->acid_sign_key); } catch (...) { - // this is minimal even though it's a warning because it's a validation method - if (mCliOutputType >= OUTPUT_MINIMAL) - printf("[WARNING] ACID Signature: FAIL\n"); + printf("[WARNING] ACID Signature: FAIL\n"); } } @@ -308,20 +306,17 @@ void NpdmProcess::validateAciFromAcid(const nx::AciBinary& aci, const nx::AcidBi // check Program ID if (acid.getProgramIdMin() > 0 && aci.getProgramId() < acid.getProgramIdMin()) { - if (mCliOutputType >= OUTPUT_MINIMAL) - printf("[WARNING] ACI ProgramId: FAIL (Outside Legal Range)\n"); + printf("[WARNING] ACI ProgramId: FAIL (Outside Legal Range)\n"); } else if (acid.getProgramIdMax() > 0 && aci.getProgramId() > acid.getProgramIdMax()) { - if (mCliOutputType >= OUTPUT_MINIMAL) - printf("[WARNING] ACI ProgramId: FAIL (Outside Legal Range)\n"); + printf("[WARNING] ACI ProgramId: FAIL (Outside Legal Range)\n"); } // Check FAC if (aci.getFac().getFormatVersion() != acid.getFac().getFormatVersion()) { - if (mCliOutputType >= OUTPUT_MINIMAL) - printf("[WARNING] ACI/FAC FormatVersion: FAIL (%d != %d (expected))\n", aci.getFac().getFormatVersion(),acid.getFac().getFormatVersion()); + printf("[WARNING] ACI/FAC FormatVersion: FAIL (%d != %d (expected))\n", aci.getFac().getFormatVersion(),acid.getFac().getFormatVersion()); } for (size_t i = 0; i < aci.getFac().getFsaRightsList().getSize(); i++) @@ -335,8 +330,8 @@ void NpdmProcess::validateAciFromAcid(const nx::AciBinary& aci, const nx::AcidBi if (fsaRightFound == false) { - if (mCliOutputType >= OUTPUT_MINIMAL) - printf("[WARNING] ACI/FAC FsaRights: FAIL (%s not permitted)\n", kFsaFlag[aci.getFac().getFsaRightsList()[i]].c_str()); + + printf("[WARNING] ACI/FAC FsaRights: FAIL (%s not permitted)\n", kFsaFlag[aci.getFac().getFsaRightsList()[i]].c_str()); } } @@ -351,8 +346,8 @@ void NpdmProcess::validateAciFromAcid(const nx::AciBinary& aci, const nx::AcidBi if (rightFound == false) { - if (mCliOutputType >= OUTPUT_MINIMAL) - printf("[WARNING] ACI/FAC ContentOwnerId: FAIL (%08x not permitted)\n", aci.getFac().getContentOwnerIdList()[i]); + + printf("[WARNING] ACI/FAC ContentOwnerId: FAIL (%08x not permitted)\n", aci.getFac().getContentOwnerIdList()[i]); } } @@ -367,8 +362,8 @@ void NpdmProcess::validateAciFromAcid(const nx::AciBinary& aci, const nx::AcidBi if (rightFound == false) { - if (mCliOutputType >= OUTPUT_MINIMAL) - printf("[WARNING] ACI/FAC ContentOwnerId: FAIL (%08x not permitted)\n", aci.getFac().getSaveDataOwnerIdList()[i]); + + printf("[WARNING] ACI/FAC ContentOwnerId: FAIL (%08x not permitted)\n", aci.getFac().getSaveDataOwnerIdList()[i]); } } @@ -384,8 +379,8 @@ void NpdmProcess::validateAciFromAcid(const nx::AciBinary& aci, const nx::AcidBi if (rightFound == false) { - if (mCliOutputType >= OUTPUT_MINIMAL) - printf("[WARNING] ACI/SAC ServiceList: FAIL (%s%s not permitted)\n", aci.getSac().getServiceList()[i].getName().c_str(), aci.getSac().getServiceList()[i].isServer()? " (Server)" : ""); + + printf("[WARNING] ACI/SAC ServiceList: FAIL (%s%s not permitted)\n", aci.getSac().getServiceList()[i].getName().c_str(), aci.getSac().getServiceList()[i].isServer()? " (Server)" : ""); } } @@ -393,23 +388,19 @@ void NpdmProcess::validateAciFromAcid(const nx::AciBinary& aci, const nx::AcidBi // check thread info if (aci.getKc().getThreadInfo().getMaxCpuId() != acid.getKc().getThreadInfo().getMaxCpuId()) { - if (mCliOutputType >= OUTPUT_MINIMAL) - printf("[WARNING] ACI/KC ThreadInfo/MaxCpuId: FAIL (%d not permitted)\n", aci.getKc().getThreadInfo().getMaxCpuId()); + printf("[WARNING] ACI/KC ThreadInfo/MaxCpuId: FAIL (%d not permitted)\n", aci.getKc().getThreadInfo().getMaxCpuId()); } if (aci.getKc().getThreadInfo().getMinCpuId() != acid.getKc().getThreadInfo().getMinCpuId()) { - if (mCliOutputType >= OUTPUT_MINIMAL) - printf("[WARNING] ACI/KC ThreadInfo/MinCpuId: FAIL (%d not permitted)\n", aci.getKc().getThreadInfo().getMinCpuId()); + printf("[WARNING] ACI/KC ThreadInfo/MinCpuId: FAIL (%d not permitted)\n", aci.getKc().getThreadInfo().getMinCpuId()); } if (aci.getKc().getThreadInfo().getMaxPriority() != acid.getKc().getThreadInfo().getMaxPriority()) { - if (mCliOutputType >= OUTPUT_MINIMAL) - printf("[WARNING] ACI/KC ThreadInfo/MaxPriority: FAIL (%d not permitted)\n", aci.getKc().getThreadInfo().getMaxPriority()); + printf("[WARNING] ACI/KC ThreadInfo/MaxPriority: FAIL (%d not permitted)\n", aci.getKc().getThreadInfo().getMaxPriority()); } if (aci.getKc().getThreadInfo().getMinPriority() != acid.getKc().getThreadInfo().getMinPriority()) { - if (mCliOutputType >= OUTPUT_MINIMAL) - printf("[WARNING] ACI/KC ThreadInfo/MinPriority: FAIL (%d not permitted)\n", aci.getKc().getThreadInfo().getMinPriority()); + printf("[WARNING] ACI/KC ThreadInfo/MinPriority: FAIL (%d not permitted)\n", aci.getKc().getThreadInfo().getMinPriority()); } // check system calls for (size_t i = 0; i < aci.getKc().getSystemCalls().getSystemCalls().getSize(); i++) @@ -423,8 +414,8 @@ void NpdmProcess::validateAciFromAcid(const nx::AciBinary& aci, const nx::AcidBi if (rightFound == false) { - if (mCliOutputType >= OUTPUT_MINIMAL) - printf("[WARNING] ACI/KC SystemCallList: FAIL (%s not permitted)\n", kSysCall[aci.getKc().getSystemCalls().getSystemCalls()[i]].c_str()); + + printf("[WARNING] ACI/KC SystemCallList: FAIL (%s not permitted)\n", kSysCall[aci.getKc().getSystemCalls().getSystemCalls()[i]].c_str()); } } // check memory maps @@ -440,8 +431,8 @@ void NpdmProcess::validateAciFromAcid(const nx::AciBinary& aci, const nx::AcidBi if (rightFound == false) { const nx::MemoryMappingHandler::sMemoryMapping& map = aci.getKc().getMemoryMaps().getMemoryMaps()[i]; - if (mCliOutputType >= OUTPUT_MINIMAL) - printf("[WARNING] ACI/KC MemoryMap: FAIL (0x%016" PRIx64 " - 0x%016" PRIx64 " (perm=%s) (type=%s) not permitted)\n", (uint64_t)map.addr << 12, ((uint64_t)(map.addr + map.size) << 12) - 1, kMemMapPerm[map.perm].c_str(), kMemMapType[map.type].c_str()); + + printf("[WARNING] ACI/KC MemoryMap: FAIL (0x%016" PRIx64 " - 0x%016" PRIx64 " (perm=%s) (type=%s) not permitted)\n", (uint64_t)map.addr << 12, ((uint64_t)(map.addr + map.size) << 12) - 1, kMemMapPerm[map.perm].c_str(), kMemMapType[map.type].c_str()); } } for (size_t i = 0; i < aci.getKc().getMemoryMaps().getIoMemoryMaps().getSize(); i++) @@ -456,8 +447,8 @@ void NpdmProcess::validateAciFromAcid(const nx::AciBinary& aci, const nx::AcidBi if (rightFound == false) { const nx::MemoryMappingHandler::sMemoryMapping& map = aci.getKc().getMemoryMaps().getIoMemoryMaps()[i]; - if (mCliOutputType >= OUTPUT_MINIMAL) - printf("[WARNING] ACI/KC IoMemoryMap: FAIL (0x%016" PRIx64 " - 0x%016" PRIx64 " (perm=%s) (type=%s) not permitted)\n", (uint64_t)map.addr << 12, ((uint64_t)(map.addr + map.size) << 12) - 1, kMemMapPerm[map.perm].c_str(), kMemMapType[map.type].c_str()); + + printf("[WARNING] ACI/KC IoMemoryMap: FAIL (0x%016" PRIx64 " - 0x%016" PRIx64 " (perm=%s) (type=%s) not permitted)\n", (uint64_t)map.addr << 12, ((uint64_t)(map.addr + map.size) << 12) - 1, kMemMapPerm[map.perm].c_str(), kMemMapType[map.type].c_str()); } } // check interupts @@ -472,29 +463,25 @@ void NpdmProcess::validateAciFromAcid(const nx::AciBinary& aci, const nx::AcidBi if (rightFound == false) { - if (mCliOutputType >= OUTPUT_MINIMAL) - printf("[WARNING] ACI/KC InteruptsList: FAIL (0x%0x not permitted)\n", aci.getKc().getInterupts().getInteruptList()[i]); + printf("[WARNING] ACI/KC InteruptsList: FAIL (0x%0x not permitted)\n", aci.getKc().getInterupts().getInteruptList()[i]); } } // check misc params if (aci.getKc().getMiscParams().getProgramType() != acid.getKc().getMiscParams().getProgramType()) { - if (mCliOutputType >= OUTPUT_MINIMAL) - printf("[WARNING] ACI/KC ProgramType: FAIL (%d not permitted)\n", aci.getKc().getMiscParams().getProgramType()); + printf("[WARNING] ACI/KC ProgramType: FAIL (%d not permitted)\n", aci.getKc().getMiscParams().getProgramType()); } // check kernel version uint32_t aciKernelVersion = (uint32_t)aci.getKc().getKernelVersion().getVerMajor() << 16 | (uint32_t)aci.getKc().getKernelVersion().getVerMinor(); uint32_t acidKernelVersion = (uint32_t)acid.getKc().getKernelVersion().getVerMajor() << 16 | (uint32_t)acid.getKc().getKernelVersion().getVerMinor(); if (aciKernelVersion < acidKernelVersion) { - if (mCliOutputType >= OUTPUT_MINIMAL) - printf("[WARNING] ACI/KC RequiredKernelVersion: FAIL (%d.%d not permitted)\n", aci.getKc().getKernelVersion().getVerMajor(), aci.getKc().getKernelVersion().getVerMinor()); + printf("[WARNING] ACI/KC RequiredKernelVersion: FAIL (%d.%d not permitted)\n", aci.getKc().getKernelVersion().getVerMajor(), aci.getKc().getKernelVersion().getVerMinor()); } // check handle table size if (aci.getKc().getHandleTableSize().getHandleTableSize() > acid.getKc().getHandleTableSize().getHandleTableSize()) { - if (mCliOutputType >= OUTPUT_MINIMAL) - printf("[WARNING] ACI/KC HandleTableSize: FAIL (0x%x too large)\n", aci.getKc().getHandleTableSize().getHandleTableSize()); + printf("[WARNING] ACI/KC HandleTableSize: FAIL (0x%x too large)\n", aci.getKc().getHandleTableSize().getHandleTableSize()); } // check misc flags for (size_t i = 0; i < aci.getKc().getMiscFlags().getFlagList().getSize(); i++) @@ -508,8 +495,7 @@ void NpdmProcess::validateAciFromAcid(const nx::AciBinary& aci, const nx::AcidBi if (rightFound == false) { - if (mCliOutputType >= OUTPUT_MINIMAL) - printf("[WARNING] ACI/KC MiscFlag: FAIL (%s not permitted)\n", kMiscFlag[aci.getKc().getMiscFlags().getFlagList()[i]].c_str()); + printf("[WARNING] ACI/KC MiscFlag: FAIL (%s not permitted)\n", kMiscFlag[aci.getKc().getMiscFlags().getFlagList()[i]].c_str()); } } } diff --git a/programs/nstool/source/NpdmProcess.h b/programs/nstool/source/NpdmProcess.h index f9d4e95..4500d0f 100644 --- a/programs/nstool/source/NpdmProcess.h +++ b/programs/nstool/source/NpdmProcess.h @@ -16,7 +16,7 @@ public: void setInputFile(fnd::IFile* file, bool ownIFile); void setKeyset(const sKeyset* keyset); - void setCliOutputMode(CliOutputType type); + void setCliOutputMode(CliOutputMode type); void setVerifyMode(bool verify); const nx::NpdmBinary& getNpdmBinary() const; @@ -27,7 +27,7 @@ private: fnd::IFile* mFile; bool mOwnIFile; const sKeyset* mKeyset; - CliOutputType mCliOutputType; + CliOutputMode mCliOutputMode; bool mVerify; nx::NpdmBinary mNpdm; diff --git a/programs/nstool/source/NroProcess.cpp b/programs/nstool/source/NroProcess.cpp index f41ae30..4a3baa8 100644 --- a/programs/nstool/source/NroProcess.cpp +++ b/programs/nstool/source/NroProcess.cpp @@ -9,7 +9,7 @@ NroProcess::NroProcess(): mFile(nullptr), mOwnIFile(false), - mCliOutputType(OUTPUT_NORMAL), + mCliOutputMode(_BIT(OUTPUT_BASIC)), mVerify(false), mInstructionType(nx::npdm::INSTR_64BIT), mListApi(false), @@ -35,8 +35,11 @@ void NroProcess::process() importHeader(); importCodeSegments(); importApiList(); - displayHeader(); - displayRoMetaData(); + if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) + { + displayHeader(); + displayRoMetaData(); + } if (mIsHomebrewNro) mAssetProc.process(); } @@ -47,9 +50,9 @@ void NroProcess::setInputFile(fnd::IFile* file, bool ownIFile) mOwnIFile = ownIFile; } -void NroProcess::setCliOutputMode(CliOutputType type) +void NroProcess::setCliOutputMode(CliOutputMode type) { - mCliOutputType = type; + mCliOutputMode = type; } void NroProcess::setVerifyMode(bool verify) @@ -111,7 +114,7 @@ void NroProcess::importHeader() { mIsHomebrewNro = true; mAssetProc.setInputFile(new OffsetAdjustedIFile(mFile, false, mHdr.getNroSize(), mFile->size() - mHdr.getNroSize()), true); - mAssetProc.setCliOutputMode(mCliOutputType); + mAssetProc.setCliOutputMode(mCliOutputMode); mAssetProc.setVerifyMode(mVerify); } else @@ -164,48 +167,45 @@ void NroProcess::importApiList() void NroProcess::displayHeader() { #define _HEXDUMP_L(var, len) do { for (size_t a__a__A = 0; a__a__A < len; a__a__A++) printf("%02x", var[a__a__A]); } while(0) - if (mCliOutputType >= OUTPUT_NORMAL) + printf("[NRO Header]\n"); + printf(" RoCrt: "); + _HEXDUMP_L(mHdr.getRoCrt().data, nx::nro::kRoCrtSize); + printf("\n"); + printf(" ModuleId: "); + _HEXDUMP_L(mHdr.getModuleId().data, nx::nro::kModuleIdSize); + printf("\n"); + printf(" NroSize: 0x%" PRIx32 "\n", mHdr.getNroSize()); + printf(" Program Sections:\n"); + printf(" .text:\n"); + printf(" Offset: 0x%" PRIx32 "\n", mHdr.getTextInfo().memory_offset); + printf(" Size: 0x%" PRIx32 "\n", mHdr.getTextInfo().size); + printf(" .ro:\n"); + printf(" Offset: 0x%" PRIx32 "\n", mHdr.getRoInfo().memory_offset); + printf(" Size: 0x%" PRIx32 "\n", mHdr.getRoInfo().size); + if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) { - printf("[NRO Header]\n"); - printf(" RoCrt: "); - _HEXDUMP_L(mHdr.getRoCrt().data, nx::nro::kRoCrtSize); - printf("\n"); - printf(" ModuleId: "); - _HEXDUMP_L(mHdr.getModuleId().data, nx::nro::kModuleIdSize); - printf("\n"); - printf(" NroSize: 0x%" PRIx32 "\n", mHdr.getNroSize()); - printf(" Program Sections:\n"); - printf(" .text:\n"); - printf(" Offset: 0x%" PRIx32 "\n", mHdr.getTextInfo().memory_offset); - printf(" Size: 0x%" PRIx32 "\n", mHdr.getTextInfo().size); - printf(" .ro:\n"); - printf(" Offset: 0x%" PRIx32 "\n", mHdr.getRoInfo().memory_offset); - printf(" Size: 0x%" PRIx32 "\n", mHdr.getRoInfo().size); - if (mCliOutputType >= OUTPUT_VERBOSE) - { - printf(" .api_info:\n"); - printf(" Offset: 0x%" PRIx32 "\n", mHdr.getRoEmbeddedInfo().memory_offset); - printf(" Size: 0x%" PRIx32 "\n", mHdr.getRoEmbeddedInfo().size); - printf(" .dynstr:\n"); - printf(" Offset: 0x%" PRIx32 "\n", mHdr.getRoDynStrInfo().memory_offset); - printf(" Size: 0x%" PRIx32 "\n", mHdr.getRoDynStrInfo().size); - printf(" .dynsym:\n"); - printf(" Offset: 0x%" PRIx32 "\n", mHdr.getRoDynSymInfo().memory_offset); - printf(" Size: 0x%" PRIx32 "\n", mHdr.getRoDynSymInfo().size); - } - printf(" .data:\n"); - printf(" Offset: 0x%" PRIx32 "\n", mHdr.getDataInfo().memory_offset); - printf(" Size: 0x%" PRIx32 "\n", mHdr.getDataInfo().size); - printf(" .bss:\n"); - printf(" Size: 0x%" PRIx32 "\n", mHdr.getBssSize()); + printf(" .api_info:\n"); + printf(" Offset: 0x%" PRIx32 "\n", mHdr.getRoEmbeddedInfo().memory_offset); + printf(" Size: 0x%" PRIx32 "\n", mHdr.getRoEmbeddedInfo().size); + printf(" .dynstr:\n"); + printf(" Offset: 0x%" PRIx32 "\n", mHdr.getRoDynStrInfo().memory_offset); + printf(" Size: 0x%" PRIx32 "\n", mHdr.getRoDynStrInfo().size); + printf(" .dynsym:\n"); + printf(" Offset: 0x%" PRIx32 "\n", mHdr.getRoDynSymInfo().memory_offset); + printf(" Size: 0x%" PRIx32 "\n", mHdr.getRoDynSymInfo().size); } + printf(" .data:\n"); + printf(" Offset: 0x%" PRIx32 "\n", mHdr.getDataInfo().memory_offset); + printf(" Size: 0x%" PRIx32 "\n", mHdr.getDataInfo().size); + printf(" .bss:\n"); + printf(" Size: 0x%" PRIx32 "\n", mHdr.getBssSize()); #undef _HEXDUMP_L } void NroProcess::displayRoMetaData() { - if (mApiList.size() > 0 && (mListApi || mCliOutputType > OUTPUT_NORMAL)) + if (mApiList.size() > 0 && (mListApi || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))) { printf("[SDK API List]\n"); for (size_t i = 0; i < mApiList.size(); i++) @@ -216,7 +216,7 @@ void NroProcess::displayRoMetaData() printf(" Module: %s\n", mApiList[i].getModuleName().c_str()); } } - if (mDynSymbolList.getDynamicSymbolList().getSize() > 0 && (mListSymbols || mCliOutputType > OUTPUT_NORMAL)) + if (mDynSymbolList.getDynamicSymbolList().getSize() > 0 && (mListSymbols || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))) { printf("[Symbol List]\n"); for (size_t i = 0; i < mDynSymbolList.getDynamicSymbolList().getSize(); i++) @@ -225,7 +225,6 @@ void NroProcess::displayRoMetaData() printf(" %s [SHN=%s (%04x)][STT=%s]\n", symbol.name.c_str(), getSectionIndexStr(symbol.shn_index), symbol.shn_index, getSymbolTypeStr(symbol.symbol_type)); } } - } const char* NroProcess::getApiTypeStr(SdkApiString::ApiType type) const diff --git a/programs/nstool/source/NroProcess.h b/programs/nstool/source/NroProcess.h index 1a81b1c..0c123e6 100644 --- a/programs/nstool/source/NroProcess.h +++ b/programs/nstool/source/NroProcess.h @@ -20,7 +20,7 @@ public: void process(); void setInputFile(fnd::IFile* file, bool ownIFile); - void setCliOutputMode(CliOutputType type); + void setCliOutputMode(CliOutputMode type); void setVerifyMode(bool verify); void setInstructionType(nx::npdm::InstructionType type); @@ -38,7 +38,7 @@ private: fnd::IFile* mFile; bool mOwnIFile; - CliOutputType mCliOutputType; + CliOutputMode mCliOutputMode; bool mVerify; nx::npdm::InstructionType mInstructionType; bool mListApi; diff --git a/programs/nstool/source/NsoProcess.cpp b/programs/nstool/source/NsoProcess.cpp index 3af7460..48d1771 100644 --- a/programs/nstool/source/NsoProcess.cpp +++ b/programs/nstool/source/NsoProcess.cpp @@ -8,7 +8,7 @@ NsoProcess::NsoProcess(): mFile(nullptr), mOwnIFile(false), - mCliOutputType(OUTPUT_NORMAL), + mCliOutputMode(_BIT(OUTPUT_BASIC)), mVerify(false), mInstructionType(nx::npdm::INSTR_64BIT), mListApi(false), @@ -34,8 +34,11 @@ void NsoProcess::process() importHeader(); importCodeSegments(); importApiList(); - displayNsoHeader(); - displayRoMetaData(); + if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) + { + displayNsoHeader(); + displayRoMetaData(); + } } void NsoProcess::setInputFile(fnd::IFile* file, bool ownIFile) @@ -44,9 +47,9 @@ void NsoProcess::setInputFile(fnd::IFile* file, bool ownIFile) mOwnIFile = ownIFile; } -void NsoProcess::setCliOutputMode(CliOutputType type) +void NsoProcess::setCliOutputMode(CliOutputMode type) { - mCliOutputType = type; + mCliOutputMode = type; } void NsoProcess::setVerifyMode(bool verify) @@ -204,75 +207,73 @@ void NsoProcess::displayNsoHeader() { #define _HEXDUMP_L(var, len) do { for (size_t a__a__A = 0; a__a__A < len; a__a__A++) printf("%02x", var[a__a__A]); } while(0) - if (mCliOutputType >= OUTPUT_NORMAL) + printf("[NSO Header]\n"); + printf(" ModuleId: "); + _HEXDUMP_L(mNsoHdr.getModuleId().data, nx::nso::kModuleIdSize); + printf("\n"); + if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT)) + printf(" Program Segments:\n"); + printf(" .module_name:\n"); + printf(" FileOffset: 0x%" PRIx32 "\n", mNsoHdr.getModuleNameInfo().offset); + printf(" FileSize: 0x%" PRIx32 "\n", mNsoHdr.getModuleNameInfo().size); + printf(" .text:\n"); + printf(" FileOffset: 0x%" PRIx32 "\n", mNsoHdr.getTextSegmentInfo().file_layout.offset); + printf(" FileSize: 0x%" PRIx32 "%s\n", mNsoHdr.getTextSegmentInfo().file_layout.size, mNsoHdr.getTextSegmentInfo().is_compressed? " (COMPRESSED)" : ""); + printf(" .ro:\n"); + printf(" FileOffset: 0x%" PRIx32 "\n", mNsoHdr.getRoSegmentInfo().file_layout.offset); + printf(" FileSize: 0x%" PRIx32 "%s\n", mNsoHdr.getRoSegmentInfo().file_layout.size, mNsoHdr.getRoSegmentInfo().is_compressed? " (COMPRESSED)" : ""); + printf(" .data:\n"); + printf(" FileOffset: 0x%" PRIx32 "\n", mNsoHdr.getDataSegmentInfo().file_layout.offset); + printf(" FileSize: 0x%" PRIx32 "%s\n", mNsoHdr.getDataSegmentInfo().file_layout.size, mNsoHdr.getDataSegmentInfo().is_compressed? " (COMPRESSED)" : ""); + printf(" Program Sections:\n"); + printf(" .text:\n"); + printf(" MemoryOffset: 0x%" PRIx32 "\n", mNsoHdr.getTextSegmentInfo().memory_layout.offset); + printf(" MemorySize: 0x%" PRIx32 "\n", mNsoHdr.getTextSegmentInfo().memory_layout.size); + if (mNsoHdr.getTextSegmentInfo().is_hashed && _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) { - printf("[NSO Header]\n"); - printf(" ModuleId: "); - _HEXDUMP_L(mNsoHdr.getModuleId().data, nx::nso::kModuleIdSize); + printf(" Hash: "); + _HEXDUMP_L(mNsoHdr.getTextSegmentInfo().hash.bytes, 32); printf("\n"); - printf(" Program Segments:\n"); - printf(" .module_name:\n"); - printf(" FileOffset: 0x%" PRIx32 "\n", mNsoHdr.getModuleNameInfo().offset); - printf(" FileSize: 0x%" PRIx32 "\n", mNsoHdr.getModuleNameInfo().size); - printf(" .text:\n"); - printf(" FileOffset: 0x%" PRIx32 "\n", mNsoHdr.getTextSegmentInfo().file_layout.offset); - printf(" FileSize: 0x%" PRIx32 "%s\n", mNsoHdr.getTextSegmentInfo().file_layout.size, mNsoHdr.getTextSegmentInfo().is_compressed? " (COMPRESSED)" : ""); - printf(" .ro:\n"); - printf(" FileOffset: 0x%" PRIx32 "\n", mNsoHdr.getRoSegmentInfo().file_layout.offset); - printf(" FileSize: 0x%" PRIx32 "%s\n", mNsoHdr.getRoSegmentInfo().file_layout.size, mNsoHdr.getRoSegmentInfo().is_compressed? " (COMPRESSED)" : ""); - printf(" .data:\n"); - printf(" FileOffset: 0x%" PRIx32 "\n", mNsoHdr.getDataSegmentInfo().file_layout.offset); - printf(" FileSize: 0x%" PRIx32 "%s\n", mNsoHdr.getDataSegmentInfo().file_layout.size, mNsoHdr.getDataSegmentInfo().is_compressed? " (COMPRESSED)" : ""); - printf(" Program Sections:\n"); - printf(" .text:\n"); - printf(" MemoryOffset: 0x%" PRIx32 "\n", mNsoHdr.getTextSegmentInfo().memory_layout.offset); - printf(" MemorySize: 0x%" PRIx32 "\n", mNsoHdr.getTextSegmentInfo().memory_layout.size); - if (mNsoHdr.getTextSegmentInfo().is_hashed && mCliOutputType >= OUTPUT_VERBOSE) - { - printf(" Hash: "); - _HEXDUMP_L(mNsoHdr.getTextSegmentInfo().hash.bytes, 32); - printf("\n"); - } - printf(" .ro:\n"); - printf(" MemoryOffset: 0x%" PRIx32 "\n", mNsoHdr.getRoSegmentInfo().memory_layout.offset); - printf(" MemorySize: 0x%" PRIx32 "\n", mNsoHdr.getRoSegmentInfo().memory_layout.size); - if (mNsoHdr.getRoSegmentInfo().is_hashed && mCliOutputType >= OUTPUT_VERBOSE) - { - printf(" Hash: "); - _HEXDUMP_L(mNsoHdr.getRoSegmentInfo().hash.bytes, 32); - printf("\n"); - } - if (mCliOutputType >= OUTPUT_VERBOSE) - { - printf(" .api_info:\n"); - printf(" MemoryOffset: 0x%" PRIx32 "\n", mNsoHdr.getRoEmbeddedInfo().offset); - printf(" MemorySize: 0x%" PRIx32 "\n", mNsoHdr.getRoEmbeddedInfo().size); - printf(" .dynstr:\n"); - printf(" MemoryOffset: 0x%" PRIx32 "\n", mNsoHdr.getRoDynStrInfo().offset); - printf(" MemorySize: 0x%" PRIx32 "\n", mNsoHdr.getRoDynStrInfo().size); - printf(" .dynsym:\n"); - printf(" MemoryOffset: 0x%" PRIx32 "\n", mNsoHdr.getRoDynSymInfo().offset); - printf(" MemorySize: 0x%" PRIx32 "\n", mNsoHdr.getRoDynSymInfo().size); - } - - printf(" .data:\n"); - printf(" MemoryOffset: 0x%" PRIx32 "\n", mNsoHdr.getDataSegmentInfo().memory_layout.offset); - printf(" MemorySize: 0x%" PRIx32 "\n", mNsoHdr.getDataSegmentInfo().memory_layout.size); - if (mNsoHdr.getDataSegmentInfo().is_hashed && mCliOutputType >= OUTPUT_VERBOSE) - { - printf(" Hash: "); - _HEXDUMP_L(mNsoHdr.getDataSegmentInfo().hash.bytes, 32); - printf("\n"); - } - printf(" .bss:\n"); - printf(" MemorySize: 0x%" PRIx32 "\n", mNsoHdr.getBssSize()); } + printf(" .ro:\n"); + printf(" MemoryOffset: 0x%" PRIx32 "\n", mNsoHdr.getRoSegmentInfo().memory_layout.offset); + printf(" MemorySize: 0x%" PRIx32 "\n", mNsoHdr.getRoSegmentInfo().memory_layout.size); + if (mNsoHdr.getRoSegmentInfo().is_hashed && _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + { + printf(" Hash: "); + _HEXDUMP_L(mNsoHdr.getRoSegmentInfo().hash.bytes, 32); + printf("\n"); + } + if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + { + printf(" .api_info:\n"); + printf(" MemoryOffset: 0x%" PRIx32 "\n", mNsoHdr.getRoEmbeddedInfo().offset); + printf(" MemorySize: 0x%" PRIx32 "\n", mNsoHdr.getRoEmbeddedInfo().size); + printf(" .dynstr:\n"); + printf(" MemoryOffset: 0x%" PRIx32 "\n", mNsoHdr.getRoDynStrInfo().offset); + printf(" MemorySize: 0x%" PRIx32 "\n", mNsoHdr.getRoDynStrInfo().size); + printf(" .dynsym:\n"); + printf(" MemoryOffset: 0x%" PRIx32 "\n", mNsoHdr.getRoDynSymInfo().offset); + printf(" MemorySize: 0x%" PRIx32 "\n", mNsoHdr.getRoDynSymInfo().size); + } + + printf(" .data:\n"); + printf(" MemoryOffset: 0x%" PRIx32 "\n", mNsoHdr.getDataSegmentInfo().memory_layout.offset); + printf(" MemorySize: 0x%" PRIx32 "\n", mNsoHdr.getDataSegmentInfo().memory_layout.size); + if (mNsoHdr.getDataSegmentInfo().is_hashed && _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + { + printf(" Hash: "); + _HEXDUMP_L(mNsoHdr.getDataSegmentInfo().hash.bytes, 32); + printf("\n"); + } + printf(" .bss:\n"); + printf(" MemorySize: 0x%" PRIx32 "\n", mNsoHdr.getBssSize()); #undef _HEXDUMP_L } void NsoProcess::displayRoMetaData() { - if (mApiList.size() > 0 && (mListApi || mCliOutputType > OUTPUT_NORMAL)) + if (mApiList.size() > 0 && (mListApi || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))) { printf("[SDK API List]\n"); for (size_t i = 0; i < mApiList.size(); i++) @@ -283,7 +284,7 @@ void NsoProcess::displayRoMetaData() printf(" Module: %s\n", mApiList[i].getModuleName().c_str()); } } - if (mDynSymbolList.getDynamicSymbolList().getSize() > 0 && (mListSymbols || mCliOutputType > OUTPUT_NORMAL)) + if (mDynSymbolList.getDynamicSymbolList().getSize() > 0 && (mListSymbols || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))) { printf("[Symbol List]\n"); for (size_t i = 0; i < mDynSymbolList.getDynamicSymbolList().getSize(); i++) @@ -292,9 +293,9 @@ void NsoProcess::displayRoMetaData() printf(" %s [SHN=%s (%04x)][STT=%s]\n", symbol.name.c_str(), getSectionIndexStr(symbol.shn_index), symbol.shn_index, getSymbolTypeStr(symbol.symbol_type)); } } - } + const char* NsoProcess::getApiTypeStr(SdkApiString::ApiType type) const { const char* str; diff --git a/programs/nstool/source/NsoProcess.h b/programs/nstool/source/NsoProcess.h index 50714fb..fd4ce7a 100644 --- a/programs/nstool/source/NsoProcess.h +++ b/programs/nstool/source/NsoProcess.h @@ -19,7 +19,7 @@ public: void process(); void setInputFile(fnd::IFile* file, bool ownIFile); - void setCliOutputMode(CliOutputType type); + void setCliOutputMode(CliOutputMode type); void setVerifyMode(bool verify); void setInstructionType(nx::npdm::InstructionType type); @@ -31,7 +31,7 @@ private: fnd::IFile* mFile; bool mOwnIFile; - CliOutputType mCliOutputType; + CliOutputMode mCliOutputMode; bool mVerify; nx::npdm::InstructionType mInstructionType; bool mListApi; diff --git a/programs/nstool/source/PfsProcess.cpp b/programs/nstool/source/PfsProcess.cpp index 30dd139..a6ff585 100644 --- a/programs/nstool/source/PfsProcess.cpp +++ b/programs/nstool/source/PfsProcess.cpp @@ -5,7 +5,7 @@ PfsProcess::PfsProcess() : mFile(nullptr), mOwnIFile(false), - mCliOutputType(OUTPUT_NORMAL), + mCliOutputMode(_BIT(OUTPUT_BASIC)), mVerify(false), mExtractPath(), mExtract(false), @@ -46,10 +46,12 @@ void PfsProcess::process() mFile->read(scratch.getBytes(), 0, scratch.getSize()); mPfs.importBinary(scratch.getBytes(), scratch.getSize()); - if (mCliOutputType >= OUTPUT_NORMAL) + if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) + { displayHeader(); - if (mListFs || mCliOutputType >= OUTPUT_VERBOSE) - displayFs(); + if (mListFs || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + displayFs(); + } if (mPfs.getFsType() == mPfs.TYPE_HFS0 && mVerify) validateHfs(); if (mExtract) @@ -62,9 +64,9 @@ void PfsProcess::setInputFile(fnd::IFile* file, bool ownIFile) mOwnIFile = ownIFile; } -void PfsProcess::setCliOutputMode(CliOutputType type) +void PfsProcess::setCliOutputMode(CliOutputMode type) { - mCliOutputType = type; + mCliOutputMode = type; } void PfsProcess::setVerifyMode(bool verify) @@ -107,7 +109,7 @@ void PfsProcess::displayFs() for (size_t i = 0; i < mPfs.getFileList().getSize(); i++) { printf(" %s", mPfs.getFileList()[i].name.c_str()); - if (mCliOutputType >= OUTPUT_VERBOSE) + if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT)) { if (mPfs.getFsType() == mPfs.TYPE_PFS0) printf(" (offset=0x%" PRIx64 ", size=0x%" PRIx64 ")\n", (uint64_t)mPfs.getFileList()[i].offset, (uint64_t)mPfs.getFileList()[i].size); @@ -149,9 +151,7 @@ void PfsProcess::validateHfs() crypto::sha::Sha256(mCache.getBytes(), file[i].hash_protected_size, hash.bytes); if (hash != file[i].hash) { - if (mCliOutputType >= OUTPUT_MINIMAL) - printf("[WARNING] HFS0 %s%s%s: FAIL (bad hash)\n", !mMountName.empty()? mMountName.c_str() : "", (!mMountName.empty() && mMountName.at(mMountName.length()-1) != '/' )? "/" : "", file[i].name.c_str()); - + printf("[WARNING] HFS0 %s%s%s: FAIL (bad hash)\n", !mMountName.empty()? mMountName.c_str() : "", (!mMountName.empty() && mMountName.at(mMountName.length()-1) != '/' )? "/" : "", file[i].name.c_str()); } } } @@ -174,7 +174,7 @@ void PfsProcess::extractFs() fnd::io::appendToPath(file_path, mExtractPath); fnd::io::appendToPath(file_path, file[i].name); - if (mCliOutputType >= OUTPUT_VERBOSE) + if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) printf("extract=[%s]\n", file_path.c_str()); outFile.open(file_path, outFile.Create); diff --git a/programs/nstool/source/PfsProcess.h b/programs/nstool/source/PfsProcess.h index 24b4c63..441a738 100644 --- a/programs/nstool/source/PfsProcess.h +++ b/programs/nstool/source/PfsProcess.h @@ -16,7 +16,7 @@ public: // generic void setInputFile(fnd::IFile* file, bool ownIFile); - void setCliOutputMode(CliOutputType type); + void setCliOutputMode(CliOutputMode type); void setVerifyMode(bool verify); // pfs specific @@ -32,7 +32,7 @@ private: fnd::IFile* mFile; bool mOwnIFile; - CliOutputType mCliOutputType; + CliOutputMode mCliOutputMode; bool mVerify; std::string mExtractPath; diff --git a/programs/nstool/source/RomfsProcess.cpp b/programs/nstool/source/RomfsProcess.cpp index 1c30b5e..5f2e34e 100644 --- a/programs/nstool/source/RomfsProcess.cpp +++ b/programs/nstool/source/RomfsProcess.cpp @@ -6,7 +6,7 @@ RomfsProcess::RomfsProcess() : mFile(nullptr), mOwnIFile(false), - mCliOutputType(OUTPUT_NORMAL), + mCliOutputMode(_BIT(OUTPUT_BASIC)), mVerify(false), mExtractPath(), mExtract(false), @@ -37,10 +37,12 @@ void RomfsProcess::process() resolveRomfs(); - if (mCliOutputType >= OUTPUT_NORMAL) + if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) + { displayHeader(); - if (mListFs || mCliOutputType >= OUTPUT_VERBOSE) - displayFs(); + if (mListFs || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + displayFs(); + } if (mExtract) extractFs(); } @@ -51,9 +53,9 @@ void RomfsProcess::setInputFile(fnd::IFile* file, bool ownIFile) mOwnIFile = ownIFile; } -void RomfsProcess::setCliOutputMode(CliOutputType type) +void RomfsProcess::setCliOutputMode(CliOutputMode type) { - mCliOutputType = type; + mCliOutputMode = type; } void RomfsProcess::setVerifyMode(bool verify) @@ -94,7 +96,7 @@ void RomfsProcess::displayFile(const sFile& file, size_t tab) const { printTab(tab); printf("%s", file.name.c_str()); - if (mCliOutputType >= OUTPUT_VERBOSE) + if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT)) { printf(" (offset=0x%" PRIx64 ", size=0x%" PRIx64 ")", file.offset, file.size); } @@ -154,9 +156,8 @@ void RomfsProcess::extractDir(const std::string& path, const sDirectory& dir) fnd::io::appendToPath(file_path, dir_path); fnd::io::appendToPath(file_path, dir.file_list[i].name); - if (mCliOutputType >= OUTPUT_VERBOSE) - printf("extract=[%s]\n", file_path.c_str()); - + if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) + printf("extract=[%s]\n", file_path.c_str()); outFile.open(file_path, outFile.Create); mFile->seek(dir.file_list[i].offset); diff --git a/programs/nstool/source/RomfsProcess.h b/programs/nstool/source/RomfsProcess.h index a183517..169ac4c 100644 --- a/programs/nstool/source/RomfsProcess.h +++ b/programs/nstool/source/RomfsProcess.h @@ -95,7 +95,7 @@ public: // generic void setInputFile(fnd::IFile* file, bool ownIFile); - void setCliOutputMode(CliOutputType type); + void setCliOutputMode(CliOutputMode type); void setVerifyMode(bool verify); // romfs specific @@ -110,7 +110,7 @@ private: fnd::IFile* mFile; bool mOwnIFile; - CliOutputType mCliOutputType; + CliOutputMode mCliOutputMode; bool mVerify; std::string mExtractPath; diff --git a/programs/nstool/source/UserSettings.cpp b/programs/nstool/source/UserSettings.cpp index 1031ae2..bdaa973 100644 --- a/programs/nstool/source/UserSettings.cpp +++ b/programs/nstool/source/UserSettings.cpp @@ -45,8 +45,10 @@ void UserSettings::showHelp() printf(" -k, --keyset Specify keyset file\n"); printf(" -t, --type Specify input file type [xci, pfs, romfs, nca, npdm, cnmt, nso, nro, nacp, aset]\n"); printf(" -y, --verify Verify file\n"); + printf("\n Output Options:\n"); + printf(" --showkeys Show keys generated\n"); + printf(" --showlayout Show layout metadata\n"); printf(" -v, --verbose Verbose output\n"); - printf(" -q, --quiet Minimal output\n"); printf("\n XCI (GameCard Image)\n"); printf(" nstool [--listfs] [--update --logo --normal --secure ] <.xci file>\n"); printf(" --listfs Print file system in embedded partitions\n"); @@ -101,9 +103,9 @@ bool UserSettings::isVerifyFile() const return mVerifyFile; } -CliOutputType UserSettings::getCliOutputType() const +CliOutputMode UserSettings::getCliOutputMode() const { - return mOutputType; + return mOutputMode; } bool UserSettings::isListFs() const @@ -223,18 +225,24 @@ void UserSettings::populateCmdArgs(int argc, char** argv, sCmdArgs& cmd_args) cmd_args.verify_file = true; } + else if (args[i] == "--showkeys") + { + if (hasParamter) throw fnd::Exception(kModuleName, args[i] + " does not take a parameter."); + cmd_args.show_keys = true; + } + + else if (args[i] == "--showlayout") + { + if (hasParamter) throw fnd::Exception(kModuleName, args[i] + " does not take a parameter."); + cmd_args.show_layout = true; + } + else if (args[i] == "-v" || args[i] == "--verbose") { if (hasParamter) throw fnd::Exception(kModuleName, args[i] + " does not take a parameter."); cmd_args.verbose_output = true; } - else if (args[i] == "-q" || args[i] == "--quiet") - { - if (hasParamter) throw fnd::Exception(kModuleName, args[i] + " does not take a parameter."); - cmd_args.minimal_output = true; - } - else if (args[i] == "-k" || args[i] == "--keyset") { if (!hasParamter) throw fnd::Exception(kModuleName, args[i] + " requries a parameter."); @@ -588,8 +596,6 @@ void UserSettings::populateUserSettings(sCmdArgs& args) // check invalid input if (args.input_path.isSet == false) throw fnd::Exception(kModuleName, "No input file specified"); - if (args.verbose_output.isSet && args.minimal_output.isSet) - throw fnd::Exception(kModuleName, "Options --verbose and --quiet cannot be used together."); // save arguments mInputPath = *args.input_path; @@ -618,13 +624,22 @@ void UserSettings::populateUserSettings(sCmdArgs& args) mAssetIconPath = args.asset_icon_path; mAssetNacpPath = args.asset_nacp_path; - // determine output path + // determine output mode + mOutputMode = _BIT(OUTPUT_BASIC); if (args.verbose_output.isSet) - mOutputType = OUTPUT_VERBOSE; - else if (args.minimal_output.isSet) - mOutputType = OUTPUT_MINIMAL; - else - mOutputType = OUTPUT_NORMAL; + { + mOutputMode |= _BIT(OUTPUT_KEY_DATA); + mOutputMode |= _BIT(OUTPUT_LAYOUT); + mOutputMode |= _BIT(OUTPUT_EXTENDED); + } + if (args.show_keys.isSet) + { + mOutputMode |= _BIT(OUTPUT_KEY_DATA); + } + if (args.show_layout.isSet) + { + mOutputMode |= _BIT(OUTPUT_LAYOUT); + } // determine input file type if (args.file_type.isSet) diff --git a/programs/nstool/source/UserSettings.h b/programs/nstool/source/UserSettings.h index cb82b5e..0744b41 100644 --- a/programs/nstool/source/UserSettings.h +++ b/programs/nstool/source/UserSettings.h @@ -18,7 +18,7 @@ public: const sKeyset& getKeyset() const; FileType getFileType() const; bool isVerifyFile() const; - CliOutputType getCliOutputType() const; + CliOutputMode getCliOutputMode() const; // specialised toggles bool isListFs() const; @@ -50,8 +50,9 @@ private: sOptional keyset_path; sOptional file_type; sOptional verify_file; + sOptional show_keys; + sOptional show_layout; sOptional verbose_output; - sOptional minimal_output; sOptional list_fs; sOptional update_path; sOptional logo_path; @@ -75,7 +76,7 @@ private: FileType mFileType; sKeyset mKeyset; bool mVerifyFile; - CliOutputType mOutputType; + CliOutputMode mOutputMode; bool mListFs; sOptional mXciUpdatePath; diff --git a/programs/nstool/source/XciProcess.cpp b/programs/nstool/source/XciProcess.cpp index 277811a..b1afc3e 100644 --- a/programs/nstool/source/XciProcess.cpp +++ b/programs/nstool/source/XciProcess.cpp @@ -7,7 +7,7 @@ XciProcess::XciProcess() : mFile(nullptr), mOwnIFile(false), mKeyset(nullptr), - mCliOutputType(OUTPUT_NORMAL), + mCliOutputMode(_BIT(OUTPUT_BASIC)), mVerify(false), mListFs(false), mRootPfs(), @@ -49,10 +49,8 @@ void XciProcess::process() mHdr.importBinary(scratch.getBytes(), scratch.getSize()); // display header - if (mCliOutputType >= OUTPUT_NORMAL) - { + if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC)) displayHeader(); - } // process root partition processRootPfs(); @@ -72,9 +70,9 @@ void XciProcess::setKeyset(const sKeyset* keyset) mKeyset = keyset; } -void XciProcess::setCliOutputMode(CliOutputType type) +void XciProcess::setCliOutputMode(CliOutputMode type) { - mCliOutputType = type; + mCliOutputMode = type; } void XciProcess::setVerifyMode(bool verify) @@ -142,63 +140,81 @@ inline const char* getCardClockRate(uint32_t acc_ctrl_1) void XciProcess::displayHeader() { - printf("[XCI HEADER]\n"); - printf(" Magic: HEAD\n"); - printf(" RomAreaStartPage: 0x%0x", mHdr.getRomAreaStartPage()); - if (mHdr.getRomAreaStartPage() != (uint32_t)(-1)) - printf(" (0x%" PRIx64 ")", nx::XciUtils::blockToAddr(mHdr.getRomAreaStartPage())); - printf("\n"); - printf(" BackupAreaStartPage: 0x%0x", mHdr.getBackupAreaStartPage()); - if (mHdr.getBackupAreaStartPage() != (uint32_t)(-1)) - printf(" (0x%" PRIx64 ")", nx::XciUtils::blockToAddr(mHdr.getBackupAreaStartPage())); - printf("\n"); - printf(" KekIndex: %d\n", mHdr.getKekIndex()); - printf(" TitleKeyDecIndex: %d\n", mHdr.getTitleKeyDecIndex()); - printf(" RomSize: 0x%x (%s)\n", mHdr.getRomSizeType(), getRomSizeStr(mHdr.getRomSizeType())); - printf(" CardHeaderVersion: %d\n", mHdr.getCardHeaderVersion()); - printf(" Flags: 0x%x\n", mHdr.getFlags()); - printf(" AutoBoot: %s\n", getBoolStr(_HAS_BIT(mHdr.getFlags(), nx::xci::FLAG_AUTOBOOT))); - printf(" HistoryErase: %s\n", getBoolStr(_HAS_BIT(mHdr.getFlags(), nx::xci::FLAG_HISTORY_ERASE))); - printf(" RepairTool: %s\n", getBoolStr(_HAS_BIT(mHdr.getFlags(), nx::xci::FLAG_REPAIR_TOOL))); - printf(" PackageId: 0x%" PRIx64 "\n", mHdr.getPackageId()); - printf(" ValidDataEndPage: 0x%x", mHdr.getValidDataEndPage()); - if (mHdr.getValidDataEndPage() != (uint32_t)(-1)) - printf(" (0x%" PRIx64 ")", nx::XciUtils::blockToAddr(mHdr.getValidDataEndPage())); - printf("\n"); - printf(" AesIv: "); - fnd::SimpleTextOutput::hexDump(mHdr.getAesCbcIv().iv, sizeof(mHdr.getAesCbcIv().iv)); - printf(" PartitionFs:\n"); - printf(" Offset: 0x%" PRIx64 "\n", mHdr.getPartitionFsAddress()); - printf(" Size: 0x%" PRIx64 "\n", mHdr.getPartitionFsSize()); - printf(" Hash: "); - fnd::SimpleTextOutput::hexDump(mHdr.getPartitionFsHash().bytes, sizeof(mHdr.getPartitionFsHash().bytes)); - printf(" InitialData:\n"); - printf(" Hash: "); - fnd::SimpleTextOutput::hexDump(mHdr.getInitialDataHash().bytes, sizeof(mHdr.getInitialDataHash().bytes)); - printf(" SelSec: 0x%x\n", mHdr.getSelSec()); - printf(" SelT1Key: 0x%x\n", mHdr.getSelT1Key()); - printf(" SelKey: 0x%x\n", mHdr.getSelKey()); - printf(" LimArea: 0x%x", mHdr.getLimAreaPage()); - if (mHdr.getLimAreaPage() != (uint32_t)(-1)) - printf(" (0x%" PRIx64 ")", nx::XciUtils::blockToAddr(mHdr.getLimAreaPage())); - printf("\n"); + printf("[XCI Header]\n"); + printf(" Magic: HEAD\n"); + printf(" KekIndex: %d\n", mHdr.getKekIndex()); + printf(" TitleKeyDecIndex: %d\n", mHdr.getTitleKeyDecIndex()); + printf(" RomSize: 0x%x (%s)\n", mHdr.getRomSizeType(), getRomSizeStr(mHdr.getRomSizeType())); + printf(" CardHeaderVersion: %d\n", mHdr.getCardHeaderVersion()); + printf(" Flags: 0x%x\n", mHdr.getFlags()); + printf(" AutoBoot: %s\n", getBoolStr(_HAS_BIT(mHdr.getFlags(), nx::xci::FLAG_AUTOBOOT))); + printf(" HistoryErase: %s\n", getBoolStr(_HAS_BIT(mHdr.getFlags(), nx::xci::FLAG_HISTORY_ERASE))); + printf(" RepairTool: %s\n", getBoolStr(_HAS_BIT(mHdr.getFlags(), nx::xci::FLAG_REPAIR_TOOL))); + printf(" PackageId: 0x%" PRIx64 "\n", mHdr.getPackageId()); + if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + { + printf(" InitialDataHash: \n"); + fnd::SimpleTextOutput::hexDump(mHdr.getInitialDataHash().bytes, sizeof(mHdr.getInitialDataHash().bytes)); + } + if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + { + printf(" Enc Header AES-IV: "); + fnd::SimpleTextOutput::hexDump(mHdr.getAesCbcIv().iv, sizeof(mHdr.getAesCbcIv().iv)); + } + printf(" SelSec: 0x%x\n", mHdr.getSelSec()); + printf(" SelT1Key: 0x%x\n", mHdr.getSelT1Key()); + printf(" SelKey: 0x%x\n", mHdr.getSelKey()); + if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT)) + { + printf(" RomAreaStartPage: 0x%0x", mHdr.getRomAreaStartPage()); + if (mHdr.getRomAreaStartPage() != (uint32_t)(-1)) + printf(" (0x%" PRIx64 ")", nx::XciUtils::blockToAddr(mHdr.getRomAreaStartPage())); + printf("\n"); + printf(" BackupAreaStartPage: 0x%0x", mHdr.getBackupAreaStartPage()); + if (mHdr.getBackupAreaStartPage() != (uint32_t)(-1)) + printf(" (0x%" PRIx64 ")", nx::XciUtils::blockToAddr(mHdr.getBackupAreaStartPage())); + printf("\n"); - printf(" FwVersion: v%d.%d\n", mHdr.getFwVerMajor(), mHdr.getFwVerMinor()); - printf(" AccCtrl1: 0x%x\n", mHdr.getAccCtrl1()); - printf(" CardClockRate: %s\n", getCardClockRate(mHdr.getAccCtrl1())); - printf(" Wait1TimeRead: 0x%x\n", mHdr.getWait1TimeRead()); - printf(" Wait2TimeRead: 0x%x\n", mHdr.getWait2TimeRead()); - printf(" Wait1TimeWrite: 0x%x\n", mHdr.getWait1TimeWrite()); - printf(" Wait2TimeWrite: 0x%x\n", mHdr.getWait2TimeWrite()); - printf(" FwMode: 0x%x\n", mHdr.getFwMode()); + printf(" ValidDataEndPage: 0x%x", mHdr.getValidDataEndPage()); + if (mHdr.getValidDataEndPage() != (uint32_t)(-1)) + printf(" (0x%" PRIx64 ")", nx::XciUtils::blockToAddr(mHdr.getValidDataEndPage())); + printf("\n"); + + printf(" LimArea: 0x%x", mHdr.getLimAreaPage()); + if (mHdr.getLimAreaPage() != (uint32_t)(-1)) + printf(" (0x%" PRIx64 ")", nx::XciUtils::blockToAddr(mHdr.getLimAreaPage())); + printf("\n"); + + printf(" PartitionFs Header:\n"); + printf(" Offset: 0x%" PRIx64 "\n", mHdr.getPartitionFsAddress()); + printf(" Size: 0x%" PRIx64 "\n", mHdr.getPartitionFsSize()); + if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)) + { + printf(" Hash: "); + fnd::SimpleTextOutput::hexDump(mHdr.getPartitionFsHash().bytes, sizeof(mHdr.getPartitionFsHash().bytes)); + } + } + + printf("[XCI Extended Header]\n"); + printf(" FwVersion: v%d.%d\n", mHdr.getFwVerMajor(), mHdr.getFwVerMinor()); + printf(" AccCtrl1: 0x%x\n", mHdr.getAccCtrl1()); + printf(" CardClockRate: %s\n", getCardClockRate(mHdr.getAccCtrl1())); + printf(" Wait1TimeRead: 0x%x\n", mHdr.getWait1TimeRead()); + printf(" Wait2TimeRead: 0x%x\n", mHdr.getWait2TimeRead()); + printf(" Wait1TimeWrite: 0x%x\n", mHdr.getWait1TimeWrite()); + printf(" Wait2TimeWrite: 0x%x\n", mHdr.getWait2TimeWrite()); + printf(" FwMode: 0x%x\n", mHdr.getFwMode()); + printf(" Update Partition Info:\n"); #define _SPLIT_VER(ver) ( (ver>>26) & 0x3f), ( (ver>>20) & 0x3f), ( (ver>>16) & 0xf), (ver & 0xffff) - printf(" UppVersion: v%" PRId32 " (%d.%d.%d.%d)\n", mHdr.getUppVersion(), _SPLIT_VER(mHdr.getUppVersion())); + printf(" CUP Version: v%" PRId32 " (%d.%d.%d.%d)\n", mHdr.getUppVersion(), _SPLIT_VER(mHdr.getUppVersion())); #undef _SPLIT_VER - printf(" UppHash: "); + printf(" CUP TitleId: %016" PRIx64 "\n", mHdr.getUppId()); + printf(" Partition Hash: "); fnd::SimpleTextOutput::hexDump(mHdr.getUppHash(), 8); - printf(" UppId: %016" PRIx64 "\n", mHdr.getUppId()); + + } bool XciProcess::validateRegionOfFile(size_t offset, size_t len, const byte_t* test_hash) @@ -217,9 +233,7 @@ void XciProcess::validateXciSignature() crypto::sha::Sha256((byte_t*)&mHdrPage.header, sizeof(nx::sXciHeader), calc_hash.bytes); if (crypto::rsa::pkcs::rsaVerify(mKeyset->xci.header_sign_key, crypto::sha::HASH_SHA256, calc_hash.bytes, mHdrPage.signature) != 0) { - // this is minimal even though it's a warning because it's a validation method - if (mCliOutputType >= OUTPUT_MINIMAL) - printf("[WARNING] XCI Header Signature: FAIL \n"); + printf("[WARNING] XCI Header Signature: FAIL \n"); } } @@ -232,7 +246,7 @@ void XciProcess::processRootPfs() mRootPfs.setInputFile(new OffsetAdjustedIFile(mFile, SHARED_IFILE, mHdr.getPartitionFsAddress(), mHdr.getPartitionFsSize()), OWN_IFILE); mRootPfs.setListFs(mListFs); mRootPfs.setVerifyMode(false); - mRootPfs.setCliOutputMode(mCliOutputType); + mRootPfs.setCliOutputMode(mCliOutputMode); mRootPfs.setMountPointName(kXciMountPointName); mRootPfs.process(); } @@ -252,7 +266,7 @@ void XciProcess::processPartitionPfs() tmp.setInputFile(new OffsetAdjustedIFile(mFile, SHARED_IFILE, mHdr.getPartitionFsAddress() + rootPartitions[i].offset, rootPartitions[i].size), OWN_IFILE); tmp.setListFs(mListFs); tmp.setVerifyMode(mVerify); - tmp.setCliOutputMode(mCliOutputType); + tmp.setCliOutputMode(mCliOutputMode); tmp.setMountPointName(kXciMountPointName + rootPartitions[i].name); for (size_t j = 0; j < mExtractInfo.size(); j++) { diff --git a/programs/nstool/source/XciProcess.h b/programs/nstool/source/XciProcess.h index 2b9216e..7be23a4 100644 --- a/programs/nstool/source/XciProcess.h +++ b/programs/nstool/source/XciProcess.h @@ -20,7 +20,7 @@ public: // generic void setInputFile(fnd::IFile* file, bool ownIFile); void setKeyset(const sKeyset* keyset); - void setCliOutputMode(CliOutputType type); + void setCliOutputMode(CliOutputMode type); void setVerifyMode(bool verify); // xci specific @@ -34,7 +34,7 @@ private: fnd::IFile* mFile; bool mOwnIFile; const sKeyset* mKeyset; - CliOutputType mCliOutputType; + CliOutputMode mCliOutputMode; bool mVerify; struct sExtractInfo diff --git a/programs/nstool/source/main.cpp b/programs/nstool/source/main.cpp index 0edeffd..9039e59 100644 --- a/programs/nstool/source/main.cpp +++ b/programs/nstool/source/main.cpp @@ -25,7 +25,7 @@ int main(int argc, char** argv) xci.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE); xci.setKeyset(&user_set.getKeyset()); - xci.setCliOutputMode(user_set.getCliOutputType()); + xci.setCliOutputMode(user_set.getCliOutputMode()); xci.setVerifyMode(user_set.isVerifyFile()); if (user_set.getXciUpdatePath().isSet) @@ -45,7 +45,7 @@ int main(int argc, char** argv) PfsProcess pfs; pfs.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE); - pfs.setCliOutputMode(user_set.getCliOutputType()); + pfs.setCliOutputMode(user_set.getCliOutputMode()); pfs.setVerifyMode(user_set.isVerifyFile()); if (user_set.getFsPath().isSet) @@ -59,7 +59,7 @@ int main(int argc, char** argv) RomfsProcess romfs; romfs.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE); - romfs.setCliOutputMode(user_set.getCliOutputType()); + romfs.setCliOutputMode(user_set.getCliOutputMode()); romfs.setVerifyMode(user_set.isVerifyFile()); if (user_set.getFsPath().isSet) @@ -74,7 +74,7 @@ int main(int argc, char** argv) nca.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE); nca.setKeyset(&user_set.getKeyset()); - nca.setCliOutputMode(user_set.getCliOutputType()); + nca.setCliOutputMode(user_set.getCliOutputMode()); nca.setVerifyMode(user_set.isVerifyFile()); @@ -96,7 +96,7 @@ int main(int argc, char** argv) npdm.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE); npdm.setKeyset(&user_set.getKeyset()); - npdm.setCliOutputMode(user_set.getCliOutputType()); + npdm.setCliOutputMode(user_set.getCliOutputMode()); npdm.setVerifyMode(user_set.isVerifyFile()); npdm.process(); @@ -106,7 +106,7 @@ int main(int argc, char** argv) CnmtProcess cnmt; cnmt.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE); - cnmt.setCliOutputMode(user_set.getCliOutputType()); + cnmt.setCliOutputMode(user_set.getCliOutputMode()); cnmt.setVerifyMode(user_set.isVerifyFile()); cnmt.process(); @@ -116,7 +116,7 @@ int main(int argc, char** argv) NsoProcess obj; obj.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE); - obj.setCliOutputMode(user_set.getCliOutputType()); + obj.setCliOutputMode(user_set.getCliOutputMode()); obj.setVerifyMode(user_set.isVerifyFile()); obj.setInstructionType(user_set.getInstType()); @@ -130,7 +130,7 @@ int main(int argc, char** argv) NroProcess obj; obj.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE); - obj.setCliOutputMode(user_set.getCliOutputType()); + obj.setCliOutputMode(user_set.getCliOutputMode()); obj.setVerifyMode(user_set.isVerifyFile()); obj.setInstructionType(user_set.getInstType()); @@ -153,7 +153,7 @@ int main(int argc, char** argv) NacpProcess nacp; nacp.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE); - nacp.setCliOutputMode(user_set.getCliOutputType()); + nacp.setCliOutputMode(user_set.getCliOutputMode()); nacp.setVerifyMode(user_set.isVerifyFile()); nacp.process(); @@ -163,7 +163,7 @@ int main(int argc, char** argv) AssetProcess obj; obj.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE); - obj.setCliOutputMode(user_set.getCliOutputType()); + obj.setCliOutputMode(user_set.getCliOutputMode()); obj.setVerifyMode(user_set.isVerifyFile()); if (user_set.getAssetIconPath().isSet) diff --git a/programs/nstool/source/nstool.h b/programs/nstool/source/nstool.h index fa5fd9c..cf6505c 100644 --- a/programs/nstool/source/nstool.h +++ b/programs/nstool/source/nstool.h @@ -31,13 +31,16 @@ enum FileType FILE_INVALID = -1, }; -enum CliOutputType +enum CliOutputModeFlag { - OUTPUT_MINIMAL, - OUTPUT_NORMAL, - OUTPUT_VERBOSE + OUTPUT_BASIC, + OUTPUT_LAYOUT, + OUTPUT_KEY_DATA, + OUTPUT_EXTENDED }; +typedef byte_t CliOutputMode; + template struct sOptional {