mirror of https://github.com/AxioDL/nod.git
Wii image generation fixes
This commit is contained in:
parent
7403996ed3
commit
e9bac54e10
|
@ -8,7 +8,7 @@ static void printHelp()
|
||||||
fprintf(stderr, "Usage:\n"
|
fprintf(stderr, "Usage:\n"
|
||||||
" nodtool extract [-f] <image-in> [<dir-out>]\n"
|
" nodtool extract [-f] <image-in> [<dir-out>]\n"
|
||||||
" nodtool makegcn <gameid> <game-title> <fsroot-in> <dol-in> <apploader-in> [<image-out>]\n"
|
" nodtool makegcn <gameid> <game-title> <fsroot-in> <dol-in> <apploader-in> [<image-out>]\n"
|
||||||
" nodtool makewii <gameid> <game-title> <fsroot-in> <dol-in> <apploader-in> <parthead-in> [<image-out>]\n");
|
" nodtool makewii(sl|dl) <gameid> <game-title> <fsroot-in> <dol-in> <apploader-in> <parthead-in> [<image-out>]\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
#if NOD_UCS2
|
#if NOD_UCS2
|
||||||
|
@ -25,7 +25,8 @@ int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
if (argc < 3 ||
|
if (argc < 3 ||
|
||||||
(!strcasecmp(argv[1], _S("makegcn")) && argc < 7) ||
|
(!strcasecmp(argv[1], _S("makegcn")) && argc < 7) ||
|
||||||
(!strcasecmp(argv[1], _S("makewii")) && argc < 8))
|
(!strcasecmp(argv[1], _S("makewiisl")) && argc < 8) ||
|
||||||
|
(!strcasecmp(argv[1], _S("makewiidl")) && argc < 8))
|
||||||
{
|
{
|
||||||
printHelp();
|
printHelp();
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -55,10 +56,17 @@ int main(int argc, char* argv[])
|
||||||
|
|
||||||
if (!strcasecmp(argv[1], _S("extract")))
|
if (!strcasecmp(argv[1], _S("extract")))
|
||||||
{
|
{
|
||||||
std::unique_ptr<NOD::DiscBase> disc = NOD::OpenDiscFromImage(inDir);
|
bool isWii;
|
||||||
|
std::unique_ptr<NOD::DiscBase> disc = NOD::OpenDiscFromImage(inDir, isWii);
|
||||||
if (!disc)
|
if (!disc)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
NOD::Mkdir(outDir, 0755);
|
||||||
|
|
||||||
|
if (isWii)
|
||||||
|
static_cast<NOD::DiscWii&>(*disc).writeOutDataPartitionHeader(
|
||||||
|
(NOD::SystemString(outDir) + _S("/partition_head.bin")).c_str());
|
||||||
|
|
||||||
NOD::Partition* dataPart = disc->getDataPartition();
|
NOD::Partition* dataPart = disc->getDataPartition();
|
||||||
if (!dataPart)
|
if (!dataPart)
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -115,7 +123,7 @@ int main(int argc, char* argv[])
|
||||||
|
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
else if (!strcasecmp(argv[1], _S("makewii")))
|
else if (!strcasecmp(argv[1], _S("makewiisl")) || !strcasecmp(argv[1], _S("makewiidl")))
|
||||||
{
|
{
|
||||||
#if NOD_UCS2
|
#if NOD_UCS2
|
||||||
if (_wcslen(argv[2]) < 6)
|
if (_wcslen(argv[2]) < 6)
|
||||||
|
@ -151,16 +159,18 @@ int main(int argc, char* argv[])
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool dual = (argv[1][7] == _S('d') || argv[1][7] == _S('D'));
|
||||||
|
|
||||||
if (argc < 9)
|
if (argc < 9)
|
||||||
{
|
{
|
||||||
NOD::SystemString outPath(argv[4]);
|
NOD::SystemString outPath(argv[4]);
|
||||||
outPath.append(_S(".iso"));
|
outPath.append(_S(".iso"));
|
||||||
NOD::DiscBuilderWii b(outPath.c_str(), argv[2], argv[3], progFunc);
|
NOD::DiscBuilderWii b(outPath.c_str(), argv[2], argv[3], dual, progFunc);
|
||||||
b.buildFromDirectory(argv[4], argv[5], argv[6], argv[7]);
|
b.buildFromDirectory(argv[4], argv[5], argv[6], argv[7]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
NOD::DiscBuilderWii b(argv[8], argv[2], argv[3], progFunc);
|
NOD::DiscBuilderWii b(argv[8], argv[2], argv[3], dual, progFunc);
|
||||||
b.buildFromDirectory(argv[4], argv[5], argv[6], argv[7]);
|
b.buildFromDirectory(argv[4], argv[5], argv[6], argv[7]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -229,6 +229,7 @@ public:
|
||||||
: m_parent(parent), m_kind(kind), m_offset(offset) {}
|
: m_parent(parent), m_kind(kind), m_offset(offset) {}
|
||||||
virtual uint64_t normalizeOffset(uint64_t anOffset) const {return anOffset;}
|
virtual uint64_t normalizeOffset(uint64_t anOffset) const {return anOffset;}
|
||||||
inline Kind getKind() const {return m_kind;}
|
inline Kind getKind() const {return m_kind;}
|
||||||
|
inline uint64_t getDiscOffset() const {return m_offset;}
|
||||||
virtual std::unique_ptr<IPartReadStream> beginReadStream(uint64_t offset=0) const=0;
|
virtual std::unique_ptr<IPartReadStream> beginReadStream(uint64_t offset=0) const=0;
|
||||||
inline std::unique_ptr<IPartReadStream> beginDOLReadStream(uint64_t offset=0) const
|
inline std::unique_ptr<IPartReadStream> beginDOLReadStream(uint64_t offset=0) const
|
||||||
{return beginReadStream(m_dolOff + offset);}
|
{return beginReadStream(m_dolOff + offset);}
|
||||||
|
@ -314,6 +315,7 @@ public:
|
||||||
std::vector<std::string> m_buildNames;
|
std::vector<std::string> m_buildNames;
|
||||||
size_t m_buildNameOff = 0;
|
size_t m_buildNameOff = 0;
|
||||||
virtual uint64_t userAllocate(uint64_t reqSz)=0;
|
virtual uint64_t userAllocate(uint64_t reqSz)=0;
|
||||||
|
virtual uint32_t packOffset(uint64_t offset) const=0;
|
||||||
void recursiveBuildNodes(const SystemChar* dirIn, uint64_t dolInode,
|
void recursiveBuildNodes(const SystemChar* dirIn, uint64_t dolInode,
|
||||||
std::function<void(void)> incParents);
|
std::function<void(void)> incParents);
|
||||||
void addBuildName(const SystemString& str)
|
void addBuildName(const SystemString& str)
|
||||||
|
@ -329,6 +331,7 @@ public:
|
||||||
char m_gameID[6];
|
char m_gameID[6];
|
||||||
std::string m_gameTitle;
|
std::string m_gameTitle;
|
||||||
uint64_t m_dolOffset = 0;
|
uint64_t m_dolOffset = 0;
|
||||||
|
uint64_t m_dolSize = 0;
|
||||||
public:
|
public:
|
||||||
IPartitionBuilder(DiscBuilderBase& parent, Kind kind,
|
IPartitionBuilder(DiscBuilderBase& parent, Kind kind,
|
||||||
const char gameID[6], const char* gameTitle)
|
const char gameID[6], const char* gameTitle)
|
||||||
|
@ -338,6 +341,9 @@ public:
|
||||||
}
|
}
|
||||||
bool buildFromDirectory(const SystemChar* dirIn, const SystemChar* dolIn,
|
bool buildFromDirectory(const SystemChar* dirIn, const SystemChar* dolIn,
|
||||||
const SystemChar* apploaderIn);
|
const SystemChar* apploaderIn);
|
||||||
|
|
||||||
|
const char* getGameID() const {return m_gameID;}
|
||||||
|
const std::string& getGameTitle() const {return m_gameTitle;}
|
||||||
};
|
};
|
||||||
protected:
|
protected:
|
||||||
std::unique_ptr<IFileIO> m_fileIO;
|
std::unique_ptr<IFileIO> m_fileIO;
|
||||||
|
|
|
@ -10,13 +10,15 @@ class DiscWii : public DiscBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DiscWii(std::unique_ptr<IDiscIO>&& dio);
|
DiscWii(std::unique_ptr<IDiscIO>&& dio);
|
||||||
|
void writeOutDataPartitionHeader(const SystemChar* pathOut) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DiscBuilderWii : public DiscBuilderBase
|
class DiscBuilderWii : public DiscBuilderBase
|
||||||
{
|
{
|
||||||
const SystemChar* m_outPath;
|
const SystemChar* m_outPath;
|
||||||
|
bool m_dualLayer;
|
||||||
public:
|
public:
|
||||||
DiscBuilderWii(const SystemChar* outPath, const char gameID[6], const char* gameTitle,
|
DiscBuilderWii(const SystemChar* outPath, const char gameID[6], const char* gameTitle, bool dualLayer,
|
||||||
std::function<void(size_t, const SystemString&, size_t)> progressCB);
|
std::function<void(size_t, const SystemString&, size_t)> progressCB);
|
||||||
bool buildFromDirectory(const SystemChar* dirIn, const SystemChar* dolIn,
|
bool buildFromDirectory(const SystemChar* dirIn, const SystemChar* dolIn,
|
||||||
const SystemChar* apploaderIn, const SystemChar* partHeadIn);
|
const SystemChar* apploaderIn, const SystemChar* partHeadIn);
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#else
|
#else
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <sys/file.h>
|
#include <sys/file.h>
|
||||||
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
@ -102,6 +103,15 @@ public:
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static inline void Unlink(const SystemChar* file)
|
||||||
|
{
|
||||||
|
#if _WIN32
|
||||||
|
_wunlink(file);
|
||||||
|
#else
|
||||||
|
unlink(file);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
#undef bswap16
|
#undef bswap16
|
||||||
#undef bswap32
|
#undef bswap32
|
||||||
#undef bswap64
|
#undef bswap64
|
||||||
|
|
|
@ -121,11 +121,11 @@ bool DiscBase::IPartition::extractToDirectory(const SystemString& path,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Extract Dol */
|
/* Extract Dol */
|
||||||
SystemString dolPath = path + _S("/main.dol");
|
SystemString dolPath = path + _S("/boot.dol");
|
||||||
if (ctx.force || Stat(dolPath.c_str(), &theStat))
|
if (ctx.force || Stat(dolPath.c_str(), &theStat))
|
||||||
{
|
{
|
||||||
if (ctx.verbose && ctx.progressCB)
|
if (ctx.verbose && ctx.progressCB)
|
||||||
ctx.progressCB("main.dol");
|
ctx.progressCB("boot.dol");
|
||||||
std::unique_ptr<uint8_t[]> buf = getDOLBuf();
|
std::unique_ptr<uint8_t[]> buf = getDOLBuf();
|
||||||
NewFileIO(dolPath)->beginWriteStream()->write(buf.get(), m_dolSz);
|
NewFileIO(dolPath)->beginWriteStream()->write(buf.get(), m_dolSz);
|
||||||
}
|
}
|
||||||
|
@ -174,20 +174,26 @@ void DiscBuilderBase::IPartitionBuilder::recursiveBuildNodes(const SystemChar* d
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if (dolInode == GetInode(e.m_path.c_str()))
|
||||||
|
{
|
||||||
|
m_buildNodes.emplace_back(false, m_buildNameOff, packOffset(m_dolOffset), m_dolSize);
|
||||||
|
addBuildName(e.m_name);
|
||||||
|
incParents();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
size_t fileSz = ROUND_UP_32(e.m_fileSz);
|
size_t fileSz = ROUND_UP_32(e.m_fileSz);
|
||||||
uint64_t fileOff = userAllocate(fileSz);
|
uint64_t fileOff = userAllocate(fileSz);
|
||||||
if (dolInode == GetInode(e.m_path.c_str()))
|
|
||||||
m_dolOffset = fileOff;
|
|
||||||
std::unique_ptr<IFileIO::IWriteStream> ws = m_parent.getFileIO().beginWriteStream(fileOff);
|
std::unique_ptr<IFileIO::IWriteStream> ws = m_parent.getFileIO().beginWriteStream(fileOff);
|
||||||
FILE* fp = Fopen(e.m_path.c_str(), _S("rb"), FileLockType::Read);
|
FILE* fp = Fopen(e.m_path.c_str(), _S("rb"), FileLockType::Read);
|
||||||
if (!fp)
|
if (!fp)
|
||||||
LogModule.report(LogVisor::FatalError, _S("unable to open '%s' for reading"), e.m_path.c_str());
|
LogModule.report(LogVisor::FatalError, _S("unable to open '%s' for reading"), e.m_path.c_str());
|
||||||
char buf[8192];
|
char buf[0x8000];
|
||||||
size_t xferSz = 0;
|
size_t xferSz = 0;
|
||||||
++m_parent.m_progressIdx;
|
++m_parent.m_progressIdx;
|
||||||
while (xferSz < e.m_fileSz)
|
while (xferSz < e.m_fileSz)
|
||||||
{
|
{
|
||||||
size_t rdSz = fread(buf, 1, std::min(8192ul, e.m_fileSz - xferSz), fp);
|
size_t rdSz = fread(buf, 1, std::min(0x8000ul, e.m_fileSz - xferSz), fp);
|
||||||
if (!rdSz)
|
if (!rdSz)
|
||||||
break;
|
break;
|
||||||
ws->write(buf, rdSz);
|
ws->write(buf, rdSz);
|
||||||
|
@ -197,7 +203,7 @@ void DiscBuilderBase::IPartitionBuilder::recursiveBuildNodes(const SystemChar* d
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
for (size_t i=0 ; i<fileSz-xferSz ; ++i)
|
for (size_t i=0 ; i<fileSz-xferSz ; ++i)
|
||||||
ws->write("\xff", 1);
|
ws->write("\xff", 1);
|
||||||
m_buildNodes.emplace_back(false, m_buildNameOff, fileOff, fileSz);
|
m_buildNodes.emplace_back(false, m_buildNameOff, packOffset(fileOff), fileSz);
|
||||||
addBuildName(e.m_name);
|
addBuildName(e.m_name);
|
||||||
incParents();
|
incParents();
|
||||||
}
|
}
|
||||||
|
@ -216,11 +222,11 @@ bool DiscBuilderBase::IPartitionBuilder::buildFromDirectory(const SystemChar* di
|
||||||
++m_parent.m_progressIdx;
|
++m_parent.m_progressIdx;
|
||||||
m_parent.m_progressCB(m_parent.m_progressIdx, "Preparing output image", -1);
|
m_parent.m_progressCB(m_parent.m_progressIdx, "Preparing output image", -1);
|
||||||
|
|
||||||
|
/* Add root node */
|
||||||
m_buildNodes.emplace_back(true, m_buildNameOff, 0, 1);
|
m_buildNodes.emplace_back(true, m_buildNameOff, 0, 1);
|
||||||
addBuildName(_S("<root>"));
|
addBuildName(_S("<root>"));
|
||||||
recursiveBuildNodes(dirIn, GetInode(dolIn), [&](){m_buildNodes[0].incrementLength();});
|
|
||||||
|
|
||||||
if (!m_dolOffset)
|
/* Write DOL first (ensures that it's within a 32-bit offset for Wii apploaders) */
|
||||||
{
|
{
|
||||||
Sstat dolStat;
|
Sstat dolStat;
|
||||||
if (Stat(dolIn, &dolStat))
|
if (Stat(dolIn, &dolStat))
|
||||||
|
@ -228,6 +234,7 @@ bool DiscBuilderBase::IPartitionBuilder::buildFromDirectory(const SystemChar* di
|
||||||
size_t fileSz = ROUND_UP_32(dolStat.st_size);
|
size_t fileSz = ROUND_UP_32(dolStat.st_size);
|
||||||
uint64_t fileOff = userAllocate(fileSz);
|
uint64_t fileOff = userAllocate(fileSz);
|
||||||
m_dolOffset = fileOff;
|
m_dolOffset = fileOff;
|
||||||
|
m_dolSize = fileSz;
|
||||||
std::unique_ptr<IFileIO::IWriteStream> ws = m_parent.getFileIO().beginWriteStream(fileOff);
|
std::unique_ptr<IFileIO::IWriteStream> ws = m_parent.getFileIO().beginWriteStream(fileOff);
|
||||||
FILE* fp = Fopen(dolIn, _S("rb"), FileLockType::Read);
|
FILE* fp = Fopen(dolIn, _S("rb"), FileLockType::Read);
|
||||||
if (!fp)
|
if (!fp)
|
||||||
|
@ -250,6 +257,9 @@ bool DiscBuilderBase::IPartitionBuilder::buildFromDirectory(const SystemChar* di
|
||||||
ws->write("\xff", 1);
|
ws->write("\xff", 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Gather files in root directory */
|
||||||
|
recursiveBuildNodes(dirIn, GetInode(dolIn), [&](){m_buildNodes[0].incrementLength();});
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -130,6 +130,11 @@ public:
|
||||||
return m_curUser;
|
return m_curUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t packOffset(uint64_t offset) const
|
||||||
|
{
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
bool buildFromDirectory(const SystemChar* dirIn, const SystemChar* dolIn, const SystemChar* apploaderIn)
|
bool buildFromDirectory(const SystemChar* dirIn, const SystemChar* dolIn, const SystemChar* apploaderIn)
|
||||||
{
|
{
|
||||||
bool result = DiscBuilderBase::IPartitionBuilder::buildFromDirectory(dirIn, dolIn, apploaderIn);
|
bool result = DiscBuilderBase::IPartitionBuilder::buildFromDirectory(dirIn, dolIn, apploaderIn);
|
||||||
|
|
119
lib/DiscWii.cpp
119
lib/DiscWii.cpp
|
@ -339,6 +339,36 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t normalizeOffset(uint64_t anOffset) const {return anOffset << 2;}
|
uint64_t normalizeOffset(uint64_t anOffset) const {return anOffset << 2;}
|
||||||
|
|
||||||
|
void writeOutPartitionHeader(const SystemChar* pathOut) const
|
||||||
|
{
|
||||||
|
FILE* fp = Fopen(pathOut, _S("wb"), FileLockType::Write);
|
||||||
|
if (!fp)
|
||||||
|
LogModule.report(LogVisor::FatalError, _S("unable to open %s for writing"), pathOut);
|
||||||
|
|
||||||
|
uint64_t h3Off;
|
||||||
|
{
|
||||||
|
std::unique_ptr<IDiscIO::IReadStream> rs = m_parent.getDiscIO().beginReadStream(m_offset + 0x2B4);
|
||||||
|
uint32_t h3;
|
||||||
|
if (rs->read(&h3, 4) != 4)
|
||||||
|
LogModule.report(LogVisor::FatalError, _S("unable to read H3 offset from %s"), pathOut);
|
||||||
|
h3 = SBig(h3);
|
||||||
|
h3Off = uint64_t(h3) << 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
char buf[8192];
|
||||||
|
size_t rem = h3Off;
|
||||||
|
std::unique_ptr<IDiscIO::IReadStream> rs = m_parent.getDiscIO().beginReadStream(m_offset);
|
||||||
|
while (rem)
|
||||||
|
{
|
||||||
|
size_t rdSz = std::min(rem, 8192ul);
|
||||||
|
rs->read(buf, rdSz);
|
||||||
|
fwrite(buf, 1, rdSz, fp);
|
||||||
|
rem -= rdSz;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
DiscWii::DiscWii(std::unique_ptr<IDiscIO>&& dio)
|
DiscWii::DiscWii(std::unique_ptr<IDiscIO>&& dio)
|
||||||
|
@ -391,9 +421,21 @@ DiscWii::DiscWii(std::unique_ptr<IDiscIO>&& dio)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DiscWii::writeOutDataPartitionHeader(const SystemChar* pathOut) const
|
||||||
|
{
|
||||||
|
for (const std::unique_ptr<IPartition>& part : m_partitions)
|
||||||
|
{
|
||||||
|
if (part->getKind() == IPartition::Kind::Data)
|
||||||
|
{
|
||||||
|
static_cast<PartitionWii&>(*part).writeOutPartitionHeader(pathOut);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class PartitionBuilderWii : public DiscBuilderBase::IPartitionBuilder
|
class PartitionBuilderWii : public DiscBuilderBase::IPartitionBuilder
|
||||||
{
|
{
|
||||||
uint64_t m_curUser = 0x40000;
|
uint64_t m_curUser = 0x1F0000;
|
||||||
public:
|
public:
|
||||||
PartitionBuilderWii(DiscBuilderBase& parent, Kind kind,
|
PartitionBuilderWii(DiscBuilderBase& parent, Kind kind,
|
||||||
const char gameID[6], const char* gameTitle)
|
const char gameID[6], const char* gameTitle)
|
||||||
|
@ -414,6 +456,11 @@ public:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t packOffset(uint64_t offset) const
|
||||||
|
{
|
||||||
|
return uint32_t(offset >> uint64_t(2));
|
||||||
|
}
|
||||||
|
|
||||||
bool buildFromDirectory(const SystemChar* dirIn, const SystemChar* dolIn, const SystemChar* apploaderIn)
|
bool buildFromDirectory(const SystemChar* dirIn, const SystemChar* dolIn, const SystemChar* apploaderIn)
|
||||||
{
|
{
|
||||||
bool result = DiscBuilderBase::IPartitionBuilder::buildFromDirectory(dirIn, dolIn, apploaderIn);
|
bool result = DiscBuilderBase::IPartitionBuilder::buildFromDirectory(dirIn, dolIn, apploaderIn);
|
||||||
|
@ -434,7 +481,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
ws = m_parent.getFileIO().beginWriteStream(0);
|
ws = m_parent.getFileIO().beginWriteStream(0);
|
||||||
Header header(m_gameID, m_gameTitle.c_str(), true);
|
Header header(m_gameID, m_gameTitle.c_str(), true, 0, 0, 0);
|
||||||
header.write(*ws);
|
header.write(*ws);
|
||||||
|
|
||||||
ws = m_parent.getFileIO().beginWriteStream(0x2440);
|
ws = m_parent.getFileIO().beginWriteStream(0x2440);
|
||||||
|
@ -452,7 +499,7 @@ public:
|
||||||
break;
|
break;
|
||||||
ws->write(buf, rdSz);
|
ws->write(buf, rdSz);
|
||||||
xferSz += rdSz;
|
xferSz += rdSz;
|
||||||
if (0x2440 + xferSz >= 0x40000)
|
if (0x2440 + xferSz >= 0x1F0000)
|
||||||
LogModule.report(LogVisor::FatalError,
|
LogModule.report(LogVisor::FatalError,
|
||||||
"apploader flows into user area (one or the other is too big)");
|
"apploader flows into user area (one or the other is too big)");
|
||||||
m_parent.m_progressCB(m_parent.m_progressIdx, apploaderName, xferSz);
|
m_parent.m_progressCB(m_parent.m_progressIdx, apploaderName, xferSz);
|
||||||
|
@ -470,14 +517,14 @@ public:
|
||||||
fstSz += m_buildNameOff;
|
fstSz += m_buildNameOff;
|
||||||
fstSz = ROUND_UP_32(fstSz);
|
fstSz = ROUND_UP_32(fstSz);
|
||||||
|
|
||||||
if (fstOff + fstSz >= 0x40000)
|
if (fstOff + fstSz >= 0x1F0000)
|
||||||
LogModule.report(LogVisor::FatalError,
|
LogModule.report(LogVisor::FatalError,
|
||||||
"FST flows into user area (one or the other is too big)");
|
"FST flows into user area (one or the other is too big)");
|
||||||
|
|
||||||
ws = m_parent.getFileIO().beginWriteStream(0x420);
|
ws = m_parent.getFileIO().beginWriteStream(0x420);
|
||||||
uint32_t vals[4];
|
uint32_t vals[4];
|
||||||
vals[0] = SBig(uint32_t(m_dolOffset >> 2));
|
vals[0] = SBig(uint32_t(m_dolOffset >> uint64_t(2)));
|
||||||
vals[1] = SBig(uint32_t(fstOff >> 2));
|
vals[1] = SBig(uint32_t(fstOff >> uint64_t(2)));
|
||||||
vals[2] = SBig(uint32_t(fstSz));
|
vals[2] = SBig(uint32_t(fstSz));
|
||||||
vals[3] = SBig(uint32_t(fstSz));
|
vals[3] = SBig(uint32_t(fstSz));
|
||||||
ws->write(vals, sizeof(vals));
|
ws->write(vals, sizeof(vals));
|
||||||
|
@ -659,7 +706,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write new crypto content size */
|
/* Write new crypto content size */
|
||||||
uint64_t cryptContentSize = (groupCount * 0x200000) >> 2;
|
uint64_t cryptContentSize = (groupCount * 0x200000) >> uint64_t(2);
|
||||||
uint32_t cryptContentSizeBig = SBig(uint32_t(cryptContentSize));
|
uint32_t cryptContentSizeBig = SBig(uint32_t(cryptContentSize));
|
||||||
ws = out.beginWriteStream(offset + 0x2BC);
|
ws = out.beginWriteStream(offset + 0x2BC);
|
||||||
ws->write(&cryptContentSizeBig, 0x4);
|
ws->write(&cryptContentSizeBig, 0x4);
|
||||||
|
@ -699,13 +746,12 @@ public:
|
||||||
sha1_init(&sha);
|
sha1_init(&sha);
|
||||||
sha1_write(&sha, (char*)(tmdData.get() + 0x140), tmdCheckSz);
|
sha1_write(&sha, (char*)(tmdData.get() + 0x140), tmdCheckSz);
|
||||||
uint8_t* hash = sha1_result(&sha);
|
uint8_t* hash = sha1_result(&sha);
|
||||||
|
++attempts;
|
||||||
if (hash[0] == 0)
|
if (hash[0] == 0)
|
||||||
{
|
{
|
||||||
good = true;
|
good = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
++attempts;
|
|
||||||
if ((attempts % 1024) == 0)
|
|
||||||
m_parent.m_progressCB(m_parent.m_progressIdx, bfName, attempts);
|
m_parent.m_progressCB(m_parent.m_progressIdx, bfName, attempts);
|
||||||
}
|
}
|
||||||
if (good)
|
if (good)
|
||||||
|
@ -723,32 +769,75 @@ public:
|
||||||
bool DiscBuilderWii::buildFromDirectory(const SystemChar* dirIn, const SystemChar* dolIn,
|
bool DiscBuilderWii::buildFromDirectory(const SystemChar* dirIn, const SystemChar* dolIn,
|
||||||
const SystemChar* apploaderIn, const SystemChar* partHeadIn)
|
const SystemChar* apploaderIn, const SystemChar* partHeadIn)
|
||||||
{
|
{
|
||||||
|
size_t DISC_CAPACITY = m_dualLayer ? 0x1FB4E0000 : 0x118240000;
|
||||||
|
|
||||||
PartitionBuilderWii& pb = static_cast<PartitionBuilderWii&>(*m_partitions[0]);
|
PartitionBuilderWii& pb = static_cast<PartitionBuilderWii&>(*m_partitions[0]);
|
||||||
uint64_t filledSz = 0x200000;
|
uint64_t filledSz = 0x200000;
|
||||||
std::unique_ptr<IFileIO> imgOut = NewFileIO(m_outPath);
|
std::unique_ptr<IFileIO> imgOut = NewFileIO(m_outPath);
|
||||||
|
imgOut->beginWriteStream();
|
||||||
|
|
||||||
m_fileIO = std::move(NewFileIO(SystemString(m_outPath) + _S(".cleardata")));
|
/* Assemble cleartext data partition into temporary file */
|
||||||
|
SystemString clearPath(m_outPath);
|
||||||
|
clearPath += _S(".cleardata");
|
||||||
|
m_fileIO = std::move(NewFileIO(clearPath));
|
||||||
if (!pb.buildFromDirectory(dirIn, dolIn, apploaderIn))
|
if (!pb.buildFromDirectory(dirIn, dolIn, apploaderIn))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
/* Fakesign cleartext into output file */
|
||||||
filledSz = pb.cryptAndFakesign(*imgOut, filledSz, partHeadIn);
|
filledSz = pb.cryptAndFakesign(*imgOut, filledSz, partHeadIn);
|
||||||
if (filledSz >= 0x1FB4E0000)
|
if (filledSz >= DISC_CAPACITY)
|
||||||
{
|
{
|
||||||
LogModule.report(LogVisor::FatalError, "data partition exceeds disc capacity");
|
LogModule.report(LogVisor::FatalError, "data partition exceeds disc capacity");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
++m_progressIdx;
|
||||||
|
m_progressCB(m_progressIdx, "Finishing Disc", -1);
|
||||||
|
|
||||||
|
/* Populate disc header */
|
||||||
|
std::unique_ptr<IFileIO::IWriteStream> ws = imgOut->beginWriteStream(0);
|
||||||
|
Header header(pb.getGameID(), pb.getGameTitle().c_str(), true, 0, 0, 0);
|
||||||
|
header.write(*ws);
|
||||||
|
|
||||||
|
/* Populate partition info */
|
||||||
|
ws = imgOut->beginWriteStream(0x40000);
|
||||||
|
uint32_t vals[2] = {SBig(uint32_t(1)), SBig(uint32_t(0x40020 >> uint64_t(2)))};
|
||||||
|
ws->write(vals, 8);
|
||||||
|
|
||||||
|
ws = imgOut->beginWriteStream(0x40020);
|
||||||
|
vals[0] = SBig(uint32_t(0x200000 >> uint64_t(2)));
|
||||||
|
ws->write(vals, 4);
|
||||||
|
|
||||||
|
/* Populate region info */
|
||||||
|
ws = imgOut->beginWriteStream(0x4E000);
|
||||||
|
const char* gameID = pb.getGameID();
|
||||||
|
if (gameID[3] == 'P')
|
||||||
|
vals[0] = SBig(uint32_t(2));
|
||||||
|
else if (gameID[3] == 'J')
|
||||||
|
vals[0] = SBig(uint32_t(0));
|
||||||
|
else
|
||||||
|
vals[0] = SBig(uint32_t(1));
|
||||||
|
ws->write(vals, 4);
|
||||||
|
|
||||||
|
/* Make disc unrated */
|
||||||
|
ws = imgOut->beginWriteStream(0x4E010);
|
||||||
|
for (int i=0 ; i<16 ; ++i)
|
||||||
|
ws->write("\x80", 1);
|
||||||
|
|
||||||
/* Fill image to end */
|
/* Fill image to end */
|
||||||
std::unique_ptr<IFileIO::IWriteStream> ws = imgOut->beginWriteStream(filledSz);
|
ws = imgOut->beginWriteStream(filledSz);
|
||||||
for (size_t i=0 ; i<0x1FB4E0000-filledSz ; ++i)
|
for (size_t i=0 ; i<DISC_CAPACITY-filledSz ; ++i)
|
||||||
ws->write("\xff", 1);
|
ws->write("\xff", 1);
|
||||||
|
|
||||||
|
/* Delete cleartext file */
|
||||||
|
Unlink(clearPath.c_str());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
DiscBuilderWii::DiscBuilderWii(const SystemChar* outPath, const char gameID[6], const char* gameTitle,
|
DiscBuilderWii::DiscBuilderWii(const SystemChar* outPath, const char gameID[6], const char* gameTitle, bool dualLayer,
|
||||||
std::function<void(size_t, const SystemString&, size_t)> progressCB)
|
std::function<void(size_t, const SystemString&, size_t)> progressCB)
|
||||||
: DiscBuilderBase(std::move(std::unique_ptr<IFileIO>()), progressCB), m_outPath(outPath)
|
: DiscBuilderBase(std::move(std::unique_ptr<IFileIO>()), progressCB), m_outPath(outPath), m_dualLayer(dualLayer)
|
||||||
{
|
{
|
||||||
PartitionBuilderWii* partBuilder = new PartitionBuilderWii(*this, IPartitionBuilder::Kind::Data,
|
PartitionBuilderWii* partBuilder = new PartitionBuilderWii(*this, IPartitionBuilder::Kind::Data,
|
||||||
gameID, gameTitle);
|
gameID, gameTitle);
|
||||||
|
|
|
@ -56,8 +56,12 @@ public:
|
||||||
WriteStream(const SystemString& path, uint64_t offset)
|
WriteStream(const SystemString& path, uint64_t offset)
|
||||||
{
|
{
|
||||||
#if NOD_UCS2
|
#if NOD_UCS2
|
||||||
|
fp = _wfopen(path.c_str(), L"ab");
|
||||||
|
fclose(fp);
|
||||||
fp = _wfopen(path.c_str(), L"r+b");
|
fp = _wfopen(path.c_str(), L"r+b");
|
||||||
#else
|
#else
|
||||||
|
fp = fopen(path.c_str(), "ab");
|
||||||
|
fclose(fp);
|
||||||
fp = fopen(path.c_str(), "r+b");
|
fp = fopen(path.c_str(), "r+b");
|
||||||
#endif
|
#endif
|
||||||
if (!fp)
|
if (!fp)
|
||||||
|
|
Loading…
Reference in New Issue