diff --git a/lib/libnx/include/nx/ContentMetaBinary.h b/lib/libnx/include/nx/ContentMetaBinary.h index c9f08cb..6bf2ddb 100644 --- a/lib/libnx/include/nx/ContentMetaBinary.h +++ b/lib/libnx/include/nx/ContentMetaBinary.h @@ -2,7 +2,7 @@ #include #include #include -#include +#include namespace nx @@ -14,14 +14,14 @@ namespace nx struct ContentInfo { crypto::sha::sSha256Hash hash; - byte_t nca_id[cmnt::kContentIdLen]; + byte_t nca_id[cnmt::kContentIdLen]; size_t size; - cmnt::ContentType type; + cnmt::ContentType type; ContentInfo& operator=(const ContentInfo& other) { hash = other.hash; - memcpy(nca_id, other.nca_id, cmnt::kContentIdLen); + memcpy(nca_id, other.nca_id, cnmt::kContentIdLen); size = other.size; type = other.type; return *this; @@ -30,7 +30,7 @@ namespace nx bool operator==(const ContentInfo& other) const { return (hash == other.hash) \ - && (memcmp(nca_id, other.nca_id, cmnt::kContentIdLen) == 0) \ + && (memcmp(nca_id, other.nca_id, cnmt::kContentIdLen) == 0) \ && (size == other.size) \ && (type == other.type); } @@ -45,7 +45,7 @@ namespace nx { uint64_t id; uint32_t version; - cmnt::ContentMetaType type; + cnmt::ContentMetaType type; byte_t attributes; ContentMetaInfo& operator=(const ContentMetaInfo& other) @@ -71,6 +71,99 @@ namespace nx } }; + struct ApplicationMetaExtendedHeader + { + uint64_t patch_id; + uint32_t required_system_version; + + ApplicationMetaExtendedHeader& operator=(const ApplicationMetaExtendedHeader& other) + { + patch_id = other.patch_id; + required_system_version = other.required_system_version; + return *this; + } + + bool operator==(const ApplicationMetaExtendedHeader& other) const + { + return (patch_id == other.patch_id) \ + && (required_system_version == other.required_system_version); + } + + bool operator!=(const ApplicationMetaExtendedHeader& other) const + { + return !operator==(other); + } + }; + + struct PatchMetaExtendedHeader + { + uint64_t application_id; + uint32_t required_system_version; + + PatchMetaExtendedHeader& operator=(const PatchMetaExtendedHeader& other) + { + application_id = other.application_id; + required_system_version = other.required_system_version; + return *this; + } + + bool operator==(const PatchMetaExtendedHeader& other) const + { + return (application_id == other.application_id) \ + && (required_system_version == other.required_system_version); + } + + bool operator!=(const PatchMetaExtendedHeader& other) const + { + return !operator==(other); + } + }; + + struct AddOnContentMetaExtendedHeader + { + uint64_t application_id; + uint32_t required_system_version; + + AddOnContentMetaExtendedHeader& operator=(const AddOnContentMetaExtendedHeader& other) + { + application_id = other.application_id; + required_system_version = other.required_system_version; + return *this; + } + + bool operator==(const AddOnContentMetaExtendedHeader& other) const + { + return (application_id == other.application_id) \ + && (required_system_version == other.required_system_version); + } + + bool operator!=(const AddOnContentMetaExtendedHeader& other) const + { + return !operator==(other); + } + }; + + struct DeltaMetaExtendedHeader + { + uint64_t application_id; + + DeltaMetaExtendedHeader& operator=(const DeltaMetaExtendedHeader& other) + { + application_id = other.application_id; + return *this; + } + + bool operator==(const DeltaMetaExtendedHeader& other) const + { + return (application_id == other.application_id); + } + + bool operator!=(const DeltaMetaExtendedHeader& other) const + { + return !operator==(other); + } + }; + ContentMetaBinary(); ContentMetaBinary(const ContentMetaBinary& other); ContentMetaBinary(const byte_t* bytes, size_t len); @@ -92,14 +185,26 @@ namespace nx uint32_t getTitleVersion() const; void setTitleVersion(uint32_t version); - cmnt::ContentMetaType getType() const; - void setType(cmnt::ContentMetaType type); + cnmt::ContentMetaType getType() const; + void setType(cnmt::ContentMetaType type); byte_t getAttributes() const; void setAttributes(byte_t attributes); - uint32_t getRequiredSystemVersion() const; - void setRequiredSystemVersion(uint32_t version); + uint32_t getRequiredDownloadSystemVersion() const; + void setRequiredDownloadSystemVersion(uint32_t version); + + const ApplicationMetaExtendedHeader& getApplicationMetaExtendedHeader() const; + void setApplicationMetaExtendedHeader(const ApplicationMetaExtendedHeader& exhdr); + + const PatchMetaExtendedHeader& getPatchMetaExtendedHeader() const; + void setPatchMetaExtendedHeader(const PatchMetaExtendedHeader& exhdr); + + const AddOnContentMetaExtendedHeader& getAddOnContentMetaExtendedHeader() const; + void setAddOnContentMetaExtendedHeader(const AddOnContentMetaExtendedHeader& exhdr); + + const DeltaMetaExtendedHeader& getDeltaMetaExtendedHeader() const; + void setDeltaMetaExtendedHeader(const DeltaMetaExtendedHeader& exhdr); const fnd::List& getContentInfo() const; void setContentInfo(const fnd::List& info); @@ -123,10 +228,16 @@ namespace nx // variables uint64_t mTitleId; uint32_t mTitleVersion; - cmnt::ContentMetaType mType; + cnmt::ContentMetaType mType; byte_t mAttributes; - uint32_t mRequiredSystemVersion; + uint32_t mRequiredDownloadSystemVersion; fnd::MemoryBlob mExtendedHeader; + + ApplicationMetaExtendedHeader mApplicationMetaExtendedHeader; + PatchMetaExtendedHeader mPatchMetaExtendedHeader; + AddOnContentMetaExtendedHeader mAddOnContentMetaExtendedHeader; + DeltaMetaExtendedHeader mDeltaMetaExtendedHeader; + fnd::List mContentInfo; fnd::List mContentMetaInfo; fnd::MemoryBlob mExtendedData; @@ -137,11 +248,11 @@ namespace nx inline size_t getContentMetaInfoOffset(size_t exhdrSize, size_t contentInfoNum) const { return getContentInfoOffset(exhdrSize) + contentInfoNum * sizeof(sContentInfo); } inline size_t getExtendedDataOffset(size_t exhdrSize, size_t contentInfoNum, size_t contentMetaNum) const { return getContentMetaInfoOffset(exhdrSize, contentInfoNum) + contentMetaNum * sizeof(sContentMetaInfo); } inline size_t getDigestOffset(size_t exhdrSize, size_t contentInfoNum, size_t contentMetaNum, size_t exdataSize) const { return getExtendedDataOffset(exhdrSize, contentInfoNum, contentMetaNum) + exdataSize; } - inline size_t getTotalSize(size_t exhdrSize, size_t contentInfoNum, size_t contentMetaNum, size_t exdataSize) const { return getDigestOffset(exhdrSize, contentInfoNum, contentMetaNum, exdataSize) + cmnt::kDigestLen; } + inline size_t getTotalSize(size_t exhdrSize, size_t contentInfoNum, size_t contentMetaNum, size_t exdataSize) const { return getDigestOffset(exhdrSize, contentInfoNum, contentMetaNum, exdataSize) + cnmt::kDigestLen; } - bool validateExtendedHeaderSize(cmnt::ContentMetaType type, size_t exhdrSize); - size_t getExtendedDataSize(cmnt::ContentMetaType type, const byte_t* data); - void validateBinary(const byte_t* bytes, size_t len); + bool validateExtendedHeaderSize(cnmt::ContentMetaType type, size_t exhdrSize) const; + size_t getExtendedDataSize(cnmt::ContentMetaType type, const byte_t* data) const; + void validateBinary(const byte_t* bytes, size_t len) const; bool isEqual(const ContentMetaBinary& other) const; void copyFrom(const ContentMetaBinary& other); diff --git a/lib/libnx/include/nx/cmnt.h b/lib/libnx/include/nx/cnmt.h similarity index 90% rename from lib/libnx/include/nx/cmnt.h rename to lib/libnx/include/nx/cnmt.h index 3b37bf0..8912a89 100644 --- a/lib/libnx/include/nx/cmnt.h +++ b/lib/libnx/include/nx/cnmt.h @@ -7,7 +7,7 @@ namespace nx { - namespace cmnt + namespace cnmt { enum ContentType { @@ -43,7 +43,6 @@ namespace nx enum ContentMetaAttribute { - ATTRIBUTE_NONE, ATTRIBUTE_INCLUDES_EX_FAT_DRIVER, ATTRIBUTE_REBOOTLESS }; @@ -79,14 +78,14 @@ namespace nx le_uint16_t content_meta_count; byte_t attributes; byte_t reserved_1[3]; - le_uint32_t required_system_version; + le_uint32_t required_download_system_version; byte_t reserved_2[4]; }; struct sContentInfo { crypto::sha::sSha256Hash content_hash; - byte_t content_id[cmnt::kContentIdLen]; + byte_t content_id[cnmt::kContentIdLen]; le_uint32_t size_lower; le_uint16_t size_higher; byte_t content_type; @@ -104,14 +103,14 @@ namespace nx struct sApplicationMetaExtendedHeader { - le_uint64_t id; + le_uint64_t patch_id; le_uint32_t required_system_version; byte_t reserved[4]; }; struct sPatchMetaExtendedHeader { - le_uint64_t id; + le_uint64_t application_id; le_uint32_t required_system_version; le_uint32_t extended_data_size; byte_t reserved[8]; @@ -119,21 +118,21 @@ namespace nx struct sAddOnContentMetaExtendedHeader { - le_uint64_t id; + le_uint64_t application_id; le_uint32_t required_system_version; byte_t reserved[4]; }; struct sDeltaMetaExtendedHeader { - le_uint64_t id; + le_uint64_t application_id; le_uint32_t extended_data_size; byte_t reserved[4]; }; struct sDigest { - byte_t data[cmnt::kDigestLen]; + byte_t data[cnmt::kDigestLen]; }; #pragma pack(pop) } \ No newline at end of file diff --git a/lib/libnx/source/ContentMetaBinary.cpp b/lib/libnx/source/ContentMetaBinary.cpp index 003da2f..450eb61 100644 --- a/lib/libnx/source/ContentMetaBinary.cpp +++ b/lib/libnx/source/ContentMetaBinary.cpp @@ -43,9 +43,9 @@ void nx::ContentMetaBinary::importBinary(const byte_t * bytes, size_t len) mTitleId = hdr->id.get(); mTitleVersion = hdr->version.get(); - mType = (cmnt::ContentMetaType)hdr->type; + mType = (cnmt::ContentMetaType)hdr->type; mAttributes = hdr->attributes; - mRequiredSystemVersion = hdr->required_system_version.get(); + mRequiredDownloadSystemVersion = hdr->required_download_system_version.get(); size_t exdata_size = 0; // save exheader @@ -54,6 +54,27 @@ void nx::ContentMetaBinary::importBinary(const byte_t * bytes, size_t len) mExtendedHeader.alloc(hdr->exhdr_size.get()); memcpy(mExtendedHeader.getBytes(), bytes + getExtendedHeaderOffset(), hdr->exhdr_size.get()); + switch (mType) + { + case (cnmt::METATYPE_APPLICATION): + mApplicationMetaExtendedHeader.patch_id = ((sApplicationMetaExtendedHeader*)mExtendedHeader.getBytes())->patch_id.get(); + mApplicationMetaExtendedHeader.required_system_version = ((sApplicationMetaExtendedHeader*)mExtendedHeader.getBytes())->required_system_version.get(); + break; + case (cnmt::METATYPE_PATCH): + mPatchMetaExtendedHeader.application_id = ((sPatchMetaExtendedHeader*)mExtendedHeader.getBytes())->application_id.get(); + mPatchMetaExtendedHeader.required_system_version = ((sPatchMetaExtendedHeader*)mExtendedHeader.getBytes())->required_system_version.get(); + break; + case (cnmt::METATYPE_ADD_ON_CONTENT): + mAddOnContentMetaExtendedHeader.application_id = ((sAddOnContentMetaExtendedHeader*)mExtendedHeader.getBytes())->application_id.get(); + mAddOnContentMetaExtendedHeader.required_system_version = ((sAddOnContentMetaExtendedHeader*)mExtendedHeader.getBytes())->required_system_version.get(); + break; + case (cnmt::METATYPE_DELTA): + mDeltaMetaExtendedHeader.application_id = ((sDeltaMetaExtendedHeader*)mExtendedHeader.getBytes())->application_id.get(); + break; + default: + break; + } + exdata_size = getExtendedDataSize(mType, mExtendedHeader.getBytes()); } @@ -64,9 +85,9 @@ void nx::ContentMetaBinary::importBinary(const byte_t * bytes, size_t len) for (size_t i = 0; i < hdr->content_count.get(); i++) { mContentInfo[i].hash = info[i].content_hash; - memcpy(mContentInfo[i].nca_id, info[i].content_id, cmnt::kContentIdLen); + memcpy(mContentInfo[i].nca_id, info[i].content_id, cnmt::kContentIdLen); mContentInfo[i].size = (uint64_t)(info[i].size_lower.get()) | (uint64_t)(info[i].size_higher.get()) << 32; - mContentInfo[i].type = (cmnt::ContentType)info[i].content_type; + mContentInfo[i].type = (cnmt::ContentType)info[i].content_type; } } @@ -78,7 +99,7 @@ void nx::ContentMetaBinary::importBinary(const byte_t * bytes, size_t len) { mContentMetaInfo[i].id = info[i].id.get(); mContentMetaInfo[i].version = info[i].version.get(); - mContentMetaInfo[i].type = (cmnt::ContentMetaType)info[i].type; + mContentMetaInfo[i].type = (cnmt::ContentMetaType)info[i].type; mContentMetaInfo[i].attributes = info[i].attributes; } } @@ -91,7 +112,7 @@ void nx::ContentMetaBinary::importBinary(const byte_t * bytes, size_t len) } // save digest - memcpy(mDigest.data, bytes + getDigestOffset(hdr->exhdr_size.get(), hdr->content_count.get(), hdr->content_meta_count.get(), exdata_size), cmnt::kDigestLen); + memcpy(mDigest.data, bytes + getDigestOffset(hdr->exhdr_size.get(), hdr->content_count.get(), hdr->content_meta_count.get(), exdata_size), cnmt::kDigestLen); } @@ -100,14 +121,18 @@ void nx::ContentMetaBinary::clear() mBinaryBlob.clear(); mTitleId = 0; mTitleVersion = 0; - mType = cmnt::METATYPE_SYSTEM_PROGRAM; - mAttributes = cmnt::ATTRIBUTE_NONE; - mRequiredSystemVersion = 0; + mType = cnmt::METATYPE_SYSTEM_PROGRAM; + mAttributes = 0; + mRequiredDownloadSystemVersion = 0; mExtendedHeader.clear(); + memset(&mApplicationMetaExtendedHeader, 0, sizeof(mApplicationMetaExtendedHeader)); + memset(&mPatchMetaExtendedHeader, 0, sizeof(mPatchMetaExtendedHeader)); + memset(&mAddOnContentMetaExtendedHeader, 0, sizeof(mAddOnContentMetaExtendedHeader)); + memset(&mDeltaMetaExtendedHeader, 0, sizeof(mDeltaMetaExtendedHeader)); mContentInfo.clear(); mContentMetaInfo.clear(); mExtendedData.clear(); - memset(mDigest.data, 0, cmnt::kDigestLen); + memset(mDigest.data, 0, cnmt::kDigestLen); } uint64_t nx::ContentMetaBinary::getTitleId() const @@ -130,12 +155,12 @@ void nx::ContentMetaBinary::setTitleVersion(uint32_t version) mTitleVersion = version; } -nx::cmnt::ContentMetaType nx::ContentMetaBinary::getType() const +nx::cnmt::ContentMetaType nx::ContentMetaBinary::getType() const { return mType; } -void nx::ContentMetaBinary::setType(cmnt::ContentMetaType type) +void nx::ContentMetaBinary::setType(cnmt::ContentMetaType type) { mType = type; } @@ -150,14 +175,54 @@ void nx::ContentMetaBinary::setAttributes(byte_t attributes) mAttributes = attributes; } -uint32_t nx::ContentMetaBinary::getRequiredSystemVersion() const +uint32_t nx::ContentMetaBinary::getRequiredDownloadSystemVersion() const { - return mRequiredSystemVersion; + return mRequiredDownloadSystemVersion; } -void nx::ContentMetaBinary::setRequiredSystemVersion(uint32_t version) +void nx::ContentMetaBinary::setRequiredDownloadSystemVersion(uint32_t version) { - mRequiredSystemVersion = version; + mRequiredDownloadSystemVersion = version; +} + +const nx::ContentMetaBinary::ApplicationMetaExtendedHeader& nx::ContentMetaBinary::getApplicationMetaExtendedHeader() const +{ + return mApplicationMetaExtendedHeader; +} + +void nx::ContentMetaBinary::setApplicationMetaExtendedHeader(const ApplicationMetaExtendedHeader& exhdr) +{ + mApplicationMetaExtendedHeader = exhdr; +} + +const nx::ContentMetaBinary::PatchMetaExtendedHeader& nx::ContentMetaBinary::getPatchMetaExtendedHeader() const +{ + return mPatchMetaExtendedHeader; +} + +void nx::ContentMetaBinary::setPatchMetaExtendedHeader(const PatchMetaExtendedHeader& exhdr) +{ + mPatchMetaExtendedHeader = exhdr; +} + +const nx::ContentMetaBinary::AddOnContentMetaExtendedHeader& nx::ContentMetaBinary::getAddOnContentMetaExtendedHeader() const +{ + return mAddOnContentMetaExtendedHeader; +} + +void nx::ContentMetaBinary::setAddOnContentMetaExtendedHeader(const AddOnContentMetaExtendedHeader& exhdr) +{ + mAddOnContentMetaExtendedHeader = exhdr; +} + +const nx::ContentMetaBinary::DeltaMetaExtendedHeader& nx::ContentMetaBinary::getDeltaMetaExtendedHeader() const +{ + return mDeltaMetaExtendedHeader; +} + +void nx::ContentMetaBinary::setDeltaMetaExtendedHeader(const DeltaMetaExtendedHeader& exhdr) +{ + mDeltaMetaExtendedHeader = exhdr; } const fnd::List& nx::ContentMetaBinary::getContentInfo() const @@ -198,34 +263,43 @@ const nx::sDigest & nx::ContentMetaBinary::getDigest() const void nx::ContentMetaBinary::setDigest(const nx::sDigest & digest) { - memcpy(mDigest.data, digest.data, cmnt::kDigestLen); + memcpy(mDigest.data, digest.data, cnmt::kDigestLen); } -bool nx::ContentMetaBinary::validateExtendedHeaderSize(cmnt::ContentMetaType type, size_t exhdrSize) +bool nx::ContentMetaBinary::validateExtendedHeaderSize(cnmt::ContentMetaType type, size_t exhdrSize) const { bool validSize = false; - if (type == cmnt::METATYPE_APPLICATION && exhdrSize == sizeof(sApplicationMetaExtendedHeader)) - validSize = true; - else if (type == cmnt::METATYPE_PATCH && exhdrSize == sizeof(sPatchMetaExtendedHeader)) - validSize = true; - else if (type == cmnt::METATYPE_ADD_ON_CONTENT && exhdrSize == sizeof(sAddOnContentMetaExtendedHeader)) - validSize = true; - else if (type == cmnt::METATYPE_DELTA && exhdrSize == sizeof(sDeltaMetaExtendedHeader)) - validSize = true; + switch (type) + { + case (cnmt::METATYPE_APPLICATION): + validSize = (exhdrSize == sizeof(sApplicationMetaExtendedHeader)); + break; + case (cnmt::METATYPE_PATCH): + validSize = (exhdrSize == sizeof(sPatchMetaExtendedHeader)); + break; + case (cnmt::METATYPE_ADD_ON_CONTENT): + validSize = (exhdrSize == sizeof(sAddOnContentMetaExtendedHeader)); + break; + case (cnmt::METATYPE_DELTA): + validSize = (exhdrSize == sizeof(sDeltaMetaExtendedHeader)); + break; + default: + validSize = (exhdrSize == 0); + } return validSize; } -size_t nx::ContentMetaBinary::getExtendedDataSize(cmnt::ContentMetaType type, const byte_t * data) +size_t nx::ContentMetaBinary::getExtendedDataSize(cnmt::ContentMetaType type, const byte_t * data) const { size_t exdata_len = 0; - if (type == cmnt::METATYPE_PATCH) + if (type == cnmt::METATYPE_PATCH) { const sPatchMetaExtendedHeader* exhdr = (const sPatchMetaExtendedHeader*)(data); exdata_len = exhdr->extended_data_size.get(); } - else if (type == cmnt::METATYPE_DELTA) + else if (type == cnmt::METATYPE_DELTA) { const sDeltaMetaExtendedHeader* exhdr = (const sDeltaMetaExtendedHeader*)(data); exdata_len = exhdr->extended_data_size.get(); @@ -233,7 +307,7 @@ size_t nx::ContentMetaBinary::getExtendedDataSize(cmnt::ContentMetaType type, co return exdata_len; } -void nx::ContentMetaBinary::validateBinary(const byte_t * bytes, size_t len) +void nx::ContentMetaBinary::validateBinary(const byte_t * bytes, size_t len) const { // check if it is large enough to read the header if (len < sizeof(sContentMetaHeader)) @@ -245,7 +319,7 @@ void nx::ContentMetaBinary::validateBinary(const byte_t * bytes, size_t len) const sContentMetaHeader* hdr = (const sContentMetaHeader*)bytes; // validate extended header size - if (validateExtendedHeaderSize((cmnt::ContentMetaType)hdr->type, hdr->exhdr_size.get()) == false) + if (validateExtendedHeaderSize((cnmt::ContentMetaType)hdr->type, hdr->exhdr_size.get()) == false) { throw fnd::Exception(kModuleName, "Invalid extended header size"); } @@ -257,7 +331,7 @@ void nx::ContentMetaBinary::validateBinary(const byte_t * bytes, size_t len) } // check binary size again with extended data size - if (len < getTotalSize(hdr->exhdr_size.get(), hdr->content_count.get(), hdr->content_meta_count.get(), getExtendedDataSize((cmnt::ContentMetaType)hdr->type, bytes + getExtendedHeaderOffset()))) + if (len < getTotalSize(hdr->exhdr_size.get(), hdr->content_count.get(), hdr->content_meta_count.get(), getExtendedDataSize((cnmt::ContentMetaType)hdr->type, bytes + getExtendedHeaderOffset()))) { throw fnd::Exception(kModuleName, "Binary too small"); } @@ -269,12 +343,16 @@ bool nx::ContentMetaBinary::isEqual(const ContentMetaBinary & other) const && (mTitleVersion == other.mTitleVersion) \ && (mType == other.mType) \ && (mAttributes == other.mAttributes) \ - && (mRequiredSystemVersion == other.mRequiredSystemVersion) \ + && (mRequiredDownloadSystemVersion == other.mRequiredDownloadSystemVersion) \ && (mExtendedHeader == other.mExtendedHeader) \ + && (mApplicationMetaExtendedHeader == other.mApplicationMetaExtendedHeader) \ + && (mPatchMetaExtendedHeader == other.mPatchMetaExtendedHeader) \ + && (mAddOnContentMetaExtendedHeader == other.mAddOnContentMetaExtendedHeader) \ + && (mDeltaMetaExtendedHeader == other.mDeltaMetaExtendedHeader) \ && (mContentInfo == other.mContentInfo) \ && (mContentMetaInfo == other.mContentMetaInfo) \ && (mExtendedData == other.mExtendedData) \ - && (memcmp(mDigest.data, other.mDigest.data, cmnt::kDigestLen) == 0); + && (memcmp(mDigest.data, other.mDigest.data, cnmt::kDigestLen) == 0); } void nx::ContentMetaBinary::copyFrom(const ContentMetaBinary & other) @@ -290,11 +368,15 @@ void nx::ContentMetaBinary::copyFrom(const ContentMetaBinary & other) mTitleVersion = other.mTitleVersion; mType = other.mType; mAttributes = other.mAttributes; - mRequiredSystemVersion = other.mRequiredSystemVersion; + mRequiredDownloadSystemVersion = other.mRequiredDownloadSystemVersion; mExtendedHeader = other.mExtendedHeader; + mApplicationMetaExtendedHeader = other.mApplicationMetaExtendedHeader; + mPatchMetaExtendedHeader = other.mPatchMetaExtendedHeader; + mAddOnContentMetaExtendedHeader = other.mAddOnContentMetaExtendedHeader; + mDeltaMetaExtendedHeader = other.mDeltaMetaExtendedHeader; mContentInfo = other.mContentInfo; mContentMetaInfo = other.mContentMetaInfo; mExtendedData = other.mExtendedData; - memcpy(mDigest.data, other.mDigest.data, cmnt::kDigestLen); + memcpy(mDigest.data, other.mDigest.data, cnmt::kDigestLen); } } diff --git a/programs/nstool/source/CmntProcess.cpp b/programs/nstool/source/CmntProcess.cpp deleted file mode 100644 index d321c22..0000000 --- a/programs/nstool/source/CmntProcess.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "CmntProcess.h" \ No newline at end of file diff --git a/programs/nstool/source/CmntProcess.h b/programs/nstool/source/CmntProcess.h deleted file mode 100644 index 6f70f09..0000000 --- a/programs/nstool/source/CmntProcess.h +++ /dev/null @@ -1 +0,0 @@ -#pragma once diff --git a/programs/nstool/source/CnmtProcess.cpp b/programs/nstool/source/CnmtProcess.cpp new file mode 100644 index 0000000..5aade5c --- /dev/null +++ b/programs/nstool/source/CnmtProcess.cpp @@ -0,0 +1,185 @@ +#include +#include "OffsetAdjustedIFile.h" +#include "CnmtProcess.h" + +const std::string kContentTypeStr[7] = +{ + "Meta", + "Program", + "Data", + "Control", + "HtmlDocument", + "LegalInformation", + "DeltaFragment" +}; + +const std::string kContentMetaTypeStr[2][0x80] = +{ + { + "" + "SystemProgram", + "SystemData", + "SystemUpdate", + "BootImagePackage", + "BootImagePackageSafe" + }, + { + "Application", + "Patch", + "AddOnContent", + "Delta" + } +}; + +inline const std::string& getContentMetaTypeStr(byte_t index) +{ + return (index < 0x80) ? kContentMetaTypeStr[0][index] : kContentMetaTypeStr[1][index-0x80]; +} + +const std::string kUpdateTypeStr[3] = +{ + "ApplyAsDelta", + "Overwrite", + "Create" +}; + +const std::string kContentMetaAttrStr[3] = +{ + "IncludesExFatDriver", + "Rebootless" +}; + +inline const char* getBoolStr(bool isTrue) +{ + return isTrue? "TRUE" : "FALSE"; +} + +void CnmtProcess::displayCmnt() +{ +#define _SPLIT_VER(ver) ( (ver>>24) & 0xff), ( (ver>>16) & 0xff), ( (ver>>8) & 0xff), (ver & 0xff) + + printf("[ContentMeta]\n"); + printf(" TitleId: 0x%" PRIx64 "\n", mCnmt.getTitleId()); + uint32_t ver = mCnmt.getTitleVersion(); + printf(" Version: v%d.%d.%d-%d (v%" PRId32 ")\n", _SPLIT_VER(ver), ver); + printf(" Type: %s\n", getContentMetaTypeStr(mCnmt.getType()).c_str()); + printf(" Attributes: %x\n", mCnmt.getAttributes()); + printf(" IncludesExFatDriver: %s\n", getBoolStr(_HAS_BIT(mCnmt.getAttributes(), nx::cnmt::ATTRIBUTE_INCLUDES_EX_FAT_DRIVER))); + printf(" Rebootless: %s\n", getBoolStr(_HAS_BIT(mCnmt.getAttributes(), nx::cnmt::ATTRIBUTE_REBOOTLESS))); + ver = mCnmt.getRequiredDownloadSystemVersion(); + printf(" RequiredDownloadSystemVersion: v%d.%d.%d-%d (v%" PRId32 ")\n", _SPLIT_VER(ver), ver); + switch(mCnmt.getType()) + { + case (nx::cnmt::METATYPE_APPLICATION): + printf(" ApplicationExtendedHeader:\n"); + printf(" RequiredSystemVersion: %" PRId32 "\n", mCnmt.getApplicationMetaExtendedHeader().required_system_version); + printf(" PatchId: 0x%016" PRIx64 "\n", mCnmt.getApplicationMetaExtendedHeader().patch_id); + break; + case (nx::cnmt::METATYPE_PATCH): + printf(" PatchMetaExtendedHeader:\n"); + printf(" RequiredSystemVersion: %" PRId32 "\n", mCnmt.getPatchMetaExtendedHeader().required_system_version); + printf(" ApplicationId: 0x%016" PRIx64 "\n", mCnmt.getPatchMetaExtendedHeader().application_id); + break; + case (nx::cnmt::METATYPE_ADD_ON_CONTENT): + printf(" AddOnContentMetaExtendedHeader:\n"); + printf(" RequiredSystemVersion: %" PRId32 "\n", mCnmt.getAddOnContentMetaExtendedHeader().required_system_version); + printf(" ApplicationId: 0x%016" PRIx64 "\n", mCnmt.getAddOnContentMetaExtendedHeader().application_id); + break; + case (nx::cnmt::METATYPE_DELTA): + printf(" DeltaMetaExtendedHeader:\n"); + printf(" ApplicationId: 0x%016" PRIx64 "\n", mCnmt.getDeltaMetaExtendedHeader().application_id); + break; + default: + break; + } + if (mCnmt.getContentInfo().getSize() > 0) + { + printf(" ContentInfo:\n"); + for (size_t i = 0; i < mCnmt.getContentInfo().getSize(); i++) + { + const nx::ContentMetaBinary::ContentInfo& info = mCnmt.getContentInfo()[i]; + printf(" %d\n", i); + printf(" Type: %s\n", kContentTypeStr[info.type].c_str()); + printf(" Id: "); + fnd::SimpleTextOutput::hexDump(info.nca_id, nx::cnmt::kContentIdLen); + printf(" Size: 0x%" PRIx64 "\n", info.size); + printf(" Hash: "); + fnd::SimpleTextOutput::hexDump(info.hash.bytes, sizeof(info.hash)); + } + } + if (mCnmt.getContentMetaInfo().getSize() > 0) + { + printf(" ContentMetaInfo:\n"); + for (size_t i = 0; i < mCnmt.getContentMetaInfo().getSize(); i++) + { + const nx::ContentMetaBinary::ContentMetaInfo& info = mCnmt.getContentMetaInfo()[i]; + printf(" %d\n", i); + printf(" Id: 0x%" PRIx64 "\n", info.id); + ver = info.version; + printf(" Version: v%d.%d.%d-%d (v%" PRId32 ")\n", _SPLIT_VER(ver), ver); + printf(" Type: %s\n", getContentMetaTypeStr(info.type).c_str()); + printf(" Attributes: %x\n", mCnmt.getAttributes()); + printf(" IncludesExFatDriver: %s\n", getBoolStr(_HAS_BIT(mCnmt.getAttributes(), nx::cnmt::ATTRIBUTE_INCLUDES_EX_FAT_DRIVER))); + printf(" Rebootless: %s\n", getBoolStr(_HAS_BIT(mCnmt.getAttributes(), nx::cnmt::ATTRIBUTE_REBOOTLESS))); + } + } + printf(" Digest: "); + fnd::SimpleTextOutput::hexDump(mCnmt.getDigest().data, nx::cnmt::kDigestLen); + +#undef _SPLIT_VER +} + +CnmtProcess::CnmtProcess() : + mReader(nullptr), + mCliOutputType(OUTPUT_NORMAL), + mVerify(false) +{ +} + +CnmtProcess::~CnmtProcess() +{ + if (mReader != nullptr) + { + delete mReader; + } +} + +void CnmtProcess::process() +{ + fnd::MemoryBlob scratch; + + if (mReader == nullptr) + { + throw fnd::Exception(kModuleName, "No file reader set."); + } + + scratch.alloc(mReader->size()); + mReader->read(scratch.getBytes(), 0, scratch.getSize()); + + mCnmt.importBinary(scratch.getBytes(), scratch.getSize()); + + if (mCliOutputType >= OUTPUT_NORMAL) + { + displayCmnt(); + } +} + +void CnmtProcess::setInputFile(fnd::IFile* file, size_t offset, size_t size) +{ + mReader = new OffsetAdjustedIFile(file, offset, size); +} + +void CnmtProcess::setCliOutputMode(CliOutputType type) +{ + mCliOutputType = type; +} + +void CnmtProcess::setVerifyMode(bool verify) +{ + mVerify = verify; +} + +const nx::ContentMetaBinary& CnmtProcess::getContentMetaBinary() const +{ + return mCnmt; +} diff --git a/programs/nstool/source/CnmtProcess.h b/programs/nstool/source/CnmtProcess.h new file mode 100644 index 0000000..4e57947 --- /dev/null +++ b/programs/nstool/source/CnmtProcess.h @@ -0,0 +1,33 @@ +#pragma once +#include +#include +#include +#include + +#include "nstool.h" + +class CnmtProcess +{ +public: + CnmtProcess(); + ~CnmtProcess(); + + void process(); + + void setInputFile(fnd::IFile* file, size_t offset, size_t size); + void setCliOutputMode(CliOutputType type); + void setVerifyMode(bool verify); + + const nx::ContentMetaBinary& getContentMetaBinary() const; + +private: + const std::string kModuleName = "CnmtProcess"; + + fnd::IFile* mReader; + CliOutputType mCliOutputType; + bool mVerify; + + nx::ContentMetaBinary mCnmt; + + void displayCmnt(); +}; \ No newline at end of file diff --git a/programs/nstool/source/NcaProcess.cpp b/programs/nstool/source/NcaProcess.cpp index 97d0d4d..eb1a8a3 100644 --- a/programs/nstool/source/NcaProcess.cpp +++ b/programs/nstool/source/NcaProcess.cpp @@ -2,10 +2,10 @@ #include #include #include -#include #include "NcaProcess.h" #include "PfsProcess.h" #include "RomfsProcess.h" +#include "NpdmProcess.h" #include "OffsetAdjustedIFile.h" #include "AesCtrWrappedIFile.h" #include "CopiedIFile.h" @@ -199,10 +199,11 @@ void NcaProcess::generatePartitionConfiguration() throw fnd::Exception(kModuleName, error.str()); } - // determine the data offset + // determine the data offset & size if (mPartitions[partition.index].hash_type == nx::nca::HASH_HIERARCHICAL_SHA256) { mPartitions[partition.index].data_offset = mPartitions[partition.index].hierarchicalsha256_header.hash_target.offset.get(); + mPartitions[partition.index].data_size = mPartitions[partition.index].hierarchicalsha256_header.hash_target.size.get(); } else if (mPartitions[partition.index].hash_type == nx::nca::HASH_HIERARCHICAL_INTERGRITY) { @@ -211,6 +212,7 @@ void NcaProcess::generatePartitionConfiguration() if (mPartitions[partition.index].ivfc_header.level_header[nx::ivfc::kMaxIvfcLevel-1-j].logical_offset.get() != 0) { mPartitions[partition.index].data_offset = mPartitions[partition.index].ivfc_header.level_header[nx::ivfc::kMaxIvfcLevel-1-j].logical_offset.get(); + mPartitions[partition.index].data_size = mPartitions[partition.index].ivfc_header.level_header[nx::ivfc::kMaxIvfcLevel-1-j].hash_data_size.get(); break; } } @@ -245,25 +247,21 @@ void NcaProcess::validateNcaSignatures() if (mPartitions[0].reader != nullptr) { PfsProcess exefs; - exefs.setInputFile(mPartitions[0].reader); - exefs.setInputFileOffset(mPartitions[0].offset + mPartitions[0].data_offset); + exefs.setInputFile(mPartitions[0].reader, mPartitions[0].offset + mPartitions[0].data_offset, mPartitions[0].data_size); exefs.setCliOutputMode(OUTPUT_MINIMAL); exefs.process(); // open main.npdm if (exefs.getPfsHeader().getFileList().hasElement(kNpdmExefsPath) == true) { - const nx::PfsHeader::sFile& npdmFile = exefs.getPfsHeader().getFileList()[exefs.getPfsHeader().getFileList().getIndexOf(kNpdmExefsPath)]; + const nx::PfsHeader::sFile& file = exefs.getPfsHeader().getFileList()[exefs.getPfsHeader().getFileList().getIndexOf(kNpdmExefsPath)]; - fnd::MemoryBlob scratch; - scratch.alloc(npdmFile.size); - mPartitions[0].reader->read(scratch.getBytes(), mPartitions[0].offset + mPartitions[0].data_offset + npdmFile.offset, npdmFile.size); + NpdmProcess npdm; + npdm.setInputFile(mPartitions[0].reader, mPartitions[0].offset + mPartitions[0].data_offset + file.offset, file.size); + npdm.setCliOutputMode(OUTPUT_MINIMAL); + npdm.process(); - nx::NpdmBinary npdmBinary; - - npdmBinary.importBinary(scratch.getBytes(), scratch.getSize()); - - if (crypto::rsa::pss::rsaVerify(npdmBinary.getAcid().getNcaHeader2RsaKey(), crypto::sha::HASH_SHA256, mHdrHash.bytes, mHdrBlock.signature_acid) != 0) + 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) @@ -429,8 +427,7 @@ void NcaProcess::processPartitions() if (partition.format_type == nx::nca::FORMAT_PFS0) { PfsProcess pfs; - pfs.setInputFile(partition.reader); - pfs.setInputFileOffset(partition.offset + partition.data_offset); + pfs.setInputFile(partition.reader, partition.offset + partition.data_offset, partition.data_size); pfs.setCliOutputMode(mCliOutputType); pfs.setListFs(mListFs); if (mPartitionPath[index].doExtract) @@ -442,8 +439,7 @@ void NcaProcess::processPartitions() else if (partition.format_type == nx::nca::FORMAT_ROMFS) { RomfsProcess romfs; - romfs.setInputFile(partition.reader); - romfs.setInputFileOffset(partition.offset + partition.data_offset); + romfs.setInputFile(partition.reader, partition.offset + partition.data_offset, partition.data_size); romfs.setCliOutputMode(mCliOutputType); romfs.setListFs(mListFs); if (mPartitionPath[index].doExtract) @@ -457,7 +453,6 @@ void NcaProcess::processPartitions() NcaProcess::NcaProcess() : mReader(nullptr), - mOffset(0), mKeyset(nullptr), mCliOutputType(OUTPUT_NORMAL), mVerify(false), @@ -472,6 +467,11 @@ NcaProcess::NcaProcess() : NcaProcess::~NcaProcess() { + if (mReader != nullptr) + { + delete mReader; + } + for (size_t i = 0; i < nx::nca::kPartitionNum; i++) { if (mPartitions[i].reader != nullptr) @@ -491,7 +491,7 @@ void NcaProcess::process() } // read header block - mReader->read((byte_t*)&mHdrBlock, mOffset, sizeof(nx::sNcaHeaderBlock)); + mReader->read((byte_t*)&mHdrBlock, 0, sizeof(nx::sNcaHeaderBlock)); // decrypt header block nx::NcaUtils::decryptNcaHeader((byte_t*)&mHdrBlock, (byte_t*)&mHdrBlock, mKeyset->nca.header_key); @@ -539,22 +539,11 @@ void NcaProcess::process() so the verification text can be presented without interuption */ - - - // decrypt key area - - - } -void NcaProcess::setInputFile(fnd::IFile* reader) +void NcaProcess::setInputFile(fnd::IFile* file, size_t offset, size_t size) { - mReader = reader; -} - -void NcaProcess::setInputFileOffset(size_t offset) -{ - mOffset = offset; + mReader = new OffsetAdjustedIFile(file, offset, size); } void NcaProcess::setKeyset(const sKeyset* keyset) diff --git a/programs/nstool/source/NcaProcess.h b/programs/nstool/source/NcaProcess.h index c5dced0..1505d77 100644 --- a/programs/nstool/source/NcaProcess.h +++ b/programs/nstool/source/NcaProcess.h @@ -15,8 +15,7 @@ public: void process(); // generic - void setInputFile(fnd::IFile* reader); - void setInputFileOffset(size_t offset); + void setInputFile(fnd::IFile* file, size_t offset, size_t size); void setKeyset(const sKeyset* keyset); void setCliOutputMode(CliOutputType type); void setVerifyMode(bool verify); @@ -34,7 +33,6 @@ private: // user options fnd::IFile* mReader; - size_t mOffset; const sKeyset* mKeyset; CliOutputType mCliOutputType; bool mVerify; @@ -63,8 +61,9 @@ private: { fnd::IFile* reader; size_t offset; - size_t data_offset; size_t size; + size_t data_offset; + size_t data_size; nx::nca::FormatType format_type; nx::nca::HashType hash_type; diff --git a/programs/nstool/source/NpdmProcess.cpp b/programs/nstool/source/NpdmProcess.cpp index aeac024..5c3c5d7 100644 --- a/programs/nstool/source/NpdmProcess.cpp +++ b/programs/nstool/source/NpdmProcess.cpp @@ -1,6 +1,5 @@ +#include "OffsetAdjustedIFile.h" #include "NpdmProcess.h" -#include -#include const std::string kInstructionType[2] = { "32Bit", "64Bit" }; const std::string kProcAddrSpace[4] = { "Unknown", "64Bit", "32Bit", "32Bit no reserved" }; @@ -619,13 +618,20 @@ void NpdmProcess::displayKernelCap(const nx::KcBinary& kern) NpdmProcess::NpdmProcess() : mReader(nullptr), - mOffset(0), mKeyset(nullptr), mCliOutputType(OUTPUT_NORMAL), mVerify(false) { } +NpdmProcess::~NpdmProcess() +{ + if (mReader != nullptr) + { + delete mReader; + } +} + void NpdmProcess::process() { fnd::MemoryBlob scratch; @@ -665,14 +671,9 @@ void NpdmProcess::process() } } -void NpdmProcess::setInputFile(fnd::IFile* reader) +void NpdmProcess::setInputFile(fnd::IFile* file, size_t offset, size_t size) { - mReader = reader; -} - -void NpdmProcess::setInputFileOffset(size_t offset) -{ - mOffset = offset; + mReader = new OffsetAdjustedIFile(file, offset, size); } void NpdmProcess::setKeyset(const sKeyset* keyset) @@ -688,4 +689,9 @@ void NpdmProcess::setCliOutputMode(CliOutputType type) void NpdmProcess::setVerifyMode(bool verify) { mVerify = verify; +} + +const nx::NpdmBinary& NpdmProcess::getNpdmBinary() const +{ + return mNpdm; } \ No newline at end of file diff --git a/programs/nstool/source/NpdmProcess.h b/programs/nstool/source/NpdmProcess.h index ece7623..e14cbd0 100644 --- a/programs/nstool/source/NpdmProcess.h +++ b/programs/nstool/source/NpdmProcess.h @@ -10,20 +10,21 @@ class NpdmProcess { public: NpdmProcess(); + ~NpdmProcess(); void process(); - void setInputFile(fnd::IFile* reader); - void setInputFileOffset(size_t offset); + void setInputFile(fnd::IFile* file, size_t offset, size_t size); void setKeyset(const sKeyset* keyset); void setCliOutputMode(CliOutputType type); void setVerifyMode(bool verify); + const nx::NpdmBinary& getNpdmBinary() const; + private: const std::string kModuleName = "NpdmProcess"; fnd::IFile* mReader; - size_t mOffset; const sKeyset* mKeyset; CliOutputType mCliOutputType; bool mVerify; diff --git a/programs/nstool/source/OffsetAdjustedIFile.cpp b/programs/nstool/source/OffsetAdjustedIFile.cpp index bda80d6..e9f7231 100644 --- a/programs/nstool/source/OffsetAdjustedIFile.cpp +++ b/programs/nstool/source/OffsetAdjustedIFile.cpp @@ -16,7 +16,7 @@ size_t OffsetAdjustedIFile::size() void OffsetAdjustedIFile::seek(size_t offset) { - mCurrentOffset = offset; + mCurrentOffset = MIN(offset, mSize); mFile->seek(offset + mBaseOffset); } diff --git a/programs/nstool/source/PfsProcess.cpp b/programs/nstool/source/PfsProcess.cpp index 452f38a..b108c2c 100644 --- a/programs/nstool/source/PfsProcess.cpp +++ b/programs/nstool/source/PfsProcess.cpp @@ -1,6 +1,7 @@ -#include "PfsProcess.h" #include #include +#include "OffsetAdjustedIFile.h" +#include "PfsProcess.h" void PfsProcess::displayHeader() { @@ -55,7 +56,7 @@ void PfsProcess::validateHfs() for (size_t i = 0; i < file.getSize(); i++) { scratch.alloc(file[i].hash_protected_size); - mReader->read(scratch.getBytes(), mOffset + file[i].offset, file[i].hash_protected_size); + mReader->read(scratch.getBytes(), file[i].offset, file[i].hash_protected_size); crypto::sha::Sha256(scratch.getBytes(), scratch.getSize(), hash.bytes); if (hash != file[i].hash) { @@ -85,7 +86,7 @@ void PfsProcess::extractFs() fnd::io::appendToPath(file_path, mExtractPath); fnd::io::appendToPath(file_path, file[i].name); outFile.open(file_path, outFile.Create); - mReader->seek(mOffset + file[i].offset); + mReader->seek(file[i].offset); for (size_t j = 0; j < (file[i].size / kFileExportBlockSize); j++) { mReader->read(scratch.getBytes(), kFileExportBlockSize); @@ -102,8 +103,6 @@ void PfsProcess::extractFs() PfsProcess::PfsProcess() : mReader(nullptr), - mOffset(0), - mKeyset(nullptr), mCliOutputType(OUTPUT_NORMAL), mVerify(false), mExtractPath(), @@ -112,7 +111,14 @@ PfsProcess::PfsProcess() : mListFs(false), mPfs() { +} +PfsProcess::~PfsProcess() +{ + if (mReader != nullptr) + { + delete mReader; + } } void PfsProcess::process() @@ -126,7 +132,7 @@ void PfsProcess::process() // open minimum header to get full header size scratch.alloc(sizeof(nx::sPfsHeader)); - mReader->read(scratch.getBytes(), mOffset, scratch.getSize()); + mReader->read(scratch.getBytes(), 0, scratch.getSize()); if (validateHeaderMagic(((nx::sPfsHeader*)scratch.getBytes())) == false) { throw fnd::Exception(kModuleName, "Corrupt Header"); @@ -135,7 +141,7 @@ void PfsProcess::process() // open minimum header to get full header size scratch.alloc(pfsHeaderSize); - mReader->read(scratch.getBytes(), mOffset, scratch.getSize()); + mReader->read(scratch.getBytes(), 0, scratch.getSize()); mPfs.importBinary(scratch.getBytes(), scratch.getSize()); if (mCliOutputType >= OUTPUT_NORMAL) @@ -148,19 +154,9 @@ void PfsProcess::process() extractFs(); } -void PfsProcess::setInputFile(fnd::IFile* reader) +void PfsProcess::setInputFile(fnd::IFile* file, size_t offset, size_t size) { - mReader = reader; -} - -void PfsProcess::setInputFileOffset(size_t offset) -{ - mOffset = offset; -} - -void PfsProcess::setKeyset(const sKeyset* keyset) -{ - mKeyset = keyset; + mReader = new OffsetAdjustedIFile(file, offset, size); } void PfsProcess::setCliOutputMode(CliOutputType type) diff --git a/programs/nstool/source/PfsProcess.h b/programs/nstool/source/PfsProcess.h index 7137775..e099ef4 100644 --- a/programs/nstool/source/PfsProcess.h +++ b/programs/nstool/source/PfsProcess.h @@ -10,13 +10,12 @@ class PfsProcess { public: PfsProcess(); + ~PfsProcess(); void process(); // generic - void setInputFile(fnd::IFile* reader); - void setInputFileOffset(size_t offset); - void setKeyset(const sKeyset* keyset); + void setInputFile(fnd::IFile* file, size_t offset, size_t size); void setCliOutputMode(CliOutputType type); void setVerifyMode(bool verify); @@ -32,8 +31,6 @@ private: static const size_t kFileExportBlockSize = 0x1000000; fnd::IFile* mReader; - size_t mOffset; - const sKeyset* mKeyset; CliOutputType mCliOutputType; bool mVerify; diff --git a/programs/nstool/source/RomfsProcess.cpp b/programs/nstool/source/RomfsProcess.cpp index 95aa7c5..1a0f8a3 100644 --- a/programs/nstool/source/RomfsProcess.cpp +++ b/programs/nstool/source/RomfsProcess.cpp @@ -1,7 +1,8 @@ -#include "RomfsProcess.h" #include #include #include +#include "OffsetAdjustedIFile.h" +#include "RomfsProcess.h" void RomfsProcess::printTab(size_t tab) const { @@ -87,7 +88,7 @@ void RomfsProcess::extractDir(const std::string& path, const sDirectory& dir) outFile.open(file_path, outFile.Create); - mReader->seek(mOffset + dir.file_list[i].offset); + mReader->seek(dir.file_list[i].offset); for (size_t j = 0; j < (dir.file_list[i].size / kFileExportBlockSize); j++) { mReader->read(scratch.getBytes(), kFileExportBlockSize); @@ -186,7 +187,7 @@ void RomfsProcess::importDirectory(uint32_t dir_offset, sDirectory& dir) void RomfsProcess::resolveRomfs() { // read header - mReader->read((byte_t*)&mHdr, mOffset, sizeof(nx::sRomfsHeader)); + mReader->read((byte_t*)&mHdr, 0, sizeof(nx::sRomfsHeader)); // logic check on the header layout if (validateHeaderLayout(&mHdr) == false) @@ -196,13 +197,13 @@ void RomfsProcess::resolveRomfs() // read directory nodes mDirNodes.alloc(mHdr.sections[nx::romfs::DIR_NODE_TABLE].size.get()); - mReader->read(mDirNodes.getBytes(), mOffset + mHdr.sections[nx::romfs::DIR_NODE_TABLE].offset.get(), mDirNodes.getSize()); + mReader->read(mDirNodes.getBytes(), mHdr.sections[nx::romfs::DIR_NODE_TABLE].offset.get(), mDirNodes.getSize()); //printf("[RAW DIR NODES]\n"); //fnd::SimpleTextOutput::hxdStyleDump(mDirNodes.getBytes(), mDirNodes.getSize()); // read file nodes mFileNodes.alloc(mHdr.sections[nx::romfs::FILE_NODE_TABLE].size.get()); - mReader->read(mFileNodes.getBytes(), mOffset + mHdr.sections[nx::romfs::FILE_NODE_TABLE].offset.get(), mFileNodes.getSize()); + mReader->read(mFileNodes.getBytes(), mHdr.sections[nx::romfs::FILE_NODE_TABLE].offset.get(), mFileNodes.getSize()); //printf("[RAW FILE NODES]\n"); //fnd::SimpleTextOutput::hxdStyleDump(mFileNodes.getBytes(), mFileNodes.getSize()); @@ -223,8 +224,6 @@ void RomfsProcess::resolveRomfs() RomfsProcess::RomfsProcess() : mReader(nullptr), - mOffset(0), - mKeyset(nullptr), mCliOutputType(OUTPUT_NORMAL), mVerify(false), mExtractPath(), @@ -239,6 +238,14 @@ RomfsProcess::RomfsProcess() : mRootDir.file_list.clear(); } +RomfsProcess::~RomfsProcess() +{ + if (mReader != nullptr) + { + delete mReader; + } +} + void RomfsProcess::process() { if (mReader == nullptr) @@ -256,19 +263,9 @@ void RomfsProcess::process() extractFs(); } -void RomfsProcess::setInputFile(fnd::IFile* reader) +void RomfsProcess::setInputFile(fnd::IFile* file, size_t offset, size_t size) { - mReader = reader; -} - -void RomfsProcess::setInputFileOffset(size_t offset) -{ - mOffset = offset; -} - -void RomfsProcess::setKeyset(const sKeyset* keyset) -{ - mKeyset = keyset; + mReader = new OffsetAdjustedIFile(file, offset, size); } void RomfsProcess::setCliOutputMode(CliOutputType type) diff --git a/programs/nstool/source/RomfsProcess.h b/programs/nstool/source/RomfsProcess.h index ee3ecc1..89d9702 100644 --- a/programs/nstool/source/RomfsProcess.h +++ b/programs/nstool/source/RomfsProcess.h @@ -89,13 +89,12 @@ public: }; RomfsProcess(); + ~RomfsProcess(); void process(); // generic - void setInputFile(fnd::IFile* reader); - void setInputFileOffset(size_t offset); - void setKeyset(const sKeyset* keyset); + void setInputFile(fnd::IFile* file, size_t offset, size_t size); void setCliOutputMode(CliOutputType type); void setVerifyMode(bool verify); @@ -110,8 +109,6 @@ private: static const size_t kFileExportBlockSize = 0x1000000; fnd::IFile* mReader; - size_t mOffset; - const sKeyset* mKeyset; CliOutputType mCliOutputType; bool mVerify; diff --git a/programs/nstool/source/UserSettings.cpp b/programs/nstool/source/UserSettings.cpp index b71f551..86d57ee 100644 --- a/programs/nstool/source/UserSettings.cpp +++ b/programs/nstool/source/UserSettings.cpp @@ -38,7 +38,7 @@ void UserSettings::showHelp() printf("\n General Options:\n"); printf(" -d, --dev Use devkit keyset\n"); printf(" -k, --keyset Specify keyset file\n"); - printf(" -t, --type Specify input file type [xci, pfs, romfs, nca, npdm, cmnt]\n"); + printf(" -t, --type Specify input file type [xci, pfs, romfs, nca, npdm, cnmt]\n"); printf(" -y, --verify Verify file\n"); printf(" -v, --verbose Verbose output\n"); printf(" -q, --quiet Minimal output\n"); @@ -576,8 +576,8 @@ FileType UserSettings::getFileTypeFromString(const std::string& type_str) type = FILE_NCA; else if (str == "npdm") type = FILE_NPDM; - else if (str == "cmnt") - type = FILE_CMNT; + else if (str == "cnmt") + type = FILE_CNMT; else type = FILE_INVALID; diff --git a/programs/nstool/source/XciProcess.cpp b/programs/nstool/source/XciProcess.cpp index 54ffdbf..c9417a2 100644 --- a/programs/nstool/source/XciProcess.cpp +++ b/programs/nstool/source/XciProcess.cpp @@ -1,6 +1,7 @@ -#include "XciProcess.h" #include #include +#include "OffsetAdjustedIFile.h" +#include "XciProcess.h" inline const char* getBoolStr(bool isTrue) { @@ -136,13 +137,12 @@ void XciProcess::processRootPfs() { if (mVerify) { - if (validateRegionOfFile(mOffset + mHdr.getPartitionFsAddress(), mHdr.getPartitionFsSize(), mHdr.getPartitionFsHash().bytes) == false) + if (validateRegionOfFile(mHdr.getPartitionFsAddress(), mHdr.getPartitionFsSize(), mHdr.getPartitionFsHash().bytes) == false) { printf("[WARNING] XCI Root HFS0: FAIL (bad hash)\n"); } } - mRootPfs.setInputFile(mReader); - mRootPfs.setInputFileOffset(mOffset + mHdr.getPartitionFsAddress()); + mRootPfs.setInputFile(mReader, mHdr.getPartitionFsAddress(), mHdr.getPartitionFsSize()); mRootPfs.setListFs(mListFs); mRootPfs.setVerifyMode(mVerify); mRootPfs.setCliOutputMode(mCliOutputType); @@ -156,8 +156,7 @@ void XciProcess::processPartitionPfs() for (size_t i = 0; i < rootPartitions.getSize(); i++) { PfsProcess tmp; - tmp.setInputFile(mReader); - tmp.setInputFileOffset(mOffset + mHdr.getPartitionFsAddress() + rootPartitions[i].offset); + tmp.setInputFile(mReader, mHdr.getPartitionFsAddress() + rootPartitions[i].offset, rootPartitions[i].size); tmp.setListFs(mListFs); tmp.setVerifyMode(mVerify); tmp.setCliOutputMode(mCliOutputType); @@ -174,7 +173,6 @@ void XciProcess::processPartitionPfs() XciProcess::XciProcess() : mReader(nullptr), - mOffset(0), mKeyset(nullptr), mCliOutputType(OUTPUT_NORMAL), mVerify(false), @@ -189,6 +187,14 @@ XciProcess::XciProcess() : mSecurePath.doExtract = false; } +XciProcess::~XciProcess() +{ + if (mReader != nullptr) + { + delete mReader; + } +} + void XciProcess::process() { fnd::MemoryBlob scratch; @@ -199,7 +205,7 @@ void XciProcess::process() } // read header page - mReader->read((byte_t*)&mHdrPage, mOffset, sizeof(nx::sXciHeaderPage)); + mReader->read((byte_t*)&mHdrPage, 0, sizeof(nx::sXciHeaderPage)); // allocate memory for and decrypt sXciHeader scratch.alloc(sizeof(nx::sXciHeader)); @@ -227,14 +233,9 @@ void XciProcess::process() processPartitionPfs(); } -void XciProcess::setInputFile(fnd::IFile* reader) +void XciProcess::setInputFile(fnd::IFile* file, size_t offset, size_t size) { - mReader = reader; -} - -void XciProcess::setInputFileOffset(size_t offset) -{ - mOffset = offset; + mReader = new OffsetAdjustedIFile(file, offset, size); } void XciProcess::setKeyset(const sKeyset* keyset) diff --git a/programs/nstool/source/XciProcess.h b/programs/nstool/source/XciProcess.h index d0b7061..3f6acd3 100644 --- a/programs/nstool/source/XciProcess.h +++ b/programs/nstool/source/XciProcess.h @@ -13,12 +13,12 @@ class XciProcess { public: XciProcess(); + ~XciProcess(); void process(); // generic - void setInputFile(fnd::IFile* reader); - void setInputFileOffset(size_t offset); + void setInputFile(fnd::IFile* file, size_t offset, size_t size); void setKeyset(const sKeyset* keyset); void setCliOutputMode(CliOutputType type); void setVerifyMode(bool verify); @@ -35,7 +35,6 @@ private: static const size_t kFileExportBlockSize = 0x1000000; fnd::IFile* mReader; - size_t mOffset; const sKeyset* mKeyset; CliOutputType mCliOutputType; bool mVerify; diff --git a/programs/nstool/source/main.cpp b/programs/nstool/source/main.cpp index 8907c39..89afa70 100644 --- a/programs/nstool/source/main.cpp +++ b/programs/nstool/source/main.cpp @@ -6,6 +6,7 @@ #include "RomfsProcess.h" #include "NcaProcess.h" #include "NpdmProcess.h" +#include "CnmtProcess.h" int main(int argc, char** argv) @@ -21,7 +22,7 @@ int main(int argc, char** argv) { XciProcess xci; - xci.setInputFile(&inputFile); + xci.setInputFile(&inputFile, 0, inputFile.size()); xci.setKeyset(&user_set.getKeyset()); xci.setCliOutputMode(user_set.getCliOutputType()); @@ -41,8 +42,7 @@ int main(int argc, char** argv) { PfsProcess pfs; - pfs.setInputFile(&inputFile); - pfs.setKeyset(&user_set.getKeyset()); + pfs.setInputFile(&inputFile, 0, inputFile.size()); pfs.setCliOutputMode(user_set.getCliOutputType()); pfs.setVerifyMode(user_set.isVerifyFile()); @@ -56,8 +56,7 @@ int main(int argc, char** argv) { RomfsProcess romfs; - romfs.setInputFile(&inputFile); - romfs.setKeyset(&user_set.getKeyset()); + romfs.setInputFile(&inputFile, 0, inputFile.size()); romfs.setCliOutputMode(user_set.getCliOutputType()); romfs.setVerifyMode(user_set.isVerifyFile()); @@ -71,7 +70,7 @@ int main(int argc, char** argv) { NcaProcess nca; - nca.setInputFile(&inputFile); + nca.setInputFile(&inputFile, 0, inputFile.size()); nca.setKeyset(&user_set.getKeyset()); nca.setCliOutputMode(user_set.getCliOutputType()); nca.setVerifyMode(user_set.isVerifyFile()); @@ -93,13 +92,23 @@ int main(int argc, char** argv) { NpdmProcess npdm; - npdm.setInputFile(&inputFile); + npdm.setInputFile(&inputFile, 0, inputFile.size()); npdm.setKeyset(&user_set.getKeyset()); npdm.setCliOutputMode(user_set.getCliOutputType()); npdm.setVerifyMode(user_set.isVerifyFile()); npdm.process(); } + else if (user_set.getFileType() == FILE_CNMT) + { + CnmtProcess cnmt; + + cnmt.setInputFile(&inputFile, 0, inputFile.size()); + cnmt.setCliOutputMode(user_set.getCliOutputType()); + cnmt.setVerifyMode(user_set.isVerifyFile()); + + cnmt.process(); + } } catch (const fnd::Exception& e) { printf("\n\n%s\n", e.what()); diff --git a/programs/nstool/source/nstool.h b/programs/nstool/source/nstool.h index 99827fb..54686d2 100644 --- a/programs/nstool/source/nstool.h +++ b/programs/nstool/source/nstool.h @@ -17,7 +17,7 @@ enum FileType FILE_ROMFS, FILE_NCA, FILE_NPDM, - FILE_CMNT, + FILE_CNMT, FILE_INVALID = -1, };