[nx|nstool] Added support for reading ContentMeta (.cnmt).

This commit is contained in:
jakcron 2018-05-12 23:02:53 +08:00
parent b36875661e
commit 79c24153bb
21 changed files with 589 additions and 190 deletions

View file

@ -2,7 +2,7 @@
#include <string>
#include <fnd/MemoryBlob.h>
#include <fnd/List.h>
#include <nx/cmnt.h>
#include <nx/cnmt.h>
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<nx::ContentMetaBinary::ContentInfo>& getContentInfo() const;
void setContentInfo(const fnd::List<nx::ContentMetaBinary::ContentInfo>& 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<nx::ContentMetaBinary::ContentInfo> mContentInfo;
fnd::List<nx::ContentMetaBinary::ContentMetaInfo> 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);

View file

@ -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)
}

View file

@ -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::ContentInfo>& 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);
}
}

View file

@ -1 +0,0 @@
#include "CmntProcess.h"

View file

@ -1 +0,0 @@
#pragma once

View file

@ -0,0 +1,185 @@
#include <fnd/SimpleTextOutput.h>
#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;
}

View file

@ -0,0 +1,33 @@
#pragma once
#include <string>
#include <fnd/types.h>
#include <fnd/IFile.h>
#include <nx/ContentMetaBinary.h>
#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();
};

View file

@ -2,10 +2,10 @@
#include <fnd/SimpleTextOutput.h>
#include <nx/NcaUtils.h>
#include <nx/AesKeygen.h>
#include <nx/NpdmBinary.h>
#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)

View file

@ -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;

View file

@ -1,6 +1,5 @@
#include "OffsetAdjustedIFile.h"
#include "NpdmProcess.h"
#include <fnd/SimpleFile.h>
#include <fnd/MemoryBlob.h>
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;
}

View file

@ -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;

View file

@ -16,7 +16,7 @@ size_t OffsetAdjustedIFile::size()
void OffsetAdjustedIFile::seek(size_t offset)
{
mCurrentOffset = offset;
mCurrentOffset = MIN(offset, mSize);
mFile->seek(offset + mBaseOffset);
}

View file

@ -1,6 +1,7 @@
#include "PfsProcess.h"
#include <fnd/SimpleFile.h>
#include <fnd/io.h>
#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)

View file

@ -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;

View file

@ -1,7 +1,8 @@
#include "RomfsProcess.h"
#include <fnd/SimpleTextOutput.h>
#include <fnd/SimpleFile.h>
#include <fnd/io.h>
#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)

View file

@ -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;

View file

@ -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;

View file

@ -1,6 +1,7 @@
#include "XciProcess.h"
#include <fnd/SimpleTextOutput.h>
#include <nx/XciUtils.h>
#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)

View file

@ -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;

View file

@ -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());

View file

@ -17,7 +17,7 @@ enum FileType
FILE_ROMFS,
FILE_NCA,
FILE_NPDM,
FILE_CMNT,
FILE_CNMT,
FILE_INVALID = -1,
};