mirror of
https://github.com/jakcron/nstool
synced 2024-11-15 02:06:40 +00:00
[nx|nstool] Added support for reading ContentMeta (.cnmt).
This commit is contained in:
parent
b36875661e
commit
79c24153bb
21 changed files with 589 additions and 190 deletions
|
@ -2,7 +2,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <fnd/MemoryBlob.h>
|
#include <fnd/MemoryBlob.h>
|
||||||
#include <fnd/List.h>
|
#include <fnd/List.h>
|
||||||
#include <nx/cmnt.h>
|
#include <nx/cnmt.h>
|
||||||
|
|
||||||
|
|
||||||
namespace nx
|
namespace nx
|
||||||
|
@ -14,14 +14,14 @@ namespace nx
|
||||||
struct ContentInfo
|
struct ContentInfo
|
||||||
{
|
{
|
||||||
crypto::sha::sSha256Hash hash;
|
crypto::sha::sSha256Hash hash;
|
||||||
byte_t nca_id[cmnt::kContentIdLen];
|
byte_t nca_id[cnmt::kContentIdLen];
|
||||||
size_t size;
|
size_t size;
|
||||||
cmnt::ContentType type;
|
cnmt::ContentType type;
|
||||||
|
|
||||||
ContentInfo& operator=(const ContentInfo& other)
|
ContentInfo& operator=(const ContentInfo& other)
|
||||||
{
|
{
|
||||||
hash = other.hash;
|
hash = other.hash;
|
||||||
memcpy(nca_id, other.nca_id, cmnt::kContentIdLen);
|
memcpy(nca_id, other.nca_id, cnmt::kContentIdLen);
|
||||||
size = other.size;
|
size = other.size;
|
||||||
type = other.type;
|
type = other.type;
|
||||||
return *this;
|
return *this;
|
||||||
|
@ -30,7 +30,7 @@ namespace nx
|
||||||
bool operator==(const ContentInfo& other) const
|
bool operator==(const ContentInfo& other) const
|
||||||
{
|
{
|
||||||
return (hash == other.hash) \
|
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) \
|
&& (size == other.size) \
|
||||||
&& (type == other.type);
|
&& (type == other.type);
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,7 @@ namespace nx
|
||||||
{
|
{
|
||||||
uint64_t id;
|
uint64_t id;
|
||||||
uint32_t version;
|
uint32_t version;
|
||||||
cmnt::ContentMetaType type;
|
cnmt::ContentMetaType type;
|
||||||
byte_t attributes;
|
byte_t attributes;
|
||||||
|
|
||||||
ContentMetaInfo& operator=(const ContentMetaInfo& other)
|
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();
|
||||||
ContentMetaBinary(const ContentMetaBinary& other);
|
ContentMetaBinary(const ContentMetaBinary& other);
|
||||||
ContentMetaBinary(const byte_t* bytes, size_t len);
|
ContentMetaBinary(const byte_t* bytes, size_t len);
|
||||||
|
@ -92,14 +185,26 @@ namespace nx
|
||||||
uint32_t getTitleVersion() const;
|
uint32_t getTitleVersion() const;
|
||||||
void setTitleVersion(uint32_t version);
|
void setTitleVersion(uint32_t version);
|
||||||
|
|
||||||
cmnt::ContentMetaType getType() const;
|
cnmt::ContentMetaType getType() const;
|
||||||
void setType(cmnt::ContentMetaType type);
|
void setType(cnmt::ContentMetaType type);
|
||||||
|
|
||||||
byte_t getAttributes() const;
|
byte_t getAttributes() const;
|
||||||
void setAttributes(byte_t attributes);
|
void setAttributes(byte_t attributes);
|
||||||
|
|
||||||
uint32_t getRequiredSystemVersion() const;
|
uint32_t getRequiredDownloadSystemVersion() const;
|
||||||
void setRequiredSystemVersion(uint32_t version);
|
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;
|
const fnd::List<nx::ContentMetaBinary::ContentInfo>& getContentInfo() const;
|
||||||
void setContentInfo(const fnd::List<nx::ContentMetaBinary::ContentInfo>& info);
|
void setContentInfo(const fnd::List<nx::ContentMetaBinary::ContentInfo>& info);
|
||||||
|
@ -123,10 +228,16 @@ namespace nx
|
||||||
// variables
|
// variables
|
||||||
uint64_t mTitleId;
|
uint64_t mTitleId;
|
||||||
uint32_t mTitleVersion;
|
uint32_t mTitleVersion;
|
||||||
cmnt::ContentMetaType mType;
|
cnmt::ContentMetaType mType;
|
||||||
byte_t mAttributes;
|
byte_t mAttributes;
|
||||||
uint32_t mRequiredSystemVersion;
|
uint32_t mRequiredDownloadSystemVersion;
|
||||||
fnd::MemoryBlob mExtendedHeader;
|
fnd::MemoryBlob mExtendedHeader;
|
||||||
|
|
||||||
|
ApplicationMetaExtendedHeader mApplicationMetaExtendedHeader;
|
||||||
|
PatchMetaExtendedHeader mPatchMetaExtendedHeader;
|
||||||
|
AddOnContentMetaExtendedHeader mAddOnContentMetaExtendedHeader;
|
||||||
|
DeltaMetaExtendedHeader mDeltaMetaExtendedHeader;
|
||||||
|
|
||||||
fnd::List<nx::ContentMetaBinary::ContentInfo> mContentInfo;
|
fnd::List<nx::ContentMetaBinary::ContentInfo> mContentInfo;
|
||||||
fnd::List<nx::ContentMetaBinary::ContentMetaInfo> mContentMetaInfo;
|
fnd::List<nx::ContentMetaBinary::ContentMetaInfo> mContentMetaInfo;
|
||||||
fnd::MemoryBlob mExtendedData;
|
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 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 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 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);
|
bool validateExtendedHeaderSize(cnmt::ContentMetaType type, size_t exhdrSize) const;
|
||||||
size_t getExtendedDataSize(cmnt::ContentMetaType type, const byte_t* data);
|
size_t getExtendedDataSize(cnmt::ContentMetaType type, const byte_t* data) const;
|
||||||
void validateBinary(const byte_t* bytes, size_t len);
|
void validateBinary(const byte_t* bytes, size_t len) const;
|
||||||
|
|
||||||
bool isEqual(const ContentMetaBinary& other) const;
|
bool isEqual(const ContentMetaBinary& other) const;
|
||||||
void copyFrom(const ContentMetaBinary& other);
|
void copyFrom(const ContentMetaBinary& other);
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
namespace nx
|
namespace nx
|
||||||
{
|
{
|
||||||
namespace cmnt
|
namespace cnmt
|
||||||
{
|
{
|
||||||
enum ContentType
|
enum ContentType
|
||||||
{
|
{
|
||||||
|
@ -43,7 +43,6 @@ namespace nx
|
||||||
|
|
||||||
enum ContentMetaAttribute
|
enum ContentMetaAttribute
|
||||||
{
|
{
|
||||||
ATTRIBUTE_NONE,
|
|
||||||
ATTRIBUTE_INCLUDES_EX_FAT_DRIVER,
|
ATTRIBUTE_INCLUDES_EX_FAT_DRIVER,
|
||||||
ATTRIBUTE_REBOOTLESS
|
ATTRIBUTE_REBOOTLESS
|
||||||
};
|
};
|
||||||
|
@ -79,14 +78,14 @@ namespace nx
|
||||||
le_uint16_t content_meta_count;
|
le_uint16_t content_meta_count;
|
||||||
byte_t attributes;
|
byte_t attributes;
|
||||||
byte_t reserved_1[3];
|
byte_t reserved_1[3];
|
||||||
le_uint32_t required_system_version;
|
le_uint32_t required_download_system_version;
|
||||||
byte_t reserved_2[4];
|
byte_t reserved_2[4];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sContentInfo
|
struct sContentInfo
|
||||||
{
|
{
|
||||||
crypto::sha::sSha256Hash content_hash;
|
crypto::sha::sSha256Hash content_hash;
|
||||||
byte_t content_id[cmnt::kContentIdLen];
|
byte_t content_id[cnmt::kContentIdLen];
|
||||||
le_uint32_t size_lower;
|
le_uint32_t size_lower;
|
||||||
le_uint16_t size_higher;
|
le_uint16_t size_higher;
|
||||||
byte_t content_type;
|
byte_t content_type;
|
||||||
|
@ -104,14 +103,14 @@ namespace nx
|
||||||
|
|
||||||
struct sApplicationMetaExtendedHeader
|
struct sApplicationMetaExtendedHeader
|
||||||
{
|
{
|
||||||
le_uint64_t id;
|
le_uint64_t patch_id;
|
||||||
le_uint32_t required_system_version;
|
le_uint32_t required_system_version;
|
||||||
byte_t reserved[4];
|
byte_t reserved[4];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sPatchMetaExtendedHeader
|
struct sPatchMetaExtendedHeader
|
||||||
{
|
{
|
||||||
le_uint64_t id;
|
le_uint64_t application_id;
|
||||||
le_uint32_t required_system_version;
|
le_uint32_t required_system_version;
|
||||||
le_uint32_t extended_data_size;
|
le_uint32_t extended_data_size;
|
||||||
byte_t reserved[8];
|
byte_t reserved[8];
|
||||||
|
@ -119,21 +118,21 @@ namespace nx
|
||||||
|
|
||||||
struct sAddOnContentMetaExtendedHeader
|
struct sAddOnContentMetaExtendedHeader
|
||||||
{
|
{
|
||||||
le_uint64_t id;
|
le_uint64_t application_id;
|
||||||
le_uint32_t required_system_version;
|
le_uint32_t required_system_version;
|
||||||
byte_t reserved[4];
|
byte_t reserved[4];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sDeltaMetaExtendedHeader
|
struct sDeltaMetaExtendedHeader
|
||||||
{
|
{
|
||||||
le_uint64_t id;
|
le_uint64_t application_id;
|
||||||
le_uint32_t extended_data_size;
|
le_uint32_t extended_data_size;
|
||||||
byte_t reserved[4];
|
byte_t reserved[4];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sDigest
|
struct sDigest
|
||||||
{
|
{
|
||||||
byte_t data[cmnt::kDigestLen];
|
byte_t data[cnmt::kDigestLen];
|
||||||
};
|
};
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
}
|
}
|
|
@ -43,9 +43,9 @@ void nx::ContentMetaBinary::importBinary(const byte_t * bytes, size_t len)
|
||||||
|
|
||||||
mTitleId = hdr->id.get();
|
mTitleId = hdr->id.get();
|
||||||
mTitleVersion = hdr->version.get();
|
mTitleVersion = hdr->version.get();
|
||||||
mType = (cmnt::ContentMetaType)hdr->type;
|
mType = (cnmt::ContentMetaType)hdr->type;
|
||||||
mAttributes = hdr->attributes;
|
mAttributes = hdr->attributes;
|
||||||
mRequiredSystemVersion = hdr->required_system_version.get();
|
mRequiredDownloadSystemVersion = hdr->required_download_system_version.get();
|
||||||
size_t exdata_size = 0;
|
size_t exdata_size = 0;
|
||||||
|
|
||||||
// save exheader
|
// save exheader
|
||||||
|
@ -54,6 +54,27 @@ void nx::ContentMetaBinary::importBinary(const byte_t * bytes, size_t len)
|
||||||
mExtendedHeader.alloc(hdr->exhdr_size.get());
|
mExtendedHeader.alloc(hdr->exhdr_size.get());
|
||||||
memcpy(mExtendedHeader.getBytes(), bytes + getExtendedHeaderOffset(), 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());
|
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++)
|
for (size_t i = 0; i < hdr->content_count.get(); i++)
|
||||||
{
|
{
|
||||||
mContentInfo[i].hash = info[i].content_hash;
|
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].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].id = info[i].id.get();
|
||||||
mContentMetaInfo[i].version = info[i].version.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;
|
mContentMetaInfo[i].attributes = info[i].attributes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -91,7 +112,7 @@ void nx::ContentMetaBinary::importBinary(const byte_t * bytes, size_t len)
|
||||||
}
|
}
|
||||||
|
|
||||||
// save digest
|
// 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();
|
mBinaryBlob.clear();
|
||||||
mTitleId = 0;
|
mTitleId = 0;
|
||||||
mTitleVersion = 0;
|
mTitleVersion = 0;
|
||||||
mType = cmnt::METATYPE_SYSTEM_PROGRAM;
|
mType = cnmt::METATYPE_SYSTEM_PROGRAM;
|
||||||
mAttributes = cmnt::ATTRIBUTE_NONE;
|
mAttributes = 0;
|
||||||
mRequiredSystemVersion = 0;
|
mRequiredDownloadSystemVersion = 0;
|
||||||
mExtendedHeader.clear();
|
mExtendedHeader.clear();
|
||||||
|
memset(&mApplicationMetaExtendedHeader, 0, sizeof(mApplicationMetaExtendedHeader));
|
||||||
|
memset(&mPatchMetaExtendedHeader, 0, sizeof(mPatchMetaExtendedHeader));
|
||||||
|
memset(&mAddOnContentMetaExtendedHeader, 0, sizeof(mAddOnContentMetaExtendedHeader));
|
||||||
|
memset(&mDeltaMetaExtendedHeader, 0, sizeof(mDeltaMetaExtendedHeader));
|
||||||
mContentInfo.clear();
|
mContentInfo.clear();
|
||||||
mContentMetaInfo.clear();
|
mContentMetaInfo.clear();
|
||||||
mExtendedData.clear();
|
mExtendedData.clear();
|
||||||
memset(mDigest.data, 0, cmnt::kDigestLen);
|
memset(mDigest.data, 0, cnmt::kDigestLen);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t nx::ContentMetaBinary::getTitleId() const
|
uint64_t nx::ContentMetaBinary::getTitleId() const
|
||||||
|
@ -130,12 +155,12 @@ void nx::ContentMetaBinary::setTitleVersion(uint32_t version)
|
||||||
mTitleVersion = version;
|
mTitleVersion = version;
|
||||||
}
|
}
|
||||||
|
|
||||||
nx::cmnt::ContentMetaType nx::ContentMetaBinary::getType() const
|
nx::cnmt::ContentMetaType nx::ContentMetaBinary::getType() const
|
||||||
{
|
{
|
||||||
return mType;
|
return mType;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nx::ContentMetaBinary::setType(cmnt::ContentMetaType type)
|
void nx::ContentMetaBinary::setType(cnmt::ContentMetaType type)
|
||||||
{
|
{
|
||||||
mType = type;
|
mType = type;
|
||||||
}
|
}
|
||||||
|
@ -150,14 +175,54 @@ void nx::ContentMetaBinary::setAttributes(byte_t attributes)
|
||||||
mAttributes = 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
|
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)
|
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;
|
bool validSize = false;
|
||||||
|
|
||||||
if (type == cmnt::METATYPE_APPLICATION && exhdrSize == sizeof(sApplicationMetaExtendedHeader))
|
switch (type)
|
||||||
validSize = true;
|
{
|
||||||
else if (type == cmnt::METATYPE_PATCH && exhdrSize == sizeof(sPatchMetaExtendedHeader))
|
case (cnmt::METATYPE_APPLICATION):
|
||||||
validSize = true;
|
validSize = (exhdrSize == sizeof(sApplicationMetaExtendedHeader));
|
||||||
else if (type == cmnt::METATYPE_ADD_ON_CONTENT && exhdrSize == sizeof(sAddOnContentMetaExtendedHeader))
|
break;
|
||||||
validSize = true;
|
case (cnmt::METATYPE_PATCH):
|
||||||
else if (type == cmnt::METATYPE_DELTA && exhdrSize == sizeof(sDeltaMetaExtendedHeader))
|
validSize = (exhdrSize == sizeof(sPatchMetaExtendedHeader));
|
||||||
validSize = true;
|
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;
|
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;
|
size_t exdata_len = 0;
|
||||||
if (type == cmnt::METATYPE_PATCH)
|
if (type == cnmt::METATYPE_PATCH)
|
||||||
{
|
{
|
||||||
const sPatchMetaExtendedHeader* exhdr = (const sPatchMetaExtendedHeader*)(data);
|
const sPatchMetaExtendedHeader* exhdr = (const sPatchMetaExtendedHeader*)(data);
|
||||||
exdata_len = exhdr->extended_data_size.get();
|
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);
|
const sDeltaMetaExtendedHeader* exhdr = (const sDeltaMetaExtendedHeader*)(data);
|
||||||
exdata_len = exhdr->extended_data_size.get();
|
exdata_len = exhdr->extended_data_size.get();
|
||||||
|
@ -233,7 +307,7 @@ size_t nx::ContentMetaBinary::getExtendedDataSize(cmnt::ContentMetaType type, co
|
||||||
return exdata_len;
|
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
|
// check if it is large enough to read the header
|
||||||
if (len < sizeof(sContentMetaHeader))
|
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;
|
const sContentMetaHeader* hdr = (const sContentMetaHeader*)bytes;
|
||||||
|
|
||||||
// validate extended header size
|
// 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");
|
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
|
// 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");
|
throw fnd::Exception(kModuleName, "Binary too small");
|
||||||
}
|
}
|
||||||
|
@ -269,12 +343,16 @@ bool nx::ContentMetaBinary::isEqual(const ContentMetaBinary & other) const
|
||||||
&& (mTitleVersion == other.mTitleVersion) \
|
&& (mTitleVersion == other.mTitleVersion) \
|
||||||
&& (mType == other.mType) \
|
&& (mType == other.mType) \
|
||||||
&& (mAttributes == other.mAttributes) \
|
&& (mAttributes == other.mAttributes) \
|
||||||
&& (mRequiredSystemVersion == other.mRequiredSystemVersion) \
|
&& (mRequiredDownloadSystemVersion == other.mRequiredDownloadSystemVersion) \
|
||||||
&& (mExtendedHeader == other.mExtendedHeader) \
|
&& (mExtendedHeader == other.mExtendedHeader) \
|
||||||
|
&& (mApplicationMetaExtendedHeader == other.mApplicationMetaExtendedHeader) \
|
||||||
|
&& (mPatchMetaExtendedHeader == other.mPatchMetaExtendedHeader) \
|
||||||
|
&& (mAddOnContentMetaExtendedHeader == other.mAddOnContentMetaExtendedHeader) \
|
||||||
|
&& (mDeltaMetaExtendedHeader == other.mDeltaMetaExtendedHeader) \
|
||||||
&& (mContentInfo == other.mContentInfo) \
|
&& (mContentInfo == other.mContentInfo) \
|
||||||
&& (mContentMetaInfo == other.mContentMetaInfo) \
|
&& (mContentMetaInfo == other.mContentMetaInfo) \
|
||||||
&& (mExtendedData == other.mExtendedData) \
|
&& (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)
|
void nx::ContentMetaBinary::copyFrom(const ContentMetaBinary & other)
|
||||||
|
@ -290,11 +368,15 @@ void nx::ContentMetaBinary::copyFrom(const ContentMetaBinary & other)
|
||||||
mTitleVersion = other.mTitleVersion;
|
mTitleVersion = other.mTitleVersion;
|
||||||
mType = other.mType;
|
mType = other.mType;
|
||||||
mAttributes = other.mAttributes;
|
mAttributes = other.mAttributes;
|
||||||
mRequiredSystemVersion = other.mRequiredSystemVersion;
|
mRequiredDownloadSystemVersion = other.mRequiredDownloadSystemVersion;
|
||||||
mExtendedHeader = other.mExtendedHeader;
|
mExtendedHeader = other.mExtendedHeader;
|
||||||
|
mApplicationMetaExtendedHeader = other.mApplicationMetaExtendedHeader;
|
||||||
|
mPatchMetaExtendedHeader = other.mPatchMetaExtendedHeader;
|
||||||
|
mAddOnContentMetaExtendedHeader = other.mAddOnContentMetaExtendedHeader;
|
||||||
|
mDeltaMetaExtendedHeader = other.mDeltaMetaExtendedHeader;
|
||||||
mContentInfo = other.mContentInfo;
|
mContentInfo = other.mContentInfo;
|
||||||
mContentMetaInfo = other.mContentMetaInfo;
|
mContentMetaInfo = other.mContentMetaInfo;
|
||||||
mExtendedData = other.mExtendedData;
|
mExtendedData = other.mExtendedData;
|
||||||
memcpy(mDigest.data, other.mDigest.data, cmnt::kDigestLen);
|
memcpy(mDigest.data, other.mDigest.data, cnmt::kDigestLen);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
#include "CmntProcess.h"
|
|
|
@ -1 +0,0 @@
|
||||||
#pragma once
|
|
185
programs/nstool/source/CnmtProcess.cpp
Normal file
185
programs/nstool/source/CnmtProcess.cpp
Normal 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;
|
||||||
|
}
|
33
programs/nstool/source/CnmtProcess.h
Normal file
33
programs/nstool/source/CnmtProcess.h
Normal 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();
|
||||||
|
};
|
|
@ -2,10 +2,10 @@
|
||||||
#include <fnd/SimpleTextOutput.h>
|
#include <fnd/SimpleTextOutput.h>
|
||||||
#include <nx/NcaUtils.h>
|
#include <nx/NcaUtils.h>
|
||||||
#include <nx/AesKeygen.h>
|
#include <nx/AesKeygen.h>
|
||||||
#include <nx/NpdmBinary.h>
|
|
||||||
#include "NcaProcess.h"
|
#include "NcaProcess.h"
|
||||||
#include "PfsProcess.h"
|
#include "PfsProcess.h"
|
||||||
#include "RomfsProcess.h"
|
#include "RomfsProcess.h"
|
||||||
|
#include "NpdmProcess.h"
|
||||||
#include "OffsetAdjustedIFile.h"
|
#include "OffsetAdjustedIFile.h"
|
||||||
#include "AesCtrWrappedIFile.h"
|
#include "AesCtrWrappedIFile.h"
|
||||||
#include "CopiedIFile.h"
|
#include "CopiedIFile.h"
|
||||||
|
@ -199,10 +199,11 @@ void NcaProcess::generatePartitionConfiguration()
|
||||||
throw fnd::Exception(kModuleName, error.str());
|
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)
|
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_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)
|
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)
|
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_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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -245,25 +247,21 @@ void NcaProcess::validateNcaSignatures()
|
||||||
if (mPartitions[0].reader != nullptr)
|
if (mPartitions[0].reader != nullptr)
|
||||||
{
|
{
|
||||||
PfsProcess exefs;
|
PfsProcess exefs;
|
||||||
exefs.setInputFile(mPartitions[0].reader);
|
exefs.setInputFile(mPartitions[0].reader, mPartitions[0].offset + mPartitions[0].data_offset, mPartitions[0].data_size);
|
||||||
exefs.setInputFileOffset(mPartitions[0].offset + mPartitions[0].data_offset);
|
|
||||||
exefs.setCliOutputMode(OUTPUT_MINIMAL);
|
exefs.setCliOutputMode(OUTPUT_MINIMAL);
|
||||||
exefs.process();
|
exefs.process();
|
||||||
|
|
||||||
// open main.npdm
|
// open main.npdm
|
||||||
if (exefs.getPfsHeader().getFileList().hasElement(kNpdmExefsPath) == true)
|
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;
|
NpdmProcess npdm;
|
||||||
scratch.alloc(npdmFile.size);
|
npdm.setInputFile(mPartitions[0].reader, mPartitions[0].offset + mPartitions[0].data_offset + file.offset, file.size);
|
||||||
mPartitions[0].reader->read(scratch.getBytes(), mPartitions[0].offset + mPartitions[0].data_offset + npdmFile.offset, npdmFile.size);
|
npdm.setCliOutputMode(OUTPUT_MINIMAL);
|
||||||
|
npdm.process();
|
||||||
|
|
||||||
nx::NpdmBinary npdmBinary;
|
if (crypto::rsa::pss::rsaVerify(npdm.getNpdmBinary().getAcid().getNcaHeader2RsaKey(), crypto::sha::HASH_SHA256, mHdrHash.bytes, mHdrBlock.signature_acid) != 0)
|
||||||
|
|
||||||
npdmBinary.importBinary(scratch.getBytes(), scratch.getSize());
|
|
||||||
|
|
||||||
if (crypto::rsa::pss::rsaVerify(npdmBinary.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
|
// this is minimal even though it's a warning because it's a validation method
|
||||||
if (mCliOutputType >= OUTPUT_MINIMAL)
|
if (mCliOutputType >= OUTPUT_MINIMAL)
|
||||||
|
@ -429,8 +427,7 @@ void NcaProcess::processPartitions()
|
||||||
if (partition.format_type == nx::nca::FORMAT_PFS0)
|
if (partition.format_type == nx::nca::FORMAT_PFS0)
|
||||||
{
|
{
|
||||||
PfsProcess pfs;
|
PfsProcess pfs;
|
||||||
pfs.setInputFile(partition.reader);
|
pfs.setInputFile(partition.reader, partition.offset + partition.data_offset, partition.data_size);
|
||||||
pfs.setInputFileOffset(partition.offset + partition.data_offset);
|
|
||||||
pfs.setCliOutputMode(mCliOutputType);
|
pfs.setCliOutputMode(mCliOutputType);
|
||||||
pfs.setListFs(mListFs);
|
pfs.setListFs(mListFs);
|
||||||
if (mPartitionPath[index].doExtract)
|
if (mPartitionPath[index].doExtract)
|
||||||
|
@ -442,8 +439,7 @@ void NcaProcess::processPartitions()
|
||||||
else if (partition.format_type == nx::nca::FORMAT_ROMFS)
|
else if (partition.format_type == nx::nca::FORMAT_ROMFS)
|
||||||
{
|
{
|
||||||
RomfsProcess romfs;
|
RomfsProcess romfs;
|
||||||
romfs.setInputFile(partition.reader);
|
romfs.setInputFile(partition.reader, partition.offset + partition.data_offset, partition.data_size);
|
||||||
romfs.setInputFileOffset(partition.offset + partition.data_offset);
|
|
||||||
romfs.setCliOutputMode(mCliOutputType);
|
romfs.setCliOutputMode(mCliOutputType);
|
||||||
romfs.setListFs(mListFs);
|
romfs.setListFs(mListFs);
|
||||||
if (mPartitionPath[index].doExtract)
|
if (mPartitionPath[index].doExtract)
|
||||||
|
@ -457,7 +453,6 @@ void NcaProcess::processPartitions()
|
||||||
|
|
||||||
NcaProcess::NcaProcess() :
|
NcaProcess::NcaProcess() :
|
||||||
mReader(nullptr),
|
mReader(nullptr),
|
||||||
mOffset(0),
|
|
||||||
mKeyset(nullptr),
|
mKeyset(nullptr),
|
||||||
mCliOutputType(OUTPUT_NORMAL),
|
mCliOutputType(OUTPUT_NORMAL),
|
||||||
mVerify(false),
|
mVerify(false),
|
||||||
|
@ -472,6 +467,11 @@ NcaProcess::NcaProcess() :
|
||||||
|
|
||||||
NcaProcess::~NcaProcess()
|
NcaProcess::~NcaProcess()
|
||||||
{
|
{
|
||||||
|
if (mReader != nullptr)
|
||||||
|
{
|
||||||
|
delete mReader;
|
||||||
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < nx::nca::kPartitionNum; i++)
|
for (size_t i = 0; i < nx::nca::kPartitionNum; i++)
|
||||||
{
|
{
|
||||||
if (mPartitions[i].reader != nullptr)
|
if (mPartitions[i].reader != nullptr)
|
||||||
|
@ -491,7 +491,7 @@ void NcaProcess::process()
|
||||||
}
|
}
|
||||||
|
|
||||||
// read header block
|
// read header block
|
||||||
mReader->read((byte_t*)&mHdrBlock, mOffset, sizeof(nx::sNcaHeaderBlock));
|
mReader->read((byte_t*)&mHdrBlock, 0, sizeof(nx::sNcaHeaderBlock));
|
||||||
|
|
||||||
// decrypt header block
|
// decrypt header block
|
||||||
nx::NcaUtils::decryptNcaHeader((byte_t*)&mHdrBlock, (byte_t*)&mHdrBlock, mKeyset->nca.header_key);
|
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
|
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;
|
mReader = new OffsetAdjustedIFile(file, offset, size);
|
||||||
}
|
|
||||||
|
|
||||||
void NcaProcess::setInputFileOffset(size_t offset)
|
|
||||||
{
|
|
||||||
mOffset = offset;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NcaProcess::setKeyset(const sKeyset* keyset)
|
void NcaProcess::setKeyset(const sKeyset* keyset)
|
||||||
|
|
|
@ -15,8 +15,7 @@ public:
|
||||||
void process();
|
void process();
|
||||||
|
|
||||||
// generic
|
// generic
|
||||||
void setInputFile(fnd::IFile* reader);
|
void setInputFile(fnd::IFile* file, size_t offset, size_t size);
|
||||||
void setInputFileOffset(size_t offset);
|
|
||||||
void setKeyset(const sKeyset* keyset);
|
void setKeyset(const sKeyset* keyset);
|
||||||
void setCliOutputMode(CliOutputType type);
|
void setCliOutputMode(CliOutputType type);
|
||||||
void setVerifyMode(bool verify);
|
void setVerifyMode(bool verify);
|
||||||
|
@ -34,7 +33,6 @@ private:
|
||||||
|
|
||||||
// user options
|
// user options
|
||||||
fnd::IFile* mReader;
|
fnd::IFile* mReader;
|
||||||
size_t mOffset;
|
|
||||||
const sKeyset* mKeyset;
|
const sKeyset* mKeyset;
|
||||||
CliOutputType mCliOutputType;
|
CliOutputType mCliOutputType;
|
||||||
bool mVerify;
|
bool mVerify;
|
||||||
|
@ -63,8 +61,9 @@ private:
|
||||||
{
|
{
|
||||||
fnd::IFile* reader;
|
fnd::IFile* reader;
|
||||||
size_t offset;
|
size_t offset;
|
||||||
size_t data_offset;
|
|
||||||
size_t size;
|
size_t size;
|
||||||
|
size_t data_offset;
|
||||||
|
size_t data_size;
|
||||||
nx::nca::FormatType format_type;
|
nx::nca::FormatType format_type;
|
||||||
nx::nca::HashType hash_type;
|
nx::nca::HashType hash_type;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
|
#include "OffsetAdjustedIFile.h"
|
||||||
#include "NpdmProcess.h"
|
#include "NpdmProcess.h"
|
||||||
#include <fnd/SimpleFile.h>
|
|
||||||
#include <fnd/MemoryBlob.h>
|
|
||||||
|
|
||||||
const std::string kInstructionType[2] = { "32Bit", "64Bit" };
|
const std::string kInstructionType[2] = { "32Bit", "64Bit" };
|
||||||
const std::string kProcAddrSpace[4] = { "Unknown", "64Bit", "32Bit", "32Bit no reserved" };
|
const std::string kProcAddrSpace[4] = { "Unknown", "64Bit", "32Bit", "32Bit no reserved" };
|
||||||
|
@ -619,13 +618,20 @@ void NpdmProcess::displayKernelCap(const nx::KcBinary& kern)
|
||||||
|
|
||||||
NpdmProcess::NpdmProcess() :
|
NpdmProcess::NpdmProcess() :
|
||||||
mReader(nullptr),
|
mReader(nullptr),
|
||||||
mOffset(0),
|
|
||||||
mKeyset(nullptr),
|
mKeyset(nullptr),
|
||||||
mCliOutputType(OUTPUT_NORMAL),
|
mCliOutputType(OUTPUT_NORMAL),
|
||||||
mVerify(false)
|
mVerify(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NpdmProcess::~NpdmProcess()
|
||||||
|
{
|
||||||
|
if (mReader != nullptr)
|
||||||
|
{
|
||||||
|
delete mReader;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void NpdmProcess::process()
|
void NpdmProcess::process()
|
||||||
{
|
{
|
||||||
fnd::MemoryBlob scratch;
|
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;
|
mReader = new OffsetAdjustedIFile(file, offset, size);
|
||||||
}
|
|
||||||
|
|
||||||
void NpdmProcess::setInputFileOffset(size_t offset)
|
|
||||||
{
|
|
||||||
mOffset = offset;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NpdmProcess::setKeyset(const sKeyset* keyset)
|
void NpdmProcess::setKeyset(const sKeyset* keyset)
|
||||||
|
@ -688,4 +689,9 @@ void NpdmProcess::setCliOutputMode(CliOutputType type)
|
||||||
void NpdmProcess::setVerifyMode(bool verify)
|
void NpdmProcess::setVerifyMode(bool verify)
|
||||||
{
|
{
|
||||||
mVerify = verify;
|
mVerify = verify;
|
||||||
|
}
|
||||||
|
|
||||||
|
const nx::NpdmBinary& NpdmProcess::getNpdmBinary() const
|
||||||
|
{
|
||||||
|
return mNpdm;
|
||||||
}
|
}
|
|
@ -10,20 +10,21 @@ class NpdmProcess
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NpdmProcess();
|
NpdmProcess();
|
||||||
|
~NpdmProcess();
|
||||||
|
|
||||||
void process();
|
void process();
|
||||||
|
|
||||||
void setInputFile(fnd::IFile* reader);
|
void setInputFile(fnd::IFile* file, size_t offset, size_t size);
|
||||||
void setInputFileOffset(size_t offset);
|
|
||||||
void setKeyset(const sKeyset* keyset);
|
void setKeyset(const sKeyset* keyset);
|
||||||
void setCliOutputMode(CliOutputType type);
|
void setCliOutputMode(CliOutputType type);
|
||||||
void setVerifyMode(bool verify);
|
void setVerifyMode(bool verify);
|
||||||
|
|
||||||
|
const nx::NpdmBinary& getNpdmBinary() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const std::string kModuleName = "NpdmProcess";
|
const std::string kModuleName = "NpdmProcess";
|
||||||
|
|
||||||
fnd::IFile* mReader;
|
fnd::IFile* mReader;
|
||||||
size_t mOffset;
|
|
||||||
const sKeyset* mKeyset;
|
const sKeyset* mKeyset;
|
||||||
CliOutputType mCliOutputType;
|
CliOutputType mCliOutputType;
|
||||||
bool mVerify;
|
bool mVerify;
|
||||||
|
|
|
@ -16,7 +16,7 @@ size_t OffsetAdjustedIFile::size()
|
||||||
|
|
||||||
void OffsetAdjustedIFile::seek(size_t offset)
|
void OffsetAdjustedIFile::seek(size_t offset)
|
||||||
{
|
{
|
||||||
mCurrentOffset = offset;
|
mCurrentOffset = MIN(offset, mSize);
|
||||||
mFile->seek(offset + mBaseOffset);
|
mFile->seek(offset + mBaseOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "PfsProcess.h"
|
|
||||||
#include <fnd/SimpleFile.h>
|
#include <fnd/SimpleFile.h>
|
||||||
#include <fnd/io.h>
|
#include <fnd/io.h>
|
||||||
|
#include "OffsetAdjustedIFile.h"
|
||||||
|
#include "PfsProcess.h"
|
||||||
|
|
||||||
void PfsProcess::displayHeader()
|
void PfsProcess::displayHeader()
|
||||||
{
|
{
|
||||||
|
@ -55,7 +56,7 @@ void PfsProcess::validateHfs()
|
||||||
for (size_t i = 0; i < file.getSize(); i++)
|
for (size_t i = 0; i < file.getSize(); i++)
|
||||||
{
|
{
|
||||||
scratch.alloc(file[i].hash_protected_size);
|
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);
|
crypto::sha::Sha256(scratch.getBytes(), scratch.getSize(), hash.bytes);
|
||||||
if (hash != file[i].hash)
|
if (hash != file[i].hash)
|
||||||
{
|
{
|
||||||
|
@ -85,7 +86,7 @@ void PfsProcess::extractFs()
|
||||||
fnd::io::appendToPath(file_path, mExtractPath);
|
fnd::io::appendToPath(file_path, mExtractPath);
|
||||||
fnd::io::appendToPath(file_path, file[i].name);
|
fnd::io::appendToPath(file_path, file[i].name);
|
||||||
outFile.open(file_path, outFile.Create);
|
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++)
|
for (size_t j = 0; j < (file[i].size / kFileExportBlockSize); j++)
|
||||||
{
|
{
|
||||||
mReader->read(scratch.getBytes(), kFileExportBlockSize);
|
mReader->read(scratch.getBytes(), kFileExportBlockSize);
|
||||||
|
@ -102,8 +103,6 @@ void PfsProcess::extractFs()
|
||||||
|
|
||||||
PfsProcess::PfsProcess() :
|
PfsProcess::PfsProcess() :
|
||||||
mReader(nullptr),
|
mReader(nullptr),
|
||||||
mOffset(0),
|
|
||||||
mKeyset(nullptr),
|
|
||||||
mCliOutputType(OUTPUT_NORMAL),
|
mCliOutputType(OUTPUT_NORMAL),
|
||||||
mVerify(false),
|
mVerify(false),
|
||||||
mExtractPath(),
|
mExtractPath(),
|
||||||
|
@ -112,7 +111,14 @@ PfsProcess::PfsProcess() :
|
||||||
mListFs(false),
|
mListFs(false),
|
||||||
mPfs()
|
mPfs()
|
||||||
{
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
PfsProcess::~PfsProcess()
|
||||||
|
{
|
||||||
|
if (mReader != nullptr)
|
||||||
|
{
|
||||||
|
delete mReader;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PfsProcess::process()
|
void PfsProcess::process()
|
||||||
|
@ -126,7 +132,7 @@ void PfsProcess::process()
|
||||||
|
|
||||||
// open minimum header to get full header size
|
// open minimum header to get full header size
|
||||||
scratch.alloc(sizeof(nx::sPfsHeader));
|
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)
|
if (validateHeaderMagic(((nx::sPfsHeader*)scratch.getBytes())) == false)
|
||||||
{
|
{
|
||||||
throw fnd::Exception(kModuleName, "Corrupt Header");
|
throw fnd::Exception(kModuleName, "Corrupt Header");
|
||||||
|
@ -135,7 +141,7 @@ void PfsProcess::process()
|
||||||
|
|
||||||
// open minimum header to get full header size
|
// open minimum header to get full header size
|
||||||
scratch.alloc(pfsHeaderSize);
|
scratch.alloc(pfsHeaderSize);
|
||||||
mReader->read(scratch.getBytes(), mOffset, scratch.getSize());
|
mReader->read(scratch.getBytes(), 0, scratch.getSize());
|
||||||
mPfs.importBinary(scratch.getBytes(), scratch.getSize());
|
mPfs.importBinary(scratch.getBytes(), scratch.getSize());
|
||||||
|
|
||||||
if (mCliOutputType >= OUTPUT_NORMAL)
|
if (mCliOutputType >= OUTPUT_NORMAL)
|
||||||
|
@ -148,19 +154,9 @@ void PfsProcess::process()
|
||||||
extractFs();
|
extractFs();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PfsProcess::setInputFile(fnd::IFile* reader)
|
void PfsProcess::setInputFile(fnd::IFile* file, size_t offset, size_t size)
|
||||||
{
|
{
|
||||||
mReader = reader;
|
mReader = new OffsetAdjustedIFile(file, offset, size);
|
||||||
}
|
|
||||||
|
|
||||||
void PfsProcess::setInputFileOffset(size_t offset)
|
|
||||||
{
|
|
||||||
mOffset = offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PfsProcess::setKeyset(const sKeyset* keyset)
|
|
||||||
{
|
|
||||||
mKeyset = keyset;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PfsProcess::setCliOutputMode(CliOutputType type)
|
void PfsProcess::setCliOutputMode(CliOutputType type)
|
||||||
|
|
|
@ -10,13 +10,12 @@ class PfsProcess
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PfsProcess();
|
PfsProcess();
|
||||||
|
~PfsProcess();
|
||||||
|
|
||||||
void process();
|
void process();
|
||||||
|
|
||||||
// generic
|
// generic
|
||||||
void setInputFile(fnd::IFile* reader);
|
void setInputFile(fnd::IFile* file, size_t offset, size_t size);
|
||||||
void setInputFileOffset(size_t offset);
|
|
||||||
void setKeyset(const sKeyset* keyset);
|
|
||||||
void setCliOutputMode(CliOutputType type);
|
void setCliOutputMode(CliOutputType type);
|
||||||
void setVerifyMode(bool verify);
|
void setVerifyMode(bool verify);
|
||||||
|
|
||||||
|
@ -32,8 +31,6 @@ private:
|
||||||
static const size_t kFileExportBlockSize = 0x1000000;
|
static const size_t kFileExportBlockSize = 0x1000000;
|
||||||
|
|
||||||
fnd::IFile* mReader;
|
fnd::IFile* mReader;
|
||||||
size_t mOffset;
|
|
||||||
const sKeyset* mKeyset;
|
|
||||||
CliOutputType mCliOutputType;
|
CliOutputType mCliOutputType;
|
||||||
bool mVerify;
|
bool mVerify;
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
#include "RomfsProcess.h"
|
|
||||||
#include <fnd/SimpleTextOutput.h>
|
#include <fnd/SimpleTextOutput.h>
|
||||||
#include <fnd/SimpleFile.h>
|
#include <fnd/SimpleFile.h>
|
||||||
#include <fnd/io.h>
|
#include <fnd/io.h>
|
||||||
|
#include "OffsetAdjustedIFile.h"
|
||||||
|
#include "RomfsProcess.h"
|
||||||
|
|
||||||
void RomfsProcess::printTab(size_t tab) const
|
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);
|
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++)
|
for (size_t j = 0; j < (dir.file_list[i].size / kFileExportBlockSize); j++)
|
||||||
{
|
{
|
||||||
mReader->read(scratch.getBytes(), kFileExportBlockSize);
|
mReader->read(scratch.getBytes(), kFileExportBlockSize);
|
||||||
|
@ -186,7 +187,7 @@ void RomfsProcess::importDirectory(uint32_t dir_offset, sDirectory& dir)
|
||||||
void RomfsProcess::resolveRomfs()
|
void RomfsProcess::resolveRomfs()
|
||||||
{
|
{
|
||||||
// read header
|
// 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
|
// logic check on the header layout
|
||||||
if (validateHeaderLayout(&mHdr) == false)
|
if (validateHeaderLayout(&mHdr) == false)
|
||||||
|
@ -196,13 +197,13 @@ void RomfsProcess::resolveRomfs()
|
||||||
|
|
||||||
// read directory nodes
|
// read directory nodes
|
||||||
mDirNodes.alloc(mHdr.sections[nx::romfs::DIR_NODE_TABLE].size.get());
|
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");
|
//printf("[RAW DIR NODES]\n");
|
||||||
//fnd::SimpleTextOutput::hxdStyleDump(mDirNodes.getBytes(), mDirNodes.getSize());
|
//fnd::SimpleTextOutput::hxdStyleDump(mDirNodes.getBytes(), mDirNodes.getSize());
|
||||||
|
|
||||||
// read file nodes
|
// read file nodes
|
||||||
mFileNodes.alloc(mHdr.sections[nx::romfs::FILE_NODE_TABLE].size.get());
|
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");
|
//printf("[RAW FILE NODES]\n");
|
||||||
//fnd::SimpleTextOutput::hxdStyleDump(mFileNodes.getBytes(), mFileNodes.getSize());
|
//fnd::SimpleTextOutput::hxdStyleDump(mFileNodes.getBytes(), mFileNodes.getSize());
|
||||||
|
|
||||||
|
@ -223,8 +224,6 @@ void RomfsProcess::resolveRomfs()
|
||||||
|
|
||||||
RomfsProcess::RomfsProcess() :
|
RomfsProcess::RomfsProcess() :
|
||||||
mReader(nullptr),
|
mReader(nullptr),
|
||||||
mOffset(0),
|
|
||||||
mKeyset(nullptr),
|
|
||||||
mCliOutputType(OUTPUT_NORMAL),
|
mCliOutputType(OUTPUT_NORMAL),
|
||||||
mVerify(false),
|
mVerify(false),
|
||||||
mExtractPath(),
|
mExtractPath(),
|
||||||
|
@ -239,6 +238,14 @@ RomfsProcess::RomfsProcess() :
|
||||||
mRootDir.file_list.clear();
|
mRootDir.file_list.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RomfsProcess::~RomfsProcess()
|
||||||
|
{
|
||||||
|
if (mReader != nullptr)
|
||||||
|
{
|
||||||
|
delete mReader;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void RomfsProcess::process()
|
void RomfsProcess::process()
|
||||||
{
|
{
|
||||||
if (mReader == nullptr)
|
if (mReader == nullptr)
|
||||||
|
@ -256,19 +263,9 @@ void RomfsProcess::process()
|
||||||
extractFs();
|
extractFs();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RomfsProcess::setInputFile(fnd::IFile* reader)
|
void RomfsProcess::setInputFile(fnd::IFile* file, size_t offset, size_t size)
|
||||||
{
|
{
|
||||||
mReader = reader;
|
mReader = new OffsetAdjustedIFile(file, offset, size);
|
||||||
}
|
|
||||||
|
|
||||||
void RomfsProcess::setInputFileOffset(size_t offset)
|
|
||||||
{
|
|
||||||
mOffset = offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RomfsProcess::setKeyset(const sKeyset* keyset)
|
|
||||||
{
|
|
||||||
mKeyset = keyset;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RomfsProcess::setCliOutputMode(CliOutputType type)
|
void RomfsProcess::setCliOutputMode(CliOutputType type)
|
||||||
|
|
|
@ -89,13 +89,12 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
RomfsProcess();
|
RomfsProcess();
|
||||||
|
~RomfsProcess();
|
||||||
|
|
||||||
void process();
|
void process();
|
||||||
|
|
||||||
// generic
|
// generic
|
||||||
void setInputFile(fnd::IFile* reader);
|
void setInputFile(fnd::IFile* file, size_t offset, size_t size);
|
||||||
void setInputFileOffset(size_t offset);
|
|
||||||
void setKeyset(const sKeyset* keyset);
|
|
||||||
void setCliOutputMode(CliOutputType type);
|
void setCliOutputMode(CliOutputType type);
|
||||||
void setVerifyMode(bool verify);
|
void setVerifyMode(bool verify);
|
||||||
|
|
||||||
|
@ -110,8 +109,6 @@ private:
|
||||||
static const size_t kFileExportBlockSize = 0x1000000;
|
static const size_t kFileExportBlockSize = 0x1000000;
|
||||||
|
|
||||||
fnd::IFile* mReader;
|
fnd::IFile* mReader;
|
||||||
size_t mOffset;
|
|
||||||
const sKeyset* mKeyset;
|
|
||||||
CliOutputType mCliOutputType;
|
CliOutputType mCliOutputType;
|
||||||
bool mVerify;
|
bool mVerify;
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ void UserSettings::showHelp()
|
||||||
printf("\n General Options:\n");
|
printf("\n General Options:\n");
|
||||||
printf(" -d, --dev Use devkit keyset\n");
|
printf(" -d, --dev Use devkit keyset\n");
|
||||||
printf(" -k, --keyset Specify keyset file\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(" -y, --verify Verify file\n");
|
||||||
printf(" -v, --verbose Verbose output\n");
|
printf(" -v, --verbose Verbose output\n");
|
||||||
printf(" -q, --quiet Minimal output\n");
|
printf(" -q, --quiet Minimal output\n");
|
||||||
|
@ -576,8 +576,8 @@ FileType UserSettings::getFileTypeFromString(const std::string& type_str)
|
||||||
type = FILE_NCA;
|
type = FILE_NCA;
|
||||||
else if (str == "npdm")
|
else if (str == "npdm")
|
||||||
type = FILE_NPDM;
|
type = FILE_NPDM;
|
||||||
else if (str == "cmnt")
|
else if (str == "cnmt")
|
||||||
type = FILE_CMNT;
|
type = FILE_CNMT;
|
||||||
else
|
else
|
||||||
type = FILE_INVALID;
|
type = FILE_INVALID;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "XciProcess.h"
|
|
||||||
#include <fnd/SimpleTextOutput.h>
|
#include <fnd/SimpleTextOutput.h>
|
||||||
#include <nx/XciUtils.h>
|
#include <nx/XciUtils.h>
|
||||||
|
#include "OffsetAdjustedIFile.h"
|
||||||
|
#include "XciProcess.h"
|
||||||
|
|
||||||
inline const char* getBoolStr(bool isTrue)
|
inline const char* getBoolStr(bool isTrue)
|
||||||
{
|
{
|
||||||
|
@ -136,13 +137,12 @@ void XciProcess::processRootPfs()
|
||||||
{
|
{
|
||||||
if (mVerify)
|
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");
|
printf("[WARNING] XCI Root HFS0: FAIL (bad hash)\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mRootPfs.setInputFile(mReader);
|
mRootPfs.setInputFile(mReader, mHdr.getPartitionFsAddress(), mHdr.getPartitionFsSize());
|
||||||
mRootPfs.setInputFileOffset(mOffset + mHdr.getPartitionFsAddress());
|
|
||||||
mRootPfs.setListFs(mListFs);
|
mRootPfs.setListFs(mListFs);
|
||||||
mRootPfs.setVerifyMode(mVerify);
|
mRootPfs.setVerifyMode(mVerify);
|
||||||
mRootPfs.setCliOutputMode(mCliOutputType);
|
mRootPfs.setCliOutputMode(mCliOutputType);
|
||||||
|
@ -156,8 +156,7 @@ void XciProcess::processPartitionPfs()
|
||||||
for (size_t i = 0; i < rootPartitions.getSize(); i++)
|
for (size_t i = 0; i < rootPartitions.getSize(); i++)
|
||||||
{
|
{
|
||||||
PfsProcess tmp;
|
PfsProcess tmp;
|
||||||
tmp.setInputFile(mReader);
|
tmp.setInputFile(mReader, mHdr.getPartitionFsAddress() + rootPartitions[i].offset, rootPartitions[i].size);
|
||||||
tmp.setInputFileOffset(mOffset + mHdr.getPartitionFsAddress() + rootPartitions[i].offset);
|
|
||||||
tmp.setListFs(mListFs);
|
tmp.setListFs(mListFs);
|
||||||
tmp.setVerifyMode(mVerify);
|
tmp.setVerifyMode(mVerify);
|
||||||
tmp.setCliOutputMode(mCliOutputType);
|
tmp.setCliOutputMode(mCliOutputType);
|
||||||
|
@ -174,7 +173,6 @@ void XciProcess::processPartitionPfs()
|
||||||
|
|
||||||
XciProcess::XciProcess() :
|
XciProcess::XciProcess() :
|
||||||
mReader(nullptr),
|
mReader(nullptr),
|
||||||
mOffset(0),
|
|
||||||
mKeyset(nullptr),
|
mKeyset(nullptr),
|
||||||
mCliOutputType(OUTPUT_NORMAL),
|
mCliOutputType(OUTPUT_NORMAL),
|
||||||
mVerify(false),
|
mVerify(false),
|
||||||
|
@ -189,6 +187,14 @@ XciProcess::XciProcess() :
|
||||||
mSecurePath.doExtract = false;
|
mSecurePath.doExtract = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
XciProcess::~XciProcess()
|
||||||
|
{
|
||||||
|
if (mReader != nullptr)
|
||||||
|
{
|
||||||
|
delete mReader;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void XciProcess::process()
|
void XciProcess::process()
|
||||||
{
|
{
|
||||||
fnd::MemoryBlob scratch;
|
fnd::MemoryBlob scratch;
|
||||||
|
@ -199,7 +205,7 @@ void XciProcess::process()
|
||||||
}
|
}
|
||||||
|
|
||||||
// read header page
|
// 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
|
// allocate memory for and decrypt sXciHeader
|
||||||
scratch.alloc(sizeof(nx::sXciHeader));
|
scratch.alloc(sizeof(nx::sXciHeader));
|
||||||
|
@ -227,14 +233,9 @@ void XciProcess::process()
|
||||||
processPartitionPfs();
|
processPartitionPfs();
|
||||||
}
|
}
|
||||||
|
|
||||||
void XciProcess::setInputFile(fnd::IFile* reader)
|
void XciProcess::setInputFile(fnd::IFile* file, size_t offset, size_t size)
|
||||||
{
|
{
|
||||||
mReader = reader;
|
mReader = new OffsetAdjustedIFile(file, offset, size);
|
||||||
}
|
|
||||||
|
|
||||||
void XciProcess::setInputFileOffset(size_t offset)
|
|
||||||
{
|
|
||||||
mOffset = offset;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void XciProcess::setKeyset(const sKeyset* keyset)
|
void XciProcess::setKeyset(const sKeyset* keyset)
|
||||||
|
|
|
@ -13,12 +13,12 @@ class XciProcess
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
XciProcess();
|
XciProcess();
|
||||||
|
~XciProcess();
|
||||||
|
|
||||||
void process();
|
void process();
|
||||||
|
|
||||||
// generic
|
// generic
|
||||||
void setInputFile(fnd::IFile* reader);
|
void setInputFile(fnd::IFile* file, size_t offset, size_t size);
|
||||||
void setInputFileOffset(size_t offset);
|
|
||||||
void setKeyset(const sKeyset* keyset);
|
void setKeyset(const sKeyset* keyset);
|
||||||
void setCliOutputMode(CliOutputType type);
|
void setCliOutputMode(CliOutputType type);
|
||||||
void setVerifyMode(bool verify);
|
void setVerifyMode(bool verify);
|
||||||
|
@ -35,7 +35,6 @@ private:
|
||||||
static const size_t kFileExportBlockSize = 0x1000000;
|
static const size_t kFileExportBlockSize = 0x1000000;
|
||||||
|
|
||||||
fnd::IFile* mReader;
|
fnd::IFile* mReader;
|
||||||
size_t mOffset;
|
|
||||||
const sKeyset* mKeyset;
|
const sKeyset* mKeyset;
|
||||||
CliOutputType mCliOutputType;
|
CliOutputType mCliOutputType;
|
||||||
bool mVerify;
|
bool mVerify;
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include "RomfsProcess.h"
|
#include "RomfsProcess.h"
|
||||||
#include "NcaProcess.h"
|
#include "NcaProcess.h"
|
||||||
#include "NpdmProcess.h"
|
#include "NpdmProcess.h"
|
||||||
|
#include "CnmtProcess.h"
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
|
@ -21,7 +22,7 @@ int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
XciProcess xci;
|
XciProcess xci;
|
||||||
|
|
||||||
xci.setInputFile(&inputFile);
|
xci.setInputFile(&inputFile, 0, inputFile.size());
|
||||||
|
|
||||||
xci.setKeyset(&user_set.getKeyset());
|
xci.setKeyset(&user_set.getKeyset());
|
||||||
xci.setCliOutputMode(user_set.getCliOutputType());
|
xci.setCliOutputMode(user_set.getCliOutputType());
|
||||||
|
@ -41,8 +42,7 @@ int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
PfsProcess pfs;
|
PfsProcess pfs;
|
||||||
|
|
||||||
pfs.setInputFile(&inputFile);
|
pfs.setInputFile(&inputFile, 0, inputFile.size());
|
||||||
pfs.setKeyset(&user_set.getKeyset());
|
|
||||||
pfs.setCliOutputMode(user_set.getCliOutputType());
|
pfs.setCliOutputMode(user_set.getCliOutputType());
|
||||||
pfs.setVerifyMode(user_set.isVerifyFile());
|
pfs.setVerifyMode(user_set.isVerifyFile());
|
||||||
|
|
||||||
|
@ -56,8 +56,7 @@ int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
RomfsProcess romfs;
|
RomfsProcess romfs;
|
||||||
|
|
||||||
romfs.setInputFile(&inputFile);
|
romfs.setInputFile(&inputFile, 0, inputFile.size());
|
||||||
romfs.setKeyset(&user_set.getKeyset());
|
|
||||||
romfs.setCliOutputMode(user_set.getCliOutputType());
|
romfs.setCliOutputMode(user_set.getCliOutputType());
|
||||||
romfs.setVerifyMode(user_set.isVerifyFile());
|
romfs.setVerifyMode(user_set.isVerifyFile());
|
||||||
|
|
||||||
|
@ -71,7 +70,7 @@ int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
NcaProcess nca;
|
NcaProcess nca;
|
||||||
|
|
||||||
nca.setInputFile(&inputFile);
|
nca.setInputFile(&inputFile, 0, inputFile.size());
|
||||||
nca.setKeyset(&user_set.getKeyset());
|
nca.setKeyset(&user_set.getKeyset());
|
||||||
nca.setCliOutputMode(user_set.getCliOutputType());
|
nca.setCliOutputMode(user_set.getCliOutputType());
|
||||||
nca.setVerifyMode(user_set.isVerifyFile());
|
nca.setVerifyMode(user_set.isVerifyFile());
|
||||||
|
@ -93,13 +92,23 @@ int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
NpdmProcess npdm;
|
NpdmProcess npdm;
|
||||||
|
|
||||||
npdm.setInputFile(&inputFile);
|
npdm.setInputFile(&inputFile, 0, inputFile.size());
|
||||||
npdm.setKeyset(&user_set.getKeyset());
|
npdm.setKeyset(&user_set.getKeyset());
|
||||||
npdm.setCliOutputMode(user_set.getCliOutputType());
|
npdm.setCliOutputMode(user_set.getCliOutputType());
|
||||||
npdm.setVerifyMode(user_set.isVerifyFile());
|
npdm.setVerifyMode(user_set.isVerifyFile());
|
||||||
|
|
||||||
npdm.process();
|
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) {
|
catch (const fnd::Exception& e) {
|
||||||
printf("\n\n%s\n", e.what());
|
printf("\n\n%s\n", e.what());
|
||||||
|
|
|
@ -17,7 +17,7 @@ enum FileType
|
||||||
FILE_ROMFS,
|
FILE_ROMFS,
|
||||||
FILE_NCA,
|
FILE_NCA,
|
||||||
FILE_NPDM,
|
FILE_NPDM,
|
||||||
FILE_CMNT,
|
FILE_CNMT,
|
||||||
FILE_INVALID = -1,
|
FILE_INVALID = -1,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue