2020-02-26 09:03:43 +00:00
|
|
|
#include "CnmtProcess.h"
|
|
|
|
|
|
|
|
#include <nn/hac/ContentMetaUtil.h>
|
2019-01-31 09:10:19 +00:00
|
|
|
|
2021-09-28 11:15:54 +00:00
|
|
|
nstool::CnmtProcess::CnmtProcess() :
|
2021-09-30 11:41:57 +00:00
|
|
|
mModuleName("nstool::CnmtProcess"),
|
2019-01-31 09:10:19 +00:00
|
|
|
mFile(),
|
2021-09-28 11:15:54 +00:00
|
|
|
mCliOutputMode(true, false, false, false),
|
2019-01-31 09:10:19 +00:00
|
|
|
mVerify(false)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2021-09-28 11:15:54 +00:00
|
|
|
void nstool::CnmtProcess::process()
|
2019-01-31 09:10:19 +00:00
|
|
|
{
|
|
|
|
importCnmt();
|
|
|
|
|
2021-09-28 11:15:54 +00:00
|
|
|
if (mCliOutputMode.show_basic_info)
|
2019-01-31 09:10:19 +00:00
|
|
|
displayCnmt();
|
|
|
|
}
|
|
|
|
|
2021-09-28 11:15:54 +00:00
|
|
|
void nstool::CnmtProcess::setInputFile(const std::shared_ptr<tc::io::IStream>& file)
|
2019-01-31 09:10:19 +00:00
|
|
|
{
|
|
|
|
mFile = file;
|
|
|
|
}
|
|
|
|
|
2021-09-28 11:15:54 +00:00
|
|
|
void nstool::CnmtProcess::setCliOutputMode(CliOutputMode type)
|
2019-01-31 09:10:19 +00:00
|
|
|
{
|
|
|
|
mCliOutputMode = type;
|
|
|
|
}
|
|
|
|
|
2021-09-28 11:15:54 +00:00
|
|
|
void nstool::CnmtProcess::setVerifyMode(bool verify)
|
2019-01-31 09:10:19 +00:00
|
|
|
{
|
|
|
|
mVerify = verify;
|
|
|
|
}
|
|
|
|
|
2021-09-28 11:15:54 +00:00
|
|
|
const nn::hac::ContentMeta& nstool::CnmtProcess::getContentMeta() const
|
2019-01-31 09:10:19 +00:00
|
|
|
{
|
|
|
|
return mCnmt;
|
|
|
|
}
|
|
|
|
|
2021-09-28 11:15:54 +00:00
|
|
|
void nstool::CnmtProcess::importCnmt()
|
2019-01-31 09:10:19 +00:00
|
|
|
{
|
2021-09-30 11:41:57 +00:00
|
|
|
if (mFile == nullptr)
|
|
|
|
{
|
|
|
|
throw tc::Exception(mModuleName, "No file reader set.");
|
|
|
|
}
|
2021-10-03 04:01:23 +00:00
|
|
|
if (mFile->canRead() == false || mFile->canSeek() == false)
|
|
|
|
{
|
|
|
|
throw tc::NotSupportedException(mModuleName, "Input stream requires read/seek permissions.");
|
|
|
|
}
|
2021-09-30 11:41:57 +00:00
|
|
|
|
|
|
|
// check if file_size is greater than 20MB, don't import.
|
|
|
|
size_t cnmt_file_size = tc::io::IOUtil::castInt64ToSize(mFile->length());
|
|
|
|
if (cnmt_file_size > (0x100000 * 20))
|
2019-01-31 09:10:19 +00:00
|
|
|
{
|
2021-09-30 11:41:57 +00:00
|
|
|
throw tc::Exception(mModuleName, "File too large.");
|
2019-01-31 09:10:19 +00:00
|
|
|
}
|
|
|
|
|
2021-09-30 11:41:57 +00:00
|
|
|
// read cnmt
|
|
|
|
tc::ByteData scratch = tc::ByteData(cnmt_file_size);
|
|
|
|
mFile->seek(0, tc::io::SeekOrigin::Begin);
|
|
|
|
mFile->read(scratch.data(), scratch.size());
|
2019-01-31 09:10:19 +00:00
|
|
|
|
2021-09-30 11:41:57 +00:00
|
|
|
// parse cnmt
|
2019-01-31 09:10:19 +00:00
|
|
|
mCnmt.fromBytes(scratch.data(), scratch.size());
|
|
|
|
}
|
|
|
|
|
2021-09-28 11:15:54 +00:00
|
|
|
void nstool::CnmtProcess::displayCnmt()
|
2019-01-31 09:10:19 +00:00
|
|
|
{
|
2021-09-30 11:41:57 +00:00
|
|
|
const nn::hac::sContentMetaHeader* cnmt_hdr = (const nn::hac::sContentMetaHeader*)mCnmt.getBytes().data();
|
|
|
|
fmt::print("[ContentMeta]\n");
|
|
|
|
fmt::print(" TitleId: 0x{:016x}\n", mCnmt.getTitleId());
|
|
|
|
fmt::print(" Version: {:s} (v{:d})\n", nn::hac::ContentMetaUtil::getVersionAsString(mCnmt.getTitleVersion()), mCnmt.getTitleVersion());
|
2021-10-01 09:39:34 +00:00
|
|
|
fmt::print(" Type: {:s} ({:d})\n", nn::hac::ContentMetaUtil::getContentMetaTypeAsString(mCnmt.getContentMetaType()), (uint32_t)mCnmt.getContentMetaType());
|
2021-09-30 11:41:57 +00:00
|
|
|
fmt::print(" Attributes: 0x{:x}", *((byte_t*)&cnmt_hdr->attributes));
|
|
|
|
if (mCnmt.getAttribute().size())
|
2020-02-26 09:03:43 +00:00
|
|
|
{
|
2020-05-17 04:31:07 +00:00
|
|
|
std::vector<std::string> attribute_list;
|
|
|
|
|
2021-09-30 11:41:57 +00:00
|
|
|
for (auto itr = mCnmt.getAttribute().begin(); itr != mCnmt.getAttribute().end(); itr++)
|
2020-02-26 09:03:43 +00:00
|
|
|
{
|
2021-09-30 11:41:57 +00:00
|
|
|
attribute_list.push_back(nn::hac::ContentMetaUtil::getContentMetaAttributeFlagAsString(nn::hac::cnmt::ContentMetaAttributeFlag(*itr)));
|
2020-05-17 04:31:07 +00:00
|
|
|
}
|
|
|
|
|
2021-09-30 11:41:57 +00:00
|
|
|
fmt::print(" [");
|
2020-05-17 04:31:07 +00:00
|
|
|
for (auto itr = attribute_list.begin(); itr != attribute_list.end(); itr++)
|
|
|
|
{
|
2021-09-30 11:41:57 +00:00
|
|
|
fmt::print("{:s}",*itr);
|
2020-05-17 04:31:07 +00:00
|
|
|
if ((itr + 1) != attribute_list.end())
|
|
|
|
{
|
2021-09-30 11:41:57 +00:00
|
|
|
fmt::print(", ");
|
2020-02-26 09:03:43 +00:00
|
|
|
}
|
|
|
|
}
|
2021-09-30 11:41:57 +00:00
|
|
|
fmt::print("]");
|
2020-02-26 09:03:43 +00:00
|
|
|
}
|
2021-09-30 11:41:57 +00:00
|
|
|
fmt::print("\n");
|
2020-05-17 04:31:07 +00:00
|
|
|
|
2021-09-30 11:41:57 +00:00
|
|
|
fmt::print(" StorageId: {:s} ({:d})\n", nn::hac::ContentMetaUtil::getStorageIdAsString(mCnmt.getStorageId()), (uint32_t)mCnmt.getStorageId());
|
|
|
|
fmt::print(" ContentInstallType: {:s} ({:d})\n", nn::hac::ContentMetaUtil::getContentInstallTypeAsString(mCnmt.getContentInstallType()),(uint32_t)mCnmt.getContentInstallType());
|
|
|
|
fmt::print(" RequiredDownloadSystemVersion: {:s} (v{:d})\n", nn::hac::ContentMetaUtil::getVersionAsString(mCnmt.getRequiredDownloadSystemVersion()), mCnmt.getRequiredDownloadSystemVersion());
|
2019-01-31 09:10:19 +00:00
|
|
|
switch(mCnmt.getContentMetaType())
|
|
|
|
{
|
2020-03-14 14:10:09 +00:00
|
|
|
case (nn::hac::cnmt::ContentMetaType::Application):
|
2021-09-30 11:41:57 +00:00
|
|
|
fmt::print(" ApplicationExtendedHeader:\n");
|
|
|
|
fmt::print(" RequiredApplicationVersion: {:s} (v{:d})\n", nn::hac::ContentMetaUtil::getVersionAsString(mCnmt.getApplicationMetaExtendedHeader().getRequiredApplicationVersion()), mCnmt.getApplicationMetaExtendedHeader().getRequiredApplicationVersion());
|
|
|
|
fmt::print(" RequiredSystemVersion: {:s} (v{:d})\n", nn::hac::ContentMetaUtil::getVersionAsString(mCnmt.getApplicationMetaExtendedHeader().getRequiredSystemVersion()), mCnmt.getApplicationMetaExtendedHeader().getRequiredSystemVersion());
|
|
|
|
fmt::print(" PatchId: 0x{:016x}\n", mCnmt.getApplicationMetaExtendedHeader().getPatchId());
|
2019-01-31 09:10:19 +00:00
|
|
|
break;
|
2020-03-14 14:10:09 +00:00
|
|
|
case (nn::hac::cnmt::ContentMetaType::Patch):
|
2021-09-30 11:41:57 +00:00
|
|
|
fmt::print(" PatchMetaExtendedHeader:\n");
|
|
|
|
fmt::print(" RequiredSystemVersion: {:s} (v{:d})\n", nn::hac::ContentMetaUtil::getVersionAsString(mCnmt.getPatchMetaExtendedHeader().getRequiredSystemVersion()), mCnmt.getPatchMetaExtendedHeader().getRequiredSystemVersion());
|
|
|
|
fmt::print(" ApplicationId: 0x{:016x}\n", mCnmt.getPatchMetaExtendedHeader().getApplicationId());
|
2019-01-31 09:10:19 +00:00
|
|
|
break;
|
2020-03-14 14:10:09 +00:00
|
|
|
case (nn::hac::cnmt::ContentMetaType::AddOnContent):
|
2021-09-30 11:41:57 +00:00
|
|
|
fmt::print(" AddOnContentMetaExtendedHeader:\n");
|
|
|
|
fmt::print(" RequiredApplicationVersion: {:s} (v{:d})\n", nn::hac::ContentMetaUtil::getVersionAsString(mCnmt.getAddOnContentMetaExtendedHeader().getRequiredApplicationVersion()), mCnmt.getAddOnContentMetaExtendedHeader().getRequiredApplicationVersion());
|
|
|
|
fmt::print(" ApplicationId: 0x{:016x}\n", mCnmt.getAddOnContentMetaExtendedHeader().getApplicationId());
|
2019-01-31 09:10:19 +00:00
|
|
|
break;
|
2020-03-14 14:10:09 +00:00
|
|
|
case (nn::hac::cnmt::ContentMetaType::Delta):
|
2021-09-30 11:41:57 +00:00
|
|
|
fmt::print(" DeltaMetaExtendedHeader:\n");
|
|
|
|
fmt::print(" ApplicationId: 0x{:016x}\n", mCnmt.getDeltaMetaExtendedHeader().getApplicationId());
|
2019-01-31 09:10:19 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (mCnmt.getContentInfo().size() > 0)
|
|
|
|
{
|
2021-09-30 11:41:57 +00:00
|
|
|
fmt::print(" ContentInfo:\n");
|
2019-01-31 09:10:19 +00:00
|
|
|
for (size_t i = 0; i < mCnmt.getContentInfo().size(); i++)
|
|
|
|
{
|
|
|
|
const nn::hac::ContentInfo& info = mCnmt.getContentInfo()[i];
|
2021-09-30 11:41:57 +00:00
|
|
|
fmt::print(" {:d}\n", i);
|
|
|
|
fmt::print(" Type: {:s} ({:d})\n", nn::hac::ContentMetaUtil::getContentTypeAsString(info.getContentType()), (uint32_t)info.getContentType());
|
|
|
|
fmt::print(" Id: {:s}\n", tc::cli::FormatUtil::formatBytesAsString(info.getContentId().data(), info.getContentId().size(), false, ""));
|
|
|
|
fmt::print(" Size: 0x{:x}\n", info.getContentSize());
|
|
|
|
fmt::print(" Hash: {:s}\n", tc::cli::FormatUtil::formatBytesAsString(info.getContentHash().data(), info.getContentHash().size(), false, ""));
|
2019-01-31 09:10:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (mCnmt.getContentMetaInfo().size() > 0)
|
|
|
|
{
|
2021-09-30 11:41:57 +00:00
|
|
|
fmt::print(" ContentMetaInfo:\n");
|
2020-05-23 15:49:56 +00:00
|
|
|
displayContentMetaInfoList(mCnmt.getContentMetaInfo(), " ");
|
|
|
|
}
|
|
|
|
|
|
|
|
// print extended data
|
|
|
|
if (mCnmt.getContentMetaType() == nn::hac::cnmt::ContentMetaType::Patch && mCnmt.getPatchMetaExtendedHeader().getExtendedDataSize() != 0)
|
|
|
|
{
|
|
|
|
// this is stubbed as the raw output is for development purposes
|
2021-09-30 11:41:57 +00:00
|
|
|
//fmt::print(" PatchMetaExtendedData:\n");
|
|
|
|
//tc::cli::FormatUtil::formatBytesAsHxdHexString(mCnmt.getPatchMetaExtendedData().data(), mCnmt.getPatchMetaExtendedData().size());
|
2020-05-23 15:49:56 +00:00
|
|
|
}
|
|
|
|
else if (mCnmt.getContentMetaType() == nn::hac::cnmt::ContentMetaType::Delta && mCnmt.getDeltaMetaExtendedHeader().getExtendedDataSize() != 0)
|
|
|
|
{
|
|
|
|
// this is stubbed as the raw output is for development purposes
|
2021-09-30 11:41:57 +00:00
|
|
|
//fmt::print(" DeltaMetaExtendedData:\n");
|
|
|
|
//tc::cli::FormatUtil::formatBytesAsHxdHexString(mCnmt.getDeltaMetaExtendedData().data(), mCnmt.getDeltaMetaExtendedData().size());
|
2020-05-23 15:49:56 +00:00
|
|
|
}
|
|
|
|
else if (mCnmt.getContentMetaType() == nn::hac::cnmt::ContentMetaType::SystemUpdate && mCnmt.getSystemUpdateMetaExtendedHeader().getExtendedDataSize() != 0)
|
|
|
|
{
|
2021-09-30 11:41:57 +00:00
|
|
|
fmt::print(" SystemUpdateMetaExtendedData:\n");
|
|
|
|
fmt::print(" FormatVersion: {:d}\n", mCnmt.getSystemUpdateMetaExtendedData().getFormatVersion());
|
|
|
|
fmt::print(" FirmwareVariation:\n");
|
2020-05-23 15:49:56 +00:00
|
|
|
auto variation_info = mCnmt.getSystemUpdateMetaExtendedData().getFirmwareVariationInfo();
|
|
|
|
for (size_t i = 0; i < mCnmt.getSystemUpdateMetaExtendedData().getFirmwareVariationInfo().size(); i++)
|
2019-01-31 09:10:19 +00:00
|
|
|
{
|
2021-09-30 11:41:57 +00:00
|
|
|
fmt::print(" {:d}\n", i);
|
|
|
|
fmt::print(" FirmwareVariationId: 0x{:x}\n", variation_info[i].variation_id);
|
2020-05-23 15:49:56 +00:00
|
|
|
if (mCnmt.getSystemUpdateMetaExtendedData().getFormatVersion() == 2)
|
2020-02-26 09:03:43 +00:00
|
|
|
{
|
2021-09-30 11:41:57 +00:00
|
|
|
fmt::print(" ReferToBase: {}\n", variation_info[i].meta.empty());
|
2020-05-23 15:49:56 +00:00
|
|
|
if (variation_info[i].meta.empty() == false)
|
2020-02-26 09:03:43 +00:00
|
|
|
{
|
2021-09-30 11:41:57 +00:00
|
|
|
fmt::print(" ContentMeta:\n");
|
2020-05-23 15:49:56 +00:00
|
|
|
displayContentMetaInfoList(variation_info[i].meta, " ");
|
2020-02-26 09:03:43 +00:00
|
|
|
}
|
2020-05-23 15:49:56 +00:00
|
|
|
}
|
|
|
|
}
|
2021-10-01 12:46:47 +00:00
|
|
|
}
|
2020-05-23 15:49:56 +00:00
|
|
|
|
2021-09-30 11:41:57 +00:00
|
|
|
fmt::print(" Digest: {:s}\n", tc::cli::FormatUtil::formatBytesAsString(mCnmt.getDigest().data(), mCnmt.getDigest().size(), false, ""));
|
2020-05-23 15:49:56 +00:00
|
|
|
}
|
|
|
|
|
2021-09-28 11:15:54 +00:00
|
|
|
void nstool::CnmtProcess::displayContentMetaInfo(const nn::hac::ContentMetaInfo& content_meta_info, const std::string& prefix)
|
2020-05-23 15:49:56 +00:00
|
|
|
{
|
2021-09-30 11:41:57 +00:00
|
|
|
const nn::hac::sContentMetaInfo* content_meta_info_raw = (const nn::hac::sContentMetaInfo*)content_meta_info.getBytes().data();
|
|
|
|
fmt::print("{:s}Id: 0x{:016x}\n", prefix, content_meta_info.getTitleId());
|
|
|
|
fmt::print("{:s}Version: {:s} (v{:d})\n", prefix, nn::hac::ContentMetaUtil::getVersionAsString(content_meta_info.getTitleVersion()), content_meta_info.getTitleVersion());
|
|
|
|
fmt::print("{:s}Type: {:s} ({:d})\n", prefix, nn::hac::ContentMetaUtil::getContentMetaTypeAsString(content_meta_info.getContentMetaType()), (uint32_t)content_meta_info.getContentMetaType());
|
|
|
|
fmt::print("{:s}Attributes: 0x{:x}", prefix, *((byte_t*)&content_meta_info_raw->attributes) );
|
|
|
|
if (content_meta_info.getAttribute().size())
|
2020-05-23 15:49:56 +00:00
|
|
|
{
|
|
|
|
std::vector<std::string> attribute_list;
|
|
|
|
|
2021-09-30 11:41:57 +00:00
|
|
|
for (auto itr = content_meta_info.getAttribute().begin(); itr != content_meta_info.getAttribute().end(); itr++)
|
2020-05-23 15:49:56 +00:00
|
|
|
{
|
2021-09-30 11:41:57 +00:00
|
|
|
attribute_list.push_back(nn::hac::ContentMetaUtil::getContentMetaAttributeFlagAsString(nn::hac::cnmt::ContentMetaAttributeFlag(*itr)));
|
2020-05-23 15:49:56 +00:00
|
|
|
}
|
|
|
|
|
2021-09-30 11:41:57 +00:00
|
|
|
fmt::print(" [");
|
2020-05-23 15:49:56 +00:00
|
|
|
for (auto itr = attribute_list.begin(); itr != attribute_list.end(); itr++)
|
|
|
|
{
|
2021-09-30 11:41:57 +00:00
|
|
|
fmt::print("{:s}",*itr);
|
2020-05-23 15:49:56 +00:00
|
|
|
if ((itr + 1) != attribute_list.end())
|
|
|
|
{
|
2021-09-30 11:41:57 +00:00
|
|
|
fmt::print(", ");
|
2020-02-26 09:03:43 +00:00
|
|
|
}
|
2019-01-31 09:10:19 +00:00
|
|
|
}
|
2021-09-30 11:41:57 +00:00
|
|
|
fmt::print("]");
|
2019-01-31 09:10:19 +00:00
|
|
|
}
|
2021-09-30 11:41:57 +00:00
|
|
|
fmt::print("\n");
|
2020-05-23 15:49:56 +00:00
|
|
|
}
|
2019-01-31 09:10:19 +00:00
|
|
|
|
2021-09-28 11:15:54 +00:00
|
|
|
void nstool::CnmtProcess::displayContentMetaInfoList(const std::vector<nn::hac::ContentMetaInfo>& content_meta_info_list, const std::string& prefix)
|
2020-05-23 15:49:56 +00:00
|
|
|
{
|
|
|
|
for (size_t i = 0; i < content_meta_info_list.size(); i++)
|
2021-09-30 11:41:57 +00:00
|
|
|
{
|
|
|
|
const nn::hac::ContentMetaInfo& info = mCnmt.getContentMetaInfo()[i];
|
|
|
|
fmt::print("{:s}{:d}\n", i);
|
|
|
|
displayContentMetaInfo(info, prefix + " ");
|
|
|
|
}
|
2020-02-26 09:03:43 +00:00
|
|
|
}
|