New code style refactor

This commit is contained in:
Jack Andersen 2018-12-07 19:21:47 -10:00
parent 3d380fdc3b
commit be8409681f
21 changed files with 4545 additions and 5221 deletions

View File

@ -3,14 +3,14 @@
#include "logvisor/logvisor.hpp" #include "logvisor/logvisor.hpp"
#include "nod/nod.hpp" #include "nod/nod.hpp"
static void printHelp() static void printHelp() {
{ fprintf(stderr,
fprintf(stderr, "Usage:\n" "Usage:\n"
" nodtool extract [-f] <image-in> [<dir-out>]\n" " nodtool extract [-f] <image-in> [<dir-out>]\n"
" nodtool makegcn <fsroot-in> [<image-out>]\n" " nodtool makegcn <fsroot-in> [<image-out>]\n"
" nodtool makewii <fsroot-in> [<image-out>]\n" " nodtool makewii <fsroot-in> [<image-out>]\n"
" nodtool mergegcn <fsroot-in> <image-in> [<image-out>]\n" " nodtool mergegcn <fsroot-in> <image-in> [<image-out>]\n"
" nodtool mergewii <fsroot-in> <image-in> [<image-out>]\n"); " nodtool mergewii <fsroot-in> <image-in> [<image-out>]\n");
} }
#if NOD_UCS2 #if NOD_UCS2
@ -25,241 +25,203 @@ int wmain(int argc, wchar_t* argv[])
int main(int argc, char* argv[]) int main(int argc, char* argv[])
#endif #endif
{ {
if (argc < 3 || if (argc < 3 || (!strcasecmp(argv[1], _SYS_STR("makegcn")) && argc < 3) ||
(!strcasecmp(argv[1], _SYS_STR("makegcn")) && argc < 3) || (!strcasecmp(argv[1], _SYS_STR("makewii")) && argc < 3) ||
(!strcasecmp(argv[1], _SYS_STR("makewii")) && argc < 3) || (!strcasecmp(argv[1], _SYS_STR("mergegcn")) && argc < 4) ||
(!strcasecmp(argv[1], _SYS_STR("mergegcn")) && argc < 4) || (!strcasecmp(argv[1], _SYS_STR("mergewii")) && argc < 4)) {
(!strcasecmp(argv[1], _SYS_STR("mergewii")) && argc < 4)) printHelp();
{ return 1;
printHelp(); }
return 1;
}
/* Enable logging to console */ /* Enable logging to console */
logvisor::RegisterStandardExceptions(); logvisor::RegisterStandardExceptions();
logvisor::RegisterConsoleLogger(); logvisor::RegisterConsoleLogger();
bool verbose = false; bool verbose = false;
nod::ExtractionContext ctx = {true, nod::ExtractionContext ctx = {true, [&](std::string_view str, float c) {
[&](std::string_view str, float c) { if (verbose)
if (verbose) fprintf(stderr, "Current node: %s, Extraction %g%% Complete\n", str.data(),
fprintf(stderr, "Current node: %s, Extraction %g%% Complete\n", str.data(), c * 100.f); c * 100.f);
}}; }};
const nod::SystemChar* inDir = nullptr; const nod::SystemChar* inDir = nullptr;
const nod::SystemChar* outDir = _SYS_STR("."); const nod::SystemChar* outDir = _SYS_STR(".");
for (int a=2 ; a<argc ; ++a) for (int a = 2; a < argc; ++a) {
{ if (argv[a][0] == '-' && argv[a][1] == 'f')
if (argv[a][0] == '-' && argv[a][1] == 'f') ctx.force = true;
ctx.force = true; else if (argv[a][0] == '-' && argv[a][1] == 'v')
else if (argv[a][0] == '-' && argv[a][1] == 'v') verbose = true;
verbose = true;
else if (!inDir) else if (!inDir)
inDir = argv[a]; inDir = argv[a];
else
outDir = argv[a];
}
auto progFunc = [&](float prog, nod::SystemStringView name, size_t bytes)
{
nod::Printf(_SYS_STR("\r "));
if (bytes != -1)
nod::Printf(_SYS_STR("\r%g%% %s %" PRISize " B"), prog * 100.f, name.data(), bytes);
else
nod::Printf(_SYS_STR("\r%g%% %s"), prog * 100.f, name.data());
fflush(stdout);
};
if (!strcasecmp(argv[1], _SYS_STR("extract")))
{
bool isWii;
std::unique_ptr<nod::DiscBase> disc = nod::OpenDiscFromImage(inDir, isWii);
if (!disc)
return 1;
nod::Mkdir(outDir, 0755);
nod::IPartition* dataPart = disc->getDataPartition();
if (!dataPart)
return 1;
if (!dataPart->extractToDirectory(outDir, ctx))
return 1;
}
else if (!strcasecmp(argv[1], _SYS_STR("makegcn")))
{
/* Pre-validate path */
nod::Sstat theStat;
if (nod::Stat(argv[2], &theStat) || !S_ISDIR(theStat.st_mode))
{
nod::LogModule.report(logvisor::Error, _SYS_STR("unable to stat %s as directory"), argv[2]);
return 1;
}
if (nod::DiscBuilderGCN::CalculateTotalSizeRequired(argv[2]) == -1)
return 1;
nod::EBuildResult ret;
if (argc < 4)
{
nod::SystemString outPath(argv[2]);
outPath.append(_SYS_STR(".iso"));
nod::DiscBuilderGCN b(outPath, progFunc);
ret = b.buildFromDirectory(argv[2]);
}
else
{
nod::DiscBuilderGCN b(argv[3], progFunc);
ret = b.buildFromDirectory(argv[2]);
}
printf("\n");
if (ret != nod::EBuildResult::Success)
return 1;
}
else if (!strcasecmp(argv[1], _SYS_STR("makewii")))
{
/* Pre-validate path */
nod::Sstat theStat;
if (nod::Stat(argv[2], &theStat) || !S_ISDIR(theStat.st_mode))
{
nod::LogModule.report(logvisor::Error, _SYS_STR("unable to stat %s as directory"), argv[4]);
return 1;
}
bool dual = false;
if (nod::DiscBuilderWii::CalculateTotalSizeRequired(argv[2], dual) == -1)
return 1;
nod::EBuildResult ret;
if (argc < 4)
{
nod::SystemString outPath(argv[2]);
outPath.append(_SYS_STR(".iso"));
nod::DiscBuilderWii b(outPath.c_str(), dual, progFunc);
ret = b.buildFromDirectory(argv[2]);
}
else
{
nod::DiscBuilderWii b(argv[3], dual, progFunc);
ret = b.buildFromDirectory(argv[2]);
}
printf("\n");
if (ret != nod::EBuildResult::Success)
return 1;
}
else if (!strcasecmp(argv[1], _SYS_STR("mergegcn")))
{
/* Pre-validate paths */
nod::Sstat theStat;
if (nod::Stat(argv[2], &theStat) || !S_ISDIR(theStat.st_mode))
{
nod::LogModule.report(logvisor::Error, _SYS_STR("unable to stat %s as directory"), argv[2]);
return 1;
}
if (nod::Stat(argv[3], &theStat) || !S_ISREG(theStat.st_mode))
{
nod::LogModule.report(logvisor::Error, _SYS_STR("unable to stat %s as file"), argv[3]);
return 1;
}
bool isWii;
std::unique_ptr<nod::DiscBase> disc = nod::OpenDiscFromImage(argv[3], isWii);
if (!disc)
{
nod::LogModule.report(logvisor::Error, _SYS_STR("unable to open image %s"), argv[3]);
return 1;
}
if (isWii)
{
nod::LogModule.report(logvisor::Error, _SYS_STR("Wii images should be merged with 'mergewii'"));
return 1;
}
if (nod::DiscMergerGCN::CalculateTotalSizeRequired(static_cast<nod::DiscGCN&>(*disc), argv[2]) == -1)
return 1;
nod::EBuildResult ret;
if (argc < 5)
{
nod::SystemString outPath(argv[2]);
outPath.append(_SYS_STR(".iso"));
nod::DiscMergerGCN b(outPath.c_str(), static_cast<nod::DiscGCN&>(*disc), progFunc);
ret = b.mergeFromDirectory(argv[2]);
}
else
{
nod::DiscMergerGCN b(argv[4], static_cast<nod::DiscGCN&>(*disc), progFunc);
ret = b.mergeFromDirectory(argv[2]);
}
printf("\n");
if (ret != nod::EBuildResult::Success)
return 1;
}
else if (!strcasecmp(argv[1], _SYS_STR("mergewii")))
{
/* Pre-validate paths */
nod::Sstat theStat;
if (nod::Stat(argv[2], &theStat) || !S_ISDIR(theStat.st_mode))
{
nod::LogModule.report(logvisor::Error, _SYS_STR("unable to stat %s as directory"), argv[2]);
return 1;
}
if (nod::Stat(argv[3], &theStat) || !S_ISREG(theStat.st_mode))
{
nod::LogModule.report(logvisor::Error, _SYS_STR("unable to stat %s as file"), argv[3]);
return 1;
}
bool isWii;
std::unique_ptr<nod::DiscBase> disc = nod::OpenDiscFromImage(argv[3], isWii);
if (!disc)
{
nod::LogModule.report(logvisor::Error, _SYS_STR("unable to open image %s"), argv[3]);
return 1;
}
if (!isWii)
{
nod::LogModule.report(logvisor::Error, _SYS_STR("GameCube images should be merged with 'mergegcn'"));
return 1;
}
bool dual = false;
if (nod::DiscMergerWii::CalculateTotalSizeRequired(static_cast<nod::DiscWii&>(*disc), argv[2], dual) == -1)
return 1;
nod::EBuildResult ret;
if (argc < 5)
{
nod::SystemString outPath(argv[2]);
outPath.append(_SYS_STR(".iso"));
nod::DiscMergerWii b(outPath.c_str(), static_cast<nod::DiscWii&>(*disc), dual, progFunc);
ret = b.mergeFromDirectory(argv[2]);
}
else
{
nod::DiscMergerWii b(argv[4], static_cast<nod::DiscWii&>(*disc), dual, progFunc);
ret = b.mergeFromDirectory(argv[2]);
}
printf("\n");
if (ret != nod::EBuildResult::Success)
return 1;
}
else else
{ outDir = argv[a];
printHelp(); }
return 1;
auto progFunc = [&](float prog, nod::SystemStringView name, size_t bytes) {
nod::Printf(_SYS_STR("\r "));
if (bytes != -1)
nod::Printf(_SYS_STR("\r%g%% %s %" PRISize " B"), prog * 100.f, name.data(), bytes);
else
nod::Printf(_SYS_STR("\r%g%% %s"), prog * 100.f, name.data());
fflush(stdout);
};
if (!strcasecmp(argv[1], _SYS_STR("extract"))) {
bool isWii;
std::unique_ptr<nod::DiscBase> disc = nod::OpenDiscFromImage(inDir, isWii);
if (!disc)
return 1;
nod::Mkdir(outDir, 0755);
nod::IPartition* dataPart = disc->getDataPartition();
if (!dataPart)
return 1;
if (!dataPart->extractToDirectory(outDir, ctx))
return 1;
} else if (!strcasecmp(argv[1], _SYS_STR("makegcn"))) {
/* Pre-validate path */
nod::Sstat theStat;
if (nod::Stat(argv[2], &theStat) || !S_ISDIR(theStat.st_mode)) {
nod::LogModule.report(logvisor::Error, _SYS_STR("unable to stat %s as directory"), argv[2]);
return 1;
} }
nod::LogModule.report(logvisor::Info, _SYS_STR("Success!")); if (nod::DiscBuilderGCN::CalculateTotalSizeRequired(argv[2]) == -1)
return 0; return 1;
}
nod::EBuildResult ret;
if (argc < 4) {
nod::SystemString outPath(argv[2]);
outPath.append(_SYS_STR(".iso"));
nod::DiscBuilderGCN b(outPath, progFunc);
ret = b.buildFromDirectory(argv[2]);
} else {
nod::DiscBuilderGCN b(argv[3], progFunc);
ret = b.buildFromDirectory(argv[2]);
}
printf("\n");
if (ret != nod::EBuildResult::Success)
return 1;
} else if (!strcasecmp(argv[1], _SYS_STR("makewii"))) {
/* Pre-validate path */
nod::Sstat theStat;
if (nod::Stat(argv[2], &theStat) || !S_ISDIR(theStat.st_mode)) {
nod::LogModule.report(logvisor::Error, _SYS_STR("unable to stat %s as directory"), argv[4]);
return 1;
}
bool dual = false;
if (nod::DiscBuilderWii::CalculateTotalSizeRequired(argv[2], dual) == -1)
return 1;
nod::EBuildResult ret;
if (argc < 4) {
nod::SystemString outPath(argv[2]);
outPath.append(_SYS_STR(".iso"));
nod::DiscBuilderWii b(outPath.c_str(), dual, progFunc);
ret = b.buildFromDirectory(argv[2]);
} else {
nod::DiscBuilderWii b(argv[3], dual, progFunc);
ret = b.buildFromDirectory(argv[2]);
}
printf("\n");
if (ret != nod::EBuildResult::Success)
return 1;
} else if (!strcasecmp(argv[1], _SYS_STR("mergegcn"))) {
/* Pre-validate paths */
nod::Sstat theStat;
if (nod::Stat(argv[2], &theStat) || !S_ISDIR(theStat.st_mode)) {
nod::LogModule.report(logvisor::Error, _SYS_STR("unable to stat %s as directory"), argv[2]);
return 1;
}
if (nod::Stat(argv[3], &theStat) || !S_ISREG(theStat.st_mode)) {
nod::LogModule.report(logvisor::Error, _SYS_STR("unable to stat %s as file"), argv[3]);
return 1;
}
bool isWii;
std::unique_ptr<nod::DiscBase> disc = nod::OpenDiscFromImage(argv[3], isWii);
if (!disc) {
nod::LogModule.report(logvisor::Error, _SYS_STR("unable to open image %s"), argv[3]);
return 1;
}
if (isWii) {
nod::LogModule.report(logvisor::Error, _SYS_STR("Wii images should be merged with 'mergewii'"));
return 1;
}
if (nod::DiscMergerGCN::CalculateTotalSizeRequired(static_cast<nod::DiscGCN&>(*disc), argv[2]) == -1)
return 1;
nod::EBuildResult ret;
if (argc < 5) {
nod::SystemString outPath(argv[2]);
outPath.append(_SYS_STR(".iso"));
nod::DiscMergerGCN b(outPath.c_str(), static_cast<nod::DiscGCN&>(*disc), progFunc);
ret = b.mergeFromDirectory(argv[2]);
} else {
nod::DiscMergerGCN b(argv[4], static_cast<nod::DiscGCN&>(*disc), progFunc);
ret = b.mergeFromDirectory(argv[2]);
}
printf("\n");
if (ret != nod::EBuildResult::Success)
return 1;
} else if (!strcasecmp(argv[1], _SYS_STR("mergewii"))) {
/* Pre-validate paths */
nod::Sstat theStat;
if (nod::Stat(argv[2], &theStat) || !S_ISDIR(theStat.st_mode)) {
nod::LogModule.report(logvisor::Error, _SYS_STR("unable to stat %s as directory"), argv[2]);
return 1;
}
if (nod::Stat(argv[3], &theStat) || !S_ISREG(theStat.st_mode)) {
nod::LogModule.report(logvisor::Error, _SYS_STR("unable to stat %s as file"), argv[3]);
return 1;
}
bool isWii;
std::unique_ptr<nod::DiscBase> disc = nod::OpenDiscFromImage(argv[3], isWii);
if (!disc) {
nod::LogModule.report(logvisor::Error, _SYS_STR("unable to open image %s"), argv[3]);
return 1;
}
if (!isWii) {
nod::LogModule.report(logvisor::Error, _SYS_STR("GameCube images should be merged with 'mergegcn'"));
return 1;
}
bool dual = false;
if (nod::DiscMergerWii::CalculateTotalSizeRequired(static_cast<nod::DiscWii&>(*disc), argv[2], dual) == -1)
return 1;
nod::EBuildResult ret;
if (argc < 5) {
nod::SystemString outPath(argv[2]);
outPath.append(_SYS_STR(".iso"));
nod::DiscMergerWii b(outPath.c_str(), static_cast<nod::DiscWii&>(*disc), dual, progFunc);
ret = b.mergeFromDirectory(argv[2]);
} else {
nod::DiscMergerWii b(argv[4], static_cast<nod::DiscWii&>(*disc), dual, progFunc);
ret = b.mergeFromDirectory(argv[2]);
}
printf("\n");
if (ret != nod::EBuildResult::Success)
return 1;
} else {
printHelp();
return 1;
}
nod::LogModule.report(logvisor::Info, _SYS_STR("Success!"));
return 0;
}

View File

@ -2,65 +2,52 @@
#include "Util.hpp" #include "Util.hpp"
namespace nod namespace nod {
{
struct CaseInsensitiveCompare struct CaseInsensitiveCompare {
{ bool operator()(std::string_view lhs, std::string_view rhs) const {
bool operator()(std::string_view lhs, std::string_view rhs) const
{
#if _WIN32 #if _WIN32
if (_stricmp(lhs.data(), rhs.data()) < 0) if (_stricmp(lhs.data(), rhs.data()) < 0)
#else #else
if (strcasecmp(lhs.data(), rhs.data()) < 0) if (strcasecmp(lhs.data(), rhs.data()) < 0)
#endif #endif
return true; return true;
return false; return false;
} }
#if _WIN32 #if _WIN32
bool operator()(std::wstring_view lhs, std::wstring_view rhs) const bool operator()(std::wstring_view lhs, std::wstring_view rhs) const {
{ if (_wcsicmp(lhs.data(), rhs.data()) < 0)
if (_wcsicmp(lhs.data(), rhs.data()) < 0) return true;
return true; return false;
return false; }
}
#endif #endif
}; };
class DirectoryEnumerator class DirectoryEnumerator {
{
public: public:
enum class Mode enum class Mode { Native, DirsSorted, FilesSorted, DirsThenFilesSorted };
{ struct Entry {
Native, SystemString m_path;
DirsSorted, SystemString m_name;
FilesSorted, size_t m_fileSz;
DirsThenFilesSorted bool m_isDir;
};
struct Entry
{
SystemString m_path;
SystemString m_name;
size_t m_fileSz;
bool m_isDir;
Entry(const SystemString& path, const SystemChar* name, size_t sz, bool isDir) Entry(const SystemString& path, const SystemChar* name, size_t sz, bool isDir)
: m_path(path), m_name(name), m_fileSz(sz), m_isDir(isDir) {} : m_path(path), m_name(name), m_fileSz(sz), m_isDir(isDir) {}
}; };
private: private:
std::vector<Entry> m_entries; std::vector<Entry> m_entries;
public: public:
DirectoryEnumerator(SystemStringView path, Mode mode=Mode::DirsThenFilesSorted, DirectoryEnumerator(SystemStringView path, Mode mode = Mode::DirsThenFilesSorted, bool sizeSort = false,
bool sizeSort=false, bool reverse=false, bool noHidden=false); bool reverse = false, bool noHidden = false);
operator bool() const {return m_entries.size() != 0;} operator bool() const { return m_entries.size() != 0; }
size_t size() const {return m_entries.size();} size_t size() const { return m_entries.size(); }
std::vector<Entry>::const_iterator begin() const {return m_entries.cbegin();} std::vector<Entry>::const_iterator begin() const { return m_entries.cbegin(); }
std::vector<Entry>::const_iterator end() const {return m_entries.cend();} std::vector<Entry>::const_iterator end() const { return m_entries.cend(); }
}; };
} } // namespace nod

View File

@ -11,495 +11,453 @@
#include "IDiscIO.hpp" #include "IDiscIO.hpp"
#include "IFileIO.hpp" #include "IFileIO.hpp"
namespace nod namespace nod {
{
using FProgress = std::function<void(float totalProg, SystemStringView fileName, size_t fileBytesXfered)>; using FProgress = std::function<void(float totalProg, SystemStringView fileName, size_t fileBytesXfered)>;
enum class EBuildResult enum class EBuildResult { Success, Failed, DiskFull };
{
Success,
Failed,
DiskFull
};
enum class PartitionKind : uint32_t enum class PartitionKind : uint32_t { Data, Update, Channel };
{
Data,
Update,
Channel
};
const SystemChar* getKindString(PartitionKind kind); const SystemChar* getKindString(PartitionKind kind);
class FSTNode class FSTNode {
{ uint32_t typeAndNameOffset;
uint32_t typeAndNameOffset; uint32_t offset;
uint32_t offset; uint32_t length;
uint32_t length;
public: public:
FSTNode(bool isDir, uint32_t nameOff, uint32_t off, uint32_t len) FSTNode(bool isDir, uint32_t nameOff, uint32_t off, uint32_t len) {
{ typeAndNameOffset = nameOff & 0xffffff;
typeAndNameOffset = nameOff & 0xffffff; typeAndNameOffset |= isDir << 24;
typeAndNameOffset |= isDir << 24; typeAndNameOffset = SBig(typeAndNameOffset);
typeAndNameOffset = SBig(typeAndNameOffset); offset = SBig(off);
offset = SBig(off); length = SBig(len);
length = SBig(len); }
} inline bool isDir() const { return ((SBig(typeAndNameOffset) >> 24) != 0); }
inline bool isDir() const {return ((SBig(typeAndNameOffset) >> 24) != 0);} inline uint32_t getNameOffset() const { return SBig(typeAndNameOffset) & 0xffffff; }
inline uint32_t getNameOffset() const {return SBig(typeAndNameOffset) & 0xffffff;} inline uint32_t getOffset() const { return SBig(offset); }
inline uint32_t getOffset() const {return SBig(offset);} inline uint32_t getLength() const { return SBig(length); }
inline uint32_t getLength() const {return SBig(length);} void incrementLength() {
void incrementLength() uint32_t orig = SBig(length);
{ ++orig;
uint32_t orig = SBig(length); length = SBig(orig);
++orig; }
length = SBig(orig);
}
}; };
struct Header struct Header {
{ char m_gameID[6];
char m_gameID[6]; char m_discNum;
char m_discNum; char m_discVersion;
char m_discVersion; char m_audioStreaming;
char m_audioStreaming; char m_streamBufSz;
char m_streamBufSz; char m_unk1[14];
char m_unk1[14]; uint32_t m_wiiMagic;
uint32_t m_wiiMagic; uint32_t m_gcnMagic;
uint32_t m_gcnMagic; char m_gameTitle[64];
char m_gameTitle[64]; char m_disableHashVerification;
char m_disableHashVerification; char m_disableDiscEnc;
char m_disableDiscEnc; char m_unk2[0x39e];
char m_unk2[0x39e]; uint32_t m_debugMonOff;
uint32_t m_debugMonOff; uint32_t m_debugLoadAddr;
uint32_t m_debugLoadAddr; char m_unk3[0x18];
char m_unk3[0x18]; uint32_t m_dolOff;
uint32_t m_dolOff; uint32_t m_fstOff;
uint32_t m_fstOff; uint32_t m_fstSz;
uint32_t m_fstSz; uint32_t m_fstMaxSz;
uint32_t m_fstMaxSz; uint32_t m_fstMemoryAddress;
uint32_t m_fstMemoryAddress; uint32_t m_userPosition;
uint32_t m_userPosition; uint32_t m_userSz;
uint32_t m_userSz; uint8_t padding1[4];
uint8_t padding1[4];
Header() = default; Header() = default;
Header(IDiscIO& dio, bool& err) Header(IDiscIO& dio, bool& err) {
{ auto rs = dio.beginReadStream();
auto rs = dio.beginReadStream(); if (!rs) {
if (!rs) err = true;
{ return;
err = true;
return;
}
read(*rs);
} }
read(*rs);
}
void read(IReadStream& s) void read(IReadStream& s) {
{ memset(this, 0, sizeof(*this));
memset(this, 0, sizeof(*this)); s.read(this, sizeof(*this));
s.read(this, sizeof(*this)); m_wiiMagic = SBig(m_wiiMagic);
m_wiiMagic = SBig(m_wiiMagic); m_gcnMagic = SBig(m_gcnMagic);
m_gcnMagic = SBig(m_gcnMagic); m_debugMonOff = SBig(m_debugMonOff);
m_debugMonOff = SBig(m_debugMonOff); m_debugLoadAddr = SBig(m_debugLoadAddr);
m_debugLoadAddr = SBig(m_debugLoadAddr); m_dolOff = SBig(m_dolOff);
m_dolOff = SBig(m_dolOff); m_fstOff = SBig(m_fstOff);
m_fstOff = SBig(m_fstOff); m_fstSz = SBig(m_fstSz);
m_fstSz = SBig(m_fstSz); m_fstMaxSz = SBig(m_fstMaxSz);
m_fstMaxSz = SBig(m_fstMaxSz); m_fstMemoryAddress = SBig(m_fstMemoryAddress);
m_fstMemoryAddress = SBig(m_fstMemoryAddress); m_userPosition = SBig(m_userPosition);
m_userPosition = SBig(m_userPosition); m_userSz = SBig(m_userSz);
m_userSz = SBig(m_userSz); }
}
void write(IWriteStream& ws) const void write(IWriteStream& ws) const {
{ Header hs(*this);
Header hs(*this); hs.m_wiiMagic = SBig(hs.m_wiiMagic);
hs.m_wiiMagic = SBig(hs.m_wiiMagic); hs.m_gcnMagic = SBig(hs.m_gcnMagic);
hs.m_gcnMagic = SBig(hs.m_gcnMagic); hs.m_debugMonOff = SBig(hs.m_debugMonOff);
hs.m_debugMonOff = SBig(hs.m_debugMonOff); hs.m_debugLoadAddr = SBig(hs.m_debugLoadAddr);
hs.m_debugLoadAddr = SBig(hs.m_debugLoadAddr); hs.m_dolOff = SBig(hs.m_dolOff);
hs.m_dolOff = SBig(hs.m_dolOff); hs.m_fstOff = SBig(hs.m_fstOff);
hs.m_fstOff = SBig(hs.m_fstOff); hs.m_fstSz = SBig(hs.m_fstSz);
hs.m_fstSz = SBig(hs.m_fstSz); hs.m_fstMaxSz = SBig(hs.m_fstMaxSz);
hs.m_fstMaxSz = SBig(hs.m_fstMaxSz); hs.m_fstMemoryAddress = SBig(hs.m_fstMemoryAddress);
hs.m_fstMemoryAddress = SBig(hs.m_fstMemoryAddress); hs.m_userPosition = SBig(hs.m_userPosition);
hs.m_userPosition = SBig(hs.m_userPosition); hs.m_userSz = SBig(hs.m_userSz);
hs.m_userSz = SBig(hs.m_userSz); ws.write(&hs, sizeof(hs));
ws.write(&hs, sizeof(hs)); }
}
}; };
/* Currently only kept for dolphin compatibility */ /* Currently only kept for dolphin compatibility */
struct BI2Header struct BI2Header {
{ int32_t m_debugMonitorSize;
int32_t m_debugMonitorSize; int32_t m_simMemSize;
int32_t m_simMemSize; uint32_t m_argOffset;
uint32_t m_argOffset; uint32_t m_debugFlag;
uint32_t m_debugFlag; uint32_t m_trkAddress;
uint32_t m_trkAddress; uint32_t m_trkSz;
uint32_t m_trkSz; uint32_t m_countryCode;
uint32_t m_countryCode; uint32_t m_unk1;
uint32_t m_unk1; uint32_t m_unk2;
uint32_t m_unk2; uint32_t m_unk3;
uint32_t m_unk3; uint32_t m_dolLimit;
uint32_t m_dolLimit; uint32_t m_unk4;
uint32_t m_unk4; uint8_t padding2[0x1FD0];
uint8_t padding2[0x1FD0];
void read(IReadStream& rs) void read(IReadStream& rs) {
{ memset(this, 0, sizeof(*this));
memset(this, 0, sizeof(*this)); rs.read(this, sizeof(*this));
rs.read(this, sizeof(*this)); m_debugMonitorSize = SBig(m_debugMonitorSize);
m_debugMonitorSize = SBig(m_debugMonitorSize); m_simMemSize = SBig(m_simMemSize);
m_simMemSize = SBig(m_simMemSize); m_argOffset = SBig(m_argOffset);
m_argOffset = SBig(m_argOffset); m_debugFlag = SBig(m_debugFlag);
m_debugFlag = SBig(m_debugFlag); m_trkAddress = SBig(m_trkAddress);
m_trkAddress = SBig(m_trkAddress); m_trkSz = SBig(m_trkSz);
m_trkSz = SBig(m_trkSz); m_countryCode = SBig(m_countryCode);
m_countryCode = SBig(m_countryCode); m_unk1 = SBig(m_unk1);
m_unk1 = SBig(m_unk1); m_unk2 = SBig(m_unk2);
m_unk2 = SBig(m_unk2); m_unk3 = SBig(m_unk3);
m_unk3 = SBig(m_unk3); m_dolLimit = SBig(m_dolLimit);
m_dolLimit = SBig(m_dolLimit); m_unk4 = SBig(m_unk4);
m_unk4 = SBig(m_unk4); }
}
void write(IWriteStream& ws) const void write(IWriteStream& ws) const {
{ BI2Header h = *this;
BI2Header h = *this; h.m_debugMonitorSize = SBig(h.m_debugMonitorSize);
h.m_debugMonitorSize = SBig(h.m_debugMonitorSize); h.m_simMemSize = SBig(h.m_simMemSize);
h.m_simMemSize = SBig(h.m_simMemSize); h.m_argOffset = SBig(h.m_argOffset);
h.m_argOffset = SBig(h.m_argOffset); h.m_debugFlag = SBig(h.m_debugFlag);
h.m_debugFlag = SBig(h.m_debugFlag); h.m_trkAddress = SBig(h.m_trkAddress);
h.m_trkAddress = SBig(h.m_trkAddress); h.m_trkSz = SBig(h.m_trkSz);
h.m_trkSz = SBig(h.m_trkSz); h.m_countryCode = SBig(h.m_countryCode);
h.m_countryCode = SBig(h.m_countryCode); h.m_unk1 = SBig(h.m_unk1);
h.m_unk1 = SBig(h.m_unk1); h.m_unk2 = SBig(h.m_unk2);
h.m_unk2 = SBig(h.m_unk2); h.m_unk3 = SBig(h.m_unk3);
h.m_unk3 = SBig(h.m_unk3); h.m_dolLimit = SBig(h.m_dolLimit);
h.m_dolLimit = SBig(h.m_dolLimit); h.m_unk4 = SBig(h.m_unk4);
h.m_unk4 = SBig(h.m_unk4); ws.write(&h, sizeof(h));
ws.write(&h, sizeof(h)); }
}
}; };
struct ExtractionContext; struct ExtractionContext;
class IPartition; class IPartition;
class DiscBase; class DiscBase;
class Node class Node {
{
public: public:
enum class Kind enum class Kind { File, Directory };
{
File,
Directory
};
private: private:
friend class IPartition; friend class IPartition;
const IPartition& m_parent; const IPartition& m_parent;
Kind m_kind; Kind m_kind;
uint64_t m_discOffset; uint64_t m_discOffset;
uint64_t m_discLength; uint64_t m_discLength;
std::string m_name; std::string m_name;
std::vector<Node>::iterator m_childrenBegin; std::vector<Node>::iterator m_childrenBegin;
std::vector<Node>::iterator m_childrenEnd; std::vector<Node>::iterator m_childrenEnd;
public: public:
Node(const IPartition& parent, const FSTNode& node, std::string_view name); Node(const IPartition& parent, const FSTNode& node, std::string_view name);
inline Kind getKind() const {return m_kind;} inline Kind getKind() const { return m_kind; }
inline std::string_view getName() const {return m_name;} inline std::string_view getName() const { return m_name; }
inline uint64_t size() const {return m_discLength;} inline uint64_t size() const { return m_discLength; }
std::unique_ptr<IPartReadStream> beginReadStream(uint64_t offset=0) const; std::unique_ptr<IPartReadStream> beginReadStream(uint64_t offset = 0) const;
std::unique_ptr<uint8_t[]> getBuf() const; std::unique_ptr<uint8_t[]> getBuf() const;
inline std::vector<Node>::iterator rawBegin() const {return m_childrenBegin;} inline std::vector<Node>::iterator rawBegin() const { return m_childrenBegin; }
inline std::vector<Node>::iterator rawEnd() const {return m_childrenEnd;} inline std::vector<Node>::iterator rawEnd() const { return m_childrenEnd; }
class DirectoryIterator class DirectoryIterator {
{ friend class Node;
friend class Node; std::vector<Node>::iterator m_it;
std::vector<Node>::iterator m_it; DirectoryIterator(const std::vector<Node>::iterator& it) : m_it(it) {}
DirectoryIterator(const std::vector<Node>::iterator& it) : m_it(it) {}
public:
using iterator_category = std::forward_iterator_tag;
using value_type = Node;
using difference_type = std::ptrdiff_t;
using pointer = Node*;
using reference = Node&;
inline bool operator!=(const DirectoryIterator& other) {return m_it != other.m_it;} public:
inline bool operator==(const DirectoryIterator& other) {return m_it == other.m_it;} using iterator_category = std::forward_iterator_tag;
inline DirectoryIterator& operator++() using value_type = Node;
{ using difference_type = std::ptrdiff_t;
if (m_it->m_kind == Kind::Directory) using pointer = Node*;
m_it = m_it->rawEnd(); using reference = Node&;
else
++m_it; inline bool operator!=(const DirectoryIterator& other) { return m_it != other.m_it; }
return *this; inline bool operator==(const DirectoryIterator& other) { return m_it == other.m_it; }
} inline DirectoryIterator& operator++() {
inline Node& operator*() {return *m_it;} if (m_it->m_kind == Kind::Directory)
inline Node* operator->() {return &*m_it;} m_it = m_it->rawEnd();
}; else
inline DirectoryIterator begin() const {return DirectoryIterator(m_childrenBegin);} ++m_it;
inline DirectoryIterator end() const {return DirectoryIterator(m_childrenEnd);} return *this;
inline DirectoryIterator find(std::string_view name) const
{
if (m_kind == Kind::Directory)
{
DirectoryIterator it=begin();
for (; it != end() ; ++it)
{
if (!it->getName().compare(name))
return it;
}
return it;
}
return end();
} }
inline Node& operator*() { return *m_it; }
inline Node* operator->() { return &*m_it; }
};
inline DirectoryIterator begin() const { return DirectoryIterator(m_childrenBegin); }
inline DirectoryIterator end() const { return DirectoryIterator(m_childrenEnd); }
inline DirectoryIterator find(std::string_view name) const {
if (m_kind == Kind::Directory) {
DirectoryIterator it = begin();
for (; it != end(); ++it) {
if (!it->getName().compare(name))
return it;
}
return it;
}
return end();
}
bool extractToDirectory(SystemStringView basePath, const ExtractionContext& ctx) const; bool extractToDirectory(SystemStringView basePath, const ExtractionContext& ctx) const;
}; };
class IPartition class IPartition {
{
public: public:
virtual ~IPartition() = default; virtual ~IPartition() = default;
struct DOLHeader struct DOLHeader {
{ uint32_t textOff[7];
uint32_t textOff[7]; uint32_t dataOff[11];
uint32_t dataOff[11]; uint32_t textStarts[7];
uint32_t textStarts[7]; uint32_t dataStarts[11];
uint32_t dataStarts[11]; uint32_t textSizes[7];
uint32_t textSizes[7]; uint32_t dataSizes[11];
uint32_t dataSizes[11]; uint32_t bssStart;
uint32_t bssStart; uint32_t bssSize;
uint32_t bssSize; uint32_t entryPoint;
uint32_t entryPoint; };
};
protected: protected:
Header m_header; Header m_header;
BI2Header m_bi2Header; BI2Header m_bi2Header;
uint64_t m_dolOff; uint64_t m_dolOff;
uint64_t m_fstOff; uint64_t m_fstOff;
uint64_t m_fstSz; uint64_t m_fstSz;
uint64_t m_apploaderSz; uint64_t m_apploaderSz;
std::vector<Node> m_nodes; std::vector<Node> m_nodes;
void parseFST(IPartReadStream& s); void parseFST(IPartReadStream& s);
std::vector<FSTNode> m_buildNodes;
std::vector<std::string> m_buildNames;
size_t m_buildNameOff = 0;
uint64_t m_dolSz;
void parseDOL(IPartReadStream& s);
const DiscBase& m_parent;
PartitionKind m_kind;
uint64_t m_offset;
bool m_isWii;
public:
mutable size_t m_curNodeIdx = 0;
float getProgressFactor() const { return getNodeCount() ? m_curNodeIdx / float(getNodeCount()) : 0.f; }
float getProgressFactorMidFile(size_t curByte, size_t totalBytes) const {
if (!getNodeCount())
return 0.f;
if (totalBytes)
return (m_curNodeIdx + (curByte / float(totalBytes))) / float(getNodeCount());
else
return m_curNodeIdx / float(getNodeCount());
}
IPartition(const DiscBase& parent, PartitionKind kind, bool isWii, uint64_t offset)
: m_parent(parent), m_kind(kind), m_offset(offset), m_isWii(isWii) {}
virtual uint64_t normalizeOffset(uint64_t anOffset) const { return anOffset; }
inline PartitionKind getKind() const { return m_kind; }
inline bool isWii() const { return m_isWii; }
inline uint64_t getDiscOffset() const { return m_offset; }
virtual std::unique_ptr<IPartReadStream> beginReadStream(uint64_t offset = 0) const = 0;
inline std::unique_ptr<IPartReadStream> beginDOLReadStream(uint64_t offset = 0) const {
return beginReadStream(m_dolOff + offset);
}
inline std::unique_ptr<IPartReadStream> beginFSTReadStream(uint64_t offset = 0) const {
return beginReadStream(m_fstOff + offset);
}
inline std::unique_ptr<IPartReadStream> beginApploaderReadStream(uint64_t offset = 0) const {
return beginReadStream(0x2440 + offset);
}
inline const Node& getFSTRoot() const { return m_nodes[0]; }
inline Node& getFSTRoot() { return m_nodes[0]; }
bool extractToDirectory(SystemStringView path, const ExtractionContext& ctx);
inline uint64_t getDOLSize() const { return m_dolSz; }
inline std::unique_ptr<uint8_t[]> getDOLBuf() const {
std::unique_ptr<uint8_t[]> buf(new uint8_t[m_dolSz]);
beginDOLReadStream()->read(buf.get(), m_dolSz);
return buf;
}
inline uint64_t getFSTSize() const { return m_fstSz; }
inline std::unique_ptr<uint8_t[]> getFSTBuf() const {
std::unique_ptr<uint8_t[]> buf(new uint8_t[m_fstSz]);
beginFSTReadStream()->read(buf.get(), m_fstSz);
return buf;
}
inline uint64_t getApploaderSize() const { return m_apploaderSz; }
inline std::unique_ptr<uint8_t[]> getApploaderBuf() const {
std::unique_ptr<uint8_t[]> buf(new uint8_t[m_apploaderSz]);
beginApploaderReadStream()->read(buf.get(), m_apploaderSz);
return buf;
}
inline size_t getNodeCount() const { return m_nodes.size(); }
inline const Header& getHeader() const { return m_header; }
inline const BI2Header& getBI2() const { return m_bi2Header; }
virtual bool extractCryptoFiles(SystemStringView path, const ExtractionContext& ctx) const { return true; }
bool extractSysFiles(SystemStringView path, const ExtractionContext& ctx) const;
};
class DiscBase {
public:
virtual ~DiscBase() = default;
protected:
std::unique_ptr<IDiscIO> m_discIO;
Header m_header;
std::vector<std::unique_ptr<IPartition>> m_partitions;
public:
DiscBase(std::unique_ptr<IDiscIO>&& dio, bool& err) : m_discIO(std::move(dio)), m_header(*m_discIO, err) {}
inline const Header& getHeader() const { return m_header; }
inline const IDiscIO& getDiscIO() const { return *m_discIO; }
inline size_t getPartitonNodeCount(size_t partition = 0) const {
if (partition > m_partitions.size())
return -1;
return m_partitions[partition]->getNodeCount();
}
inline IPartition* getDataPartition() {
for (const std::unique_ptr<IPartition>& part : m_partitions)
if (part->getKind() == PartitionKind::Data)
return part.get();
return nullptr;
}
inline IPartition* getUpdatePartition() {
for (const std::unique_ptr<IPartition>& part : m_partitions)
if (part->getKind() == PartitionKind::Update)
return part.get();
return nullptr;
}
inline void extractToDirectory(SystemStringView path, const ExtractionContext& ctx) {
for (std::unique_ptr<IPartition>& part : m_partitions)
part->extractToDirectory(path, ctx);
}
virtual bool extractDiscHeaderFiles(SystemStringView path, const ExtractionContext& ctx) const = 0;
};
class DiscBuilderBase {
friend class DiscMergerWii;
public:
class PartitionBuilderBase {
public:
virtual ~PartitionBuilderBase() = default;
protected:
std::unordered_map<SystemString, std::pair<uint64_t, uint64_t>> m_fileOffsetsSizes;
std::vector<FSTNode> m_buildNodes; std::vector<FSTNode> m_buildNodes;
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, IPartWriteStream& ws) = 0;
virtual uint32_t packOffset(uint64_t offset) const = 0;
uint64_t m_dolSz; void recursiveBuildNodesPre(SystemStringView dirIn);
void parseDOL(IPartReadStream& s); bool recursiveBuildNodes(IPartWriteStream& ws, bool system, SystemStringView dirIn);
const DiscBase& m_parent; bool recursiveBuildFST(SystemStringView dirIn, std::function<void(void)> incParents, size_t parentDirIdx);
void recursiveMergeNodesPre(const Node* nodeIn, SystemStringView dirIn);
bool recursiveMergeNodes(IPartWriteStream& ws, bool system, const Node* nodeIn, SystemStringView dirIn,
SystemStringView keyPath);
bool recursiveMergeFST(const Node* nodeIn, SystemStringView dirIn, std::function<void(void)> incParents,
SystemStringView keyPath);
static bool RecursiveCalculateTotalSize(uint64_t& totalSz, const Node* nodeIn, SystemStringView dirIn);
void addBuildName(SystemStringView str) {
SystemUTF8Conv utf8View(str);
m_buildNames.emplace_back(utf8View.utf8_str());
m_buildNameOff += str.size() + 1;
}
DiscBuilderBase& m_parent;
PartitionKind m_kind; PartitionKind m_kind;
uint64_t m_offset; uint64_t m_dolOffset = 0;
uint64_t m_dolSize = 0;
bool m_isWii; bool m_isWii;
public:
mutable size_t m_curNodeIdx = 0;
float getProgressFactor() const { return getNodeCount() ? m_curNodeIdx / float(getNodeCount()) : 0.f; }
float getProgressFactorMidFile(size_t curByte, size_t totalBytes) const
{
if (!getNodeCount())
return 0.f;
if (totalBytes) public:
return (m_curNodeIdx + (curByte / float(totalBytes))) / float(getNodeCount()); PartitionBuilderBase(DiscBuilderBase& parent, PartitionKind kind, bool isWii)
else : m_parent(parent), m_kind(kind), m_isWii(isWii) {}
return m_curNodeIdx / float(getNodeCount()); virtual std::unique_ptr<IPartWriteStream> beginWriteStream(uint64_t offset) = 0;
} bool buildFromDirectory(IPartWriteStream& ws, SystemStringView dirIn);
static uint64_t CalculateTotalSizeBuild(SystemStringView dirIn, PartitionKind kind, bool isWii);
bool mergeFromDirectory(IPartWriteStream& ws, const IPartition* partIn, SystemStringView dirIn);
static uint64_t CalculateTotalSizeMerge(const IPartition* partIn, SystemStringView dirIn);
};
IPartition(const DiscBase& parent, PartitionKind kind, bool isWii, uint64_t offset)
: m_parent(parent), m_kind(kind), m_offset(offset), m_isWii(isWii) {}
virtual uint64_t normalizeOffset(uint64_t anOffset) const {return anOffset;}
inline PartitionKind getKind() const {return m_kind;}
inline bool isWii() const {return m_isWii;}
inline uint64_t getDiscOffset() const {return m_offset;}
virtual std::unique_ptr<IPartReadStream> beginReadStream(uint64_t offset=0) const=0;
inline std::unique_ptr<IPartReadStream> beginDOLReadStream(uint64_t offset=0) const
{return beginReadStream(m_dolOff + offset);}
inline std::unique_ptr<IPartReadStream> beginFSTReadStream(uint64_t offset=0) const
{return beginReadStream(m_fstOff + offset);}
inline std::unique_ptr<IPartReadStream> beginApploaderReadStream(uint64_t offset=0) const
{return beginReadStream(0x2440 + offset);}
inline const Node& getFSTRoot() const {return m_nodes[0];}
inline Node& getFSTRoot() {return m_nodes[0];}
bool extractToDirectory(SystemStringView path, const ExtractionContext& ctx);
inline uint64_t getDOLSize() const {return m_dolSz;}
inline std::unique_ptr<uint8_t[]> getDOLBuf() const
{
std::unique_ptr<uint8_t[]> buf(new uint8_t[m_dolSz]);
beginDOLReadStream()->read(buf.get(), m_dolSz);
return buf;
}
inline uint64_t getFSTSize() const {return m_fstSz;}
inline std::unique_ptr<uint8_t[]> getFSTBuf() const
{
std::unique_ptr<uint8_t[]> buf(new uint8_t[m_fstSz]);
beginFSTReadStream()->read(buf.get(), m_fstSz);
return buf;
}
inline uint64_t getApploaderSize() const {return m_apploaderSz;}
inline std::unique_ptr<uint8_t[]> getApploaderBuf() const
{
std::unique_ptr<uint8_t[]> buf(new uint8_t[m_apploaderSz]);
beginApploaderReadStream()->read(buf.get(), m_apploaderSz);
return buf;
}
inline size_t getNodeCount() const { return m_nodes.size(); }
inline const Header& getHeader() const { return m_header; }
inline const BI2Header& getBI2() const { return m_bi2Header; }
virtual bool extractCryptoFiles(SystemStringView path, const ExtractionContext& ctx) const { return true; }
bool extractSysFiles(SystemStringView path, const ExtractionContext& ctx) const;
};
class DiscBase
{
public:
virtual ~DiscBase() = default;
protected: protected:
std::unique_ptr<IDiscIO> m_discIO; SystemString m_outPath;
Header m_header; std::unique_ptr<IFileIO> m_fileIO;
std::vector<std::unique_ptr<IPartition>> m_partitions; std::vector<std::unique_ptr<PartitionBuilderBase>> m_partitions;
int64_t m_discCapacity;
public: public:
DiscBase(std::unique_ptr<IDiscIO>&& dio, bool& err) FProgress m_progressCB;
: m_discIO(std::move(dio)), m_header(*m_discIO, err) {} size_t m_progressIdx = 0;
size_t m_progressTotal = 0;
float getProgressFactor() const {
return m_progressTotal ? std::min(1.f, m_progressIdx / float(m_progressTotal)) : 0.f;
}
float getProgressFactorMidFile(size_t curByte, size_t totalBytes) const {
if (!m_progressTotal)
return 0.f;
inline const Header& getHeader() const {return m_header;} if (totalBytes)
inline const IDiscIO& getDiscIO() const {return *m_discIO;} return (m_progressIdx + (curByte / float(totalBytes))) / float(m_progressTotal);
inline size_t getPartitonNodeCount(size_t partition = 0) const else
{ return m_progressIdx / float(m_progressTotal);
if (partition > m_partitions.size()) }
return -1;
return m_partitions[partition]->getNodeCount();
}
inline IPartition* getDataPartition() virtual ~DiscBuilderBase() = default;
{ DiscBuilderBase(SystemStringView outPath, int64_t discCapacity, FProgress progressCB)
for (const std::unique_ptr<IPartition>& part : m_partitions) : m_outPath(outPath)
if (part->getKind() == PartitionKind::Data) , m_fileIO(NewFileIO(outPath, discCapacity))
return part.get(); , m_discCapacity(discCapacity)
return nullptr; , m_progressCB(progressCB) {}
} DiscBuilderBase(DiscBuilderBase&&) = default;
DiscBuilderBase& operator=(DiscBuilderBase&&) = default;
inline IPartition* getUpdatePartition() IFileIO& getFileIO() { return *m_fileIO; }
{
for (const std::unique_ptr<IPartition>& part : m_partitions)
if (part->getKind() == PartitionKind::Update)
return part.get();
return nullptr;
}
inline void extractToDirectory(SystemStringView path, const ExtractionContext& ctx)
{
for (std::unique_ptr<IPartition>& part : m_partitions)
part->extractToDirectory(path, ctx);
}
virtual bool extractDiscHeaderFiles(SystemStringView path, const ExtractionContext& ctx) const=0;
}; };
class DiscBuilderBase } // namespace nod
{
friend class DiscMergerWii;
public:
class PartitionBuilderBase
{
public:
virtual ~PartitionBuilderBase() = default;
protected:
std::unordered_map<SystemString, std::pair<uint64_t,uint64_t>> m_fileOffsetsSizes;
std::vector<FSTNode> m_buildNodes;
std::vector<std::string> m_buildNames;
size_t m_buildNameOff = 0;
virtual uint64_t userAllocate(uint64_t reqSz, IPartWriteStream& ws)=0;
virtual uint32_t packOffset(uint64_t offset) const=0;
void recursiveBuildNodesPre(SystemStringView dirIn);
bool recursiveBuildNodes(IPartWriteStream& ws, bool system, SystemStringView dirIn);
bool recursiveBuildFST(SystemStringView dirIn,
std::function<void(void)> incParents,
size_t parentDirIdx);
void recursiveMergeNodesPre(const Node* nodeIn, SystemStringView dirIn);
bool recursiveMergeNodes(IPartWriteStream& ws, bool system,
const Node* nodeIn, SystemStringView dirIn,
SystemStringView keyPath);
bool recursiveMergeFST(const Node* nodeIn,
SystemStringView dirIn, std::function<void(void)> incParents,
SystemStringView keyPath);
static bool RecursiveCalculateTotalSize(uint64_t& totalSz,
const Node* nodeIn,
SystemStringView dirIn);
void addBuildName(SystemStringView str)
{
SystemUTF8Conv utf8View(str);
m_buildNames.emplace_back(utf8View.utf8_str());
m_buildNameOff += str.size() + 1;
}
DiscBuilderBase& m_parent;
PartitionKind m_kind;
uint64_t m_dolOffset = 0;
uint64_t m_dolSize = 0;
bool m_isWii;
public:
PartitionBuilderBase(DiscBuilderBase& parent, PartitionKind kind, bool isWii)
: m_parent(parent), m_kind(kind), m_isWii(isWii)
{}
virtual std::unique_ptr<IPartWriteStream> beginWriteStream(uint64_t offset)=0;
bool buildFromDirectory(IPartWriteStream& ws, SystemStringView dirIn);
static uint64_t CalculateTotalSizeBuild(SystemStringView dirIn, PartitionKind kind, bool isWii);
bool mergeFromDirectory(IPartWriteStream& ws, const IPartition* partIn, SystemStringView dirIn);
static uint64_t CalculateTotalSizeMerge(const IPartition* partIn, SystemStringView dirIn);
};
protected:
SystemString m_outPath;
std::unique_ptr<IFileIO> m_fileIO;
std::vector<std::unique_ptr<PartitionBuilderBase>> m_partitions;
int64_t m_discCapacity;
public:
FProgress m_progressCB;
size_t m_progressIdx = 0;
size_t m_progressTotal = 0;
float getProgressFactor() const
{
return m_progressTotal ? std::min(1.f, m_progressIdx / float(m_progressTotal)) : 0.f;
}
float getProgressFactorMidFile(size_t curByte, size_t totalBytes) const
{
if (!m_progressTotal)
return 0.f;
if (totalBytes)
return (m_progressIdx + (curByte / float(totalBytes))) / float(m_progressTotal);
else
return m_progressIdx / float(m_progressTotal);
}
virtual ~DiscBuilderBase() = default;
DiscBuilderBase(SystemStringView outPath,
int64_t discCapacity, FProgress progressCB)
: m_outPath(outPath), m_fileIO(NewFileIO(outPath, discCapacity)),
m_discCapacity(discCapacity), m_progressCB(progressCB) {}
DiscBuilderBase(DiscBuilderBase&&) = default;
DiscBuilderBase& operator=(DiscBuilderBase&&) = default;
IFileIO& getFileIO() { return *m_fileIO; }
};
}

View File

@ -2,38 +2,35 @@
#include "DiscBase.hpp" #include "DiscBase.hpp"
namespace nod namespace nod {
{
class DiscBuilderGCN; class DiscBuilderGCN;
class DiscGCN : public DiscBase class DiscGCN : public DiscBase {
{ friend class DiscMergerGCN;
friend class DiscMergerGCN; DiscBuilderGCN makeMergeBuilder(SystemStringView outPath, FProgress progressCB);
DiscBuilderGCN makeMergeBuilder(SystemStringView outPath, FProgress progressCB);
public: public:
DiscGCN(std::unique_ptr<IDiscIO>&& dio, bool& err); DiscGCN(std::unique_ptr<IDiscIO>&& dio, bool& err);
bool extractDiscHeaderFiles(SystemStringView path, const ExtractionContext& ctx) const; bool extractDiscHeaderFiles(SystemStringView path, const ExtractionContext& ctx) const;
}; };
class DiscBuilderGCN : public DiscBuilderBase class DiscBuilderGCN : public DiscBuilderBase {
{ friend class DiscMergerGCN;
friend class DiscMergerGCN;
public: public:
DiscBuilderGCN(SystemStringView outPath, FProgress progressCB); DiscBuilderGCN(SystemStringView outPath, FProgress progressCB);
EBuildResult buildFromDirectory(SystemStringView dirIn); EBuildResult buildFromDirectory(SystemStringView dirIn);
static uint64_t CalculateTotalSizeRequired(SystemStringView dirIn); static uint64_t CalculateTotalSizeRequired(SystemStringView dirIn);
}; };
class DiscMergerGCN class DiscMergerGCN {
{ DiscGCN& m_sourceDisc;
DiscGCN& m_sourceDisc; DiscBuilderGCN m_builder;
DiscBuilderGCN m_builder;
public: public:
DiscMergerGCN(SystemStringView outPath, DiscGCN& sourceDisc, FProgress progressCB); DiscMergerGCN(SystemStringView outPath, DiscGCN& sourceDisc, FProgress progressCB);
EBuildResult mergeFromDirectory(SystemStringView dirIn); EBuildResult mergeFromDirectory(SystemStringView dirIn);
static uint64_t CalculateTotalSizeRequired(DiscGCN& sourceDisc, SystemStringView dirIn); static uint64_t CalculateTotalSizeRequired(DiscGCN& sourceDisc, SystemStringView dirIn);
}; };
} } // namespace nod

View File

@ -2,37 +2,31 @@
#include "DiscBase.hpp" #include "DiscBase.hpp"
namespace nod namespace nod {
{
class DiscBuilderWii; class DiscBuilderWii;
class DiscWii : public DiscBase class DiscWii : public DiscBase {
{
public: public:
DiscWii(std::unique_ptr<IDiscIO>&& dio, bool& err); DiscWii(std::unique_ptr<IDiscIO>&& dio, bool& err);
DiscBuilderWii makeMergeBuilder(SystemStringView outPath, bool dualLayer, FProgress progressCB); DiscBuilderWii makeMergeBuilder(SystemStringView outPath, bool dualLayer, FProgress progressCB);
bool extractDiscHeaderFiles(SystemStringView path, const ExtractionContext& ctx) const; bool extractDiscHeaderFiles(SystemStringView path, const ExtractionContext& ctx) const;
}; };
class DiscBuilderWii : public DiscBuilderBase class DiscBuilderWii : public DiscBuilderBase {
{
public: public:
DiscBuilderWii(SystemStringView outPath, bool dualLayer, FProgress progressCB); DiscBuilderWii(SystemStringView outPath, bool dualLayer, FProgress progressCB);
EBuildResult buildFromDirectory(SystemStringView dirIn); EBuildResult buildFromDirectory(SystemStringView dirIn);
static uint64_t CalculateTotalSizeRequired(SystemStringView dirIn, bool& dualLayer); static uint64_t CalculateTotalSizeRequired(SystemStringView dirIn, bool& dualLayer);
}; };
class DiscMergerWii class DiscMergerWii {
{ DiscWii& m_sourceDisc;
DiscWii& m_sourceDisc; DiscBuilderWii m_builder;
DiscBuilderWii m_builder;
public: public:
DiscMergerWii(SystemStringView outPath, DiscWii& sourceDisc, DiscMergerWii(SystemStringView outPath, DiscWii& sourceDisc, bool dualLayer, FProgress progressCB);
bool dualLayer, FProgress progressCB); EBuildResult mergeFromDirectory(SystemStringView dirIn);
EBuildResult mergeFromDirectory(SystemStringView dirIn); static uint64_t CalculateTotalSizeRequired(DiscWii& sourceDisc, SystemStringView dirIn, bool& dualLayer);
static uint64_t CalculateTotalSizeRequired(DiscWii& sourceDisc, SystemStringView dirIn,
bool& dualLayer);
}; };
} } // namespace nod

View File

@ -10,64 +10,59 @@
#include <athena/IStreamWriter.hpp> #include <athena/IStreamWriter.hpp>
#endif #endif
namespace nod namespace nod {
{
struct IReadStream struct IReadStream {
{ virtual ~IReadStream() = default;
virtual ~IReadStream() = default; virtual uint64_t read(void* buf, uint64_t length) = 0;
virtual uint64_t read(void* buf, uint64_t length)=0; virtual void seek(int64_t offset, int whence = SEEK_SET) = 0;
virtual void seek(int64_t offset, int whence=SEEK_SET)=0; virtual uint64_t position() const = 0;
virtual uint64_t position() const=0;
}; };
struct IWriteStream struct IWriteStream {
{ virtual ~IWriteStream() = default;
virtual ~IWriteStream() = default; virtual uint64_t write(const void* buf, uint64_t length) = 0;
virtual uint64_t write(const void* buf, uint64_t length)=0;
}; };
class IDiscIO class IDiscIO {
{
public: public:
virtual ~IDiscIO() = default; virtual ~IDiscIO() = default;
virtual std::unique_ptr<IReadStream> beginReadStream(uint64_t offset=0) const=0; virtual std::unique_ptr<IReadStream> beginReadStream(uint64_t offset = 0) const = 0;
virtual std::unique_ptr<IWriteStream> beginWriteStream(uint64_t offset=0) const=0; virtual std::unique_ptr<IWriteStream> beginWriteStream(uint64_t offset = 0) const = 0;
}; };
struct IPartReadStream : IReadStream struct IPartReadStream : IReadStream {
{ virtual ~IPartReadStream() = default;
virtual ~IPartReadStream() = default;
}; };
struct IPartWriteStream : IWriteStream struct IPartWriteStream : IWriteStream {
{ virtual ~IPartWriteStream() = default;
virtual ~IPartWriteStream() = default; virtual void close() = 0;
virtual void close()=0; virtual uint64_t position() const = 0;
virtual uint64_t position() const=0;
}; };
#if NOD_ATHENA #if NOD_ATHENA
class AthenaPartReadStream : public athena::io::IStreamReader class AthenaPartReadStream : public athena::io::IStreamReader {
{ std::unique_ptr<IPartReadStream> m_rs;
std::unique_ptr<IPartReadStream> m_rs;
public:
AthenaPartReadStream(std::unique_ptr<IPartReadStream>&& rs) : m_rs(std::move(rs)) {}
inline void seek(atInt64 off, athena::SeekOrigin origin) public:
{ AthenaPartReadStream(std::unique_ptr<IPartReadStream>&& rs) : m_rs(std::move(rs)) {}
if (origin == athena::Begin)
m_rs->seek(off, SEEK_SET); inline void seek(atInt64 off, athena::SeekOrigin origin) {
else if (origin == athena::Current) if (origin == athena::Begin)
m_rs->seek(off, SEEK_CUR); m_rs->seek(off, SEEK_SET);
} else if (origin == athena::Current)
inline atUint64 position() const {return m_rs->position();} m_rs->seek(off, SEEK_CUR);
inline atUint64 length() const {return 0;} }
inline atUint64 readUBytesToBuf(void* buf, atUint64 sz) {m_rs->read(buf, sz); return sz;} inline atUint64 position() const { return m_rs->position(); }
inline atUint64 length() const { return 0; }
inline atUint64 readUBytesToBuf(void* buf, atUint64 sz) {
m_rs->read(buf, sz);
return sz;
}
}; };
#endif #endif
} } // namespace nod

View File

@ -6,79 +6,66 @@
#include "IDiscIO.hpp" #include "IDiscIO.hpp"
#include "Util.hpp" #include "Util.hpp"
namespace nod namespace nod {
{
class IFileIO class IFileIO {
{
public: public:
virtual ~IFileIO() = default; virtual ~IFileIO() = default;
virtual bool exists()=0; virtual bool exists() = 0;
virtual uint64_t size()=0; virtual uint64_t size() = 0;
struct IWriteStream : nod::IWriteStream struct IWriteStream : nod::IWriteStream {
{ uint64_t copyFromDisc(IPartReadStream& discio, uint64_t length) {
uint64_t copyFromDisc(IPartReadStream& discio, uint64_t length) uint64_t read = 0;
{ uint8_t buf[0x7c00];
uint64_t read = 0; while (length) {
uint8_t buf[0x7c00]; uint64_t thisSz = nod::min(uint64_t(0x7c00), length);
while (length) uint64_t readSz = discio.read(buf, thisSz);
{ if (thisSz != readSz) {
uint64_t thisSz = nod::min(uint64_t(0x7c00), length); LogModule.report(logvisor::Error, "unable to read enough from disc");
uint64_t readSz = discio.read(buf, thisSz); return read;
if (thisSz != readSz)
{
LogModule.report(logvisor::Error, "unable to read enough from disc");
return read;
}
if (write(buf, readSz) != readSz)
{
LogModule.report(logvisor::Error, "unable to write in file");
return read;
}
length -= thisSz;
read += thisSz;
}
return read;
} }
uint64_t copyFromDisc(IPartReadStream& discio, uint64_t length, const std::function<void(float)>& prog) if (write(buf, readSz) != readSz) {
{ LogModule.report(logvisor::Error, "unable to write in file");
uint64_t read = 0; return read;
uint8_t buf[0x7c00];
uint64_t total = length;
while (length)
{
uint64_t thisSz = nod::min(uint64_t(0x7c00), length);
uint64_t readSz = discio.read(buf, thisSz);
if (thisSz != readSz)
{
LogModule.report(logvisor::Error, "unable to read enough from disc");
return read;
}
if (write(buf, readSz) != readSz)
{
LogModule.report(logvisor::Error, "unable to write in file");
return read;
}
length -= thisSz;
read += thisSz;
prog(read / float(total));
}
return read;
} }
}; length -= thisSz;
virtual std::unique_ptr<IWriteStream> beginWriteStream() const=0; read += thisSz;
virtual std::unique_ptr<IWriteStream> beginWriteStream(uint64_t offset) const=0; }
return read;
}
uint64_t copyFromDisc(IPartReadStream& discio, uint64_t length, const std::function<void(float)>& prog) {
uint64_t read = 0;
uint8_t buf[0x7c00];
uint64_t total = length;
while (length) {
uint64_t thisSz = nod::min(uint64_t(0x7c00), length);
uint64_t readSz = discio.read(buf, thisSz);
if (thisSz != readSz) {
LogModule.report(logvisor::Error, "unable to read enough from disc");
return read;
}
if (write(buf, readSz) != readSz) {
LogModule.report(logvisor::Error, "unable to write in file");
return read;
}
length -= thisSz;
read += thisSz;
prog(read / float(total));
}
return read;
}
};
virtual std::unique_ptr<IWriteStream> beginWriteStream() const = 0;
virtual std::unique_ptr<IWriteStream> beginWriteStream(uint64_t offset) const = 0;
struct IReadStream : nod::IReadStream struct IReadStream : nod::IReadStream {
{ virtual uint64_t copyToDisc(struct IPartWriteStream& discio, uint64_t length) = 0;
virtual uint64_t copyToDisc(struct IPartWriteStream& discio, uint64_t length)=0; };
}; virtual std::unique_ptr<IReadStream> beginReadStream() const = 0;
virtual std::unique_ptr<IReadStream> beginReadStream() const=0; virtual std::unique_ptr<IReadStream> beginReadStream(uint64_t offset) const = 0;
virtual std::unique_ptr<IReadStream> beginReadStream(uint64_t offset) const=0;
}; };
std::unique_ptr<IFileIO> NewFileIO(SystemStringView path, int64_t maxWriteSize=-1); std::unique_ptr<IFileIO> NewFileIO(SystemStringView path, int64_t maxWriteSize = -1);
}
} // namespace nod

View File

@ -37,11 +37,11 @@
#include <sys/stat.h> #include <sys/stat.h>
#if !defined(S_ISREG) && defined(S_IFMT) && defined(S_IFREG) #if !defined(S_ISREG) && defined(S_IFMT) && defined(S_IFREG)
#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) #define S_ISREG(m) (((m)&S_IFMT) == S_IFREG)
#endif #endif
#if !defined(S_ISDIR) && defined(S_IFMT) && defined(S_IFDIR) #if !defined(S_ISDIR) && defined(S_IFMT) && defined(S_IFDIR)
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) #define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR)
#endif #endif
#if !defined(S_ISLNK) #if !defined(S_ISLNK)
@ -52,13 +52,16 @@
#undef min #undef min
#undef max #undef max
namespace nod namespace nod {
{
/* define our own min/max to avoid MSVC BS */ /* define our own min/max to avoid MSVC BS */
template<typename T> template <typename T>
inline T min(T a, T b) { return a < b ? a : b; } inline T min(T a, T b) {
template<typename T> return a < b ? a : b;
inline T max(T a, T b) { return a > b ? a : b; } }
template <typename T>
inline T max(T a, T b) {
return a > b ? a : b;
}
/* Log Module */ /* Log Module */
extern logvisor::Module LogModule; extern logvisor::Module LogModule;
@ -67,12 +70,12 @@ extern logvisor::Module LogModule;
#if _WIN32 && UNICODE #if _WIN32 && UNICODE
#define NOD_UCS2 1 #define NOD_UCS2 1
typedef struct _stat Sstat; typedef struct _stat Sstat;
static inline int Mkdir(const wchar_t* path, int) {return _wmkdir(path);} static inline int Mkdir(const wchar_t* path, int) { return _wmkdir(path); }
static inline int Stat(const wchar_t* path, Sstat* statout) {return _wstat(path, statout);} static inline int Stat(const wchar_t* path, Sstat* statout) { return _wstat(path, statout); }
#else #else
typedef struct stat Sstat; typedef struct stat Sstat;
static inline int Mkdir(const char* path, mode_t mode) {return mkdir(path, mode);} static inline int Mkdir(const char* path, mode_t mode) { return mkdir(path, mode); }
static inline int Stat(const char* path, Sstat* statout) {return stat(path, statout);} static inline int Stat(const char* path, Sstat* statout) { return stat(path, statout); }
#endif #endif
/* String-converting views */ /* String-converting views */
@ -80,96 +83,85 @@ static inline int Stat(const char* path, Sstat* statout) {return stat(path, stat
typedef wchar_t SystemChar; typedef wchar_t SystemChar;
typedef std::wstring SystemString; typedef std::wstring SystemString;
typedef std::wstring_view SystemStringView; typedef std::wstring_view SystemStringView;
static inline void ToLower(SystemString& str) static inline void ToLower(SystemString& str) { std::transform(str.begin(), str.end(), str.begin(), towlower); }
{std::transform(str.begin(), str.end(), str.begin(), towlower);} static inline void ToUpper(SystemString& str) { std::transform(str.begin(), str.end(), str.begin(), towupper); }
static inline void ToUpper(SystemString& str) static inline size_t StrLen(const SystemChar* str) { return wcslen(str); }
{std::transform(str.begin(), str.end(), str.begin(), towupper);} class SystemUTF8Conv {
static inline size_t StrLen(const SystemChar* str) {return wcslen(str);} std::string m_utf8;
class SystemUTF8Conv
{
std::string m_utf8;
public: public:
explicit SystemUTF8Conv(SystemStringView str) explicit SystemUTF8Conv(SystemStringView str) {
{ int len = WideCharToMultiByte(CP_UTF8, 0, str.data(), str.size(), nullptr, 0, nullptr, nullptr);
int len = WideCharToMultiByte(CP_UTF8, 0, str.data(), str.size(), nullptr, 0, nullptr, nullptr); m_utf8.assign(len, '\0');
m_utf8.assign(len, '\0'); WideCharToMultiByte(CP_UTF8, 0, str.data(), str.size(), &m_utf8[0], len, nullptr, nullptr);
WideCharToMultiByte(CP_UTF8, 0, str.data(), str.size(), &m_utf8[0], len, nullptr, nullptr); }
} inline std::string_view utf8_str() const { return m_utf8; }
inline std::string_view utf8_str() const {return m_utf8;} inline const char* c_str() const { return m_utf8.c_str(); }
inline const char* c_str() const {return m_utf8.c_str();}
}; };
class SystemStringConv class SystemStringConv {
{ std::wstring m_sys;
std::wstring m_sys;
public: public:
explicit SystemStringConv(std::string_view str) explicit SystemStringConv(std::string_view str) {
{ int len = MultiByteToWideChar(CP_UTF8, 0, str.data(), str.size(), nullptr, 0);
int len = MultiByteToWideChar(CP_UTF8, 0, str.data(), str.size(), nullptr, 0); m_sys.assign(len, L'\0');
m_sys.assign(len, L'\0'); MultiByteToWideChar(CP_UTF8, 0, str.data(), str.size(), &m_sys[0], len);
MultiByteToWideChar(CP_UTF8, 0, str.data(), str.size(), &m_sys[0], len); }
} inline SystemStringView sys_str() const { return m_sys; }
inline SystemStringView sys_str() const {return m_sys;} inline const SystemChar* c_str() const { return m_sys.c_str(); }
inline const SystemChar* c_str() const {return m_sys.c_str();}
}; };
#ifndef _SYS_STR #ifndef _SYS_STR
#define _SYS_STR(val) L ## val #define _SYS_STR(val) L##val
#endif #endif
#else #else
typedef char SystemChar; typedef char SystemChar;
typedef std::string SystemString; typedef std::string SystemString;
typedef std::string_view SystemStringView; typedef std::string_view SystemStringView;
static inline void ToLower(SystemString& str) static inline void ToLower(SystemString& str) { std::transform(str.begin(), str.end(), str.begin(), tolower); }
{std::transform(str.begin(), str.end(), str.begin(), tolower);} static inline void ToUpper(SystemString& str) { std::transform(str.begin(), str.end(), str.begin(), toupper); }
static inline void ToUpper(SystemString& str) static inline size_t StrLen(const SystemChar* str) { return strlen(str); }
{std::transform(str.begin(), str.end(), str.begin(), toupper);} class SystemUTF8Conv {
static inline size_t StrLen(const SystemChar* str) {return strlen(str);} std::string_view m_utf8;
class SystemUTF8Conv
{
std::string_view m_utf8;
public: public:
explicit SystemUTF8Conv(SystemStringView str) explicit SystemUTF8Conv(SystemStringView str) : m_utf8(str) {}
: m_utf8(str) {} inline std::string_view utf8_str() const { return m_utf8; }
inline std::string_view utf8_str() const {return m_utf8;} inline const char* c_str() const { return m_utf8.data(); }
inline const char* c_str() const {return m_utf8.data();}
}; };
class SystemStringConv class SystemStringConv {
{ SystemStringView m_sys;
SystemStringView m_sys;
public: public:
explicit SystemStringConv(std::string_view str) explicit SystemStringConv(std::string_view str) : m_sys(str) {}
: m_sys(str) {} inline SystemStringView sys_str() const { return m_sys; }
inline SystemStringView sys_str() const {return m_sys;} inline const SystemChar* c_str() const { return m_sys.data(); }
inline const SystemChar* c_str() const {return m_sys.data();}
}; };
#ifndef _SYS_STR #ifndef _SYS_STR
#define _SYS_STR(val) val #define _SYS_STR(val) val
#endif #endif
#endif #endif
static inline void Unlink(const SystemChar* file) static inline void Unlink(const SystemChar* file) {
{
#if NOD_UCS2 #if NOD_UCS2
_wunlink(file); _wunlink(file);
#else #else
unlink(file); unlink(file);
#endif #endif
} }
static inline int StrCmp(const SystemChar* str1, const SystemChar* str2) static inline int StrCmp(const SystemChar* str1, const SystemChar* str2) {
{
#if NOD_UCS2 #if NOD_UCS2
return wcscmp(str1, str2); return wcscmp(str1, str2);
#else #else
return strcmp(str1, str2); return strcmp(str1, str2);
#endif #endif
} }
static inline int StrCaseCmp(const SystemChar* str1, const SystemChar* str2) static inline int StrCaseCmp(const SystemChar* str1, const SystemChar* str2) {
{
#if NOD_UCS2 #if NOD_UCS2
return _wcsicmp(str1, str2); return _wcsicmp(str1, str2);
#else #else
return strcasecmp(str1, str2); return strcasecmp(str1, str2);
#endif #endif
} }
@ -178,79 +170,71 @@ static inline int StrCaseCmp(const SystemChar* str1, const SystemChar* str2)
#undef bswap64 #undef bswap64
/* Type-sensitive byte swappers */ /* Type-sensitive byte swappers */
template <typename T> template <typename T>
static inline T bswap16(T val) static inline T bswap16(T val) {
{
#if __GNUC__ #if __GNUC__
return __builtin_bswap16(val); return __builtin_bswap16(val);
#elif _WIN32 #elif _WIN32
return _byteswap_ushort(val); return _byteswap_ushort(val);
#else #else
return (val = (val << 8) | ((val >> 8) & 0xFF)); return (val = (val << 8) | ((val >> 8) & 0xFF));
#endif #endif
} }
template <typename T> template <typename T>
static inline T bswap32(T val) static inline T bswap32(T val) {
{
#if __GNUC__ #if __GNUC__
return __builtin_bswap32(val); return __builtin_bswap32(val);
#elif _WIN32 #elif _WIN32
return _byteswap_ulong(val); return _byteswap_ulong(val);
#else #else
val = (val & 0x0000FFFF) << 16 | (val & 0xFFFF0000) >> 16; val = (val & 0x0000FFFF) << 16 | (val & 0xFFFF0000) >> 16;
val = (val & 0x00FF00FF) << 8 | (val & 0xFF00FF00) >> 8; val = (val & 0x00FF00FF) << 8 | (val & 0xFF00FF00) >> 8;
return val; return val;
#endif #endif
} }
template <typename T> template <typename T>
static inline T bswap64(T val) static inline T bswap64(T val) {
{
#if __GNUC__ #if __GNUC__
return __builtin_bswap64(val); return __builtin_bswap64(val);
#elif _WIN32 #elif _WIN32
return _byteswap_uint64(val); return _byteswap_uint64(val);
#else #else
return ((val & 0xFF00000000000000ULL) >> 56) | return ((val & 0xFF00000000000000ULL) >> 56) | ((val & 0x00FF000000000000ULL) >> 40) |
((val & 0x00FF000000000000ULL) >> 40) | ((val & 0x0000FF0000000000ULL) >> 24) | ((val & 0x000000FF00000000ULL) >> 8) |
((val & 0x0000FF0000000000ULL) >> 24) | ((val & 0x00000000FF000000ULL) << 8) | ((val & 0x0000000000FF0000ULL) << 24) |
((val & 0x000000FF00000000ULL) >> 8) | ((val & 0x000000000000FF00ULL) << 40) | ((val & 0x00000000000000FFULL) << 56);
((val & 0x00000000FF000000ULL) << 8) |
((val & 0x0000000000FF0000ULL) << 24) |
((val & 0x000000000000FF00ULL) << 40) |
((val & 0x00000000000000FFULL) << 56);
#endif #endif
} }
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
static inline int16_t SBig(int16_t val) {return bswap16(val);} static inline int16_t SBig(int16_t val) { return bswap16(val); }
static inline uint16_t SBig(uint16_t val) {return bswap16(val);} static inline uint16_t SBig(uint16_t val) { return bswap16(val); }
static inline int32_t SBig(int32_t val) {return bswap32(val);} static inline int32_t SBig(int32_t val) { return bswap32(val); }
static inline uint32_t SBig(uint32_t val) {return bswap32(val);} static inline uint32_t SBig(uint32_t val) { return bswap32(val); }
static inline int64_t SBig(int64_t val) {return bswap64(val);} static inline int64_t SBig(int64_t val) { return bswap64(val); }
static inline uint64_t SBig(uint64_t val) {return bswap64(val);} static inline uint64_t SBig(uint64_t val) { return bswap64(val); }
static inline int16_t SLittle(int16_t val) {return val;} static inline int16_t SLittle(int16_t val) { return val; }
static inline uint16_t SLittle(uint16_t val) {return val;} static inline uint16_t SLittle(uint16_t val) { return val; }
static inline int32_t SLittle(int32_t val) {return val;} static inline int32_t SLittle(int32_t val) { return val; }
static inline uint32_t SLittle(uint32_t val) {return val;} static inline uint32_t SLittle(uint32_t val) { return val; }
static inline int64_t SLittle(int64_t val) {return val;} static inline int64_t SLittle(int64_t val) { return val; }
static inline uint64_t SLittle(uint64_t val) {return val;} static inline uint64_t SLittle(uint64_t val) { return val; }
#else #else
static inline int16_t SLittle(int16_t val) {return bswap16(val);} static inline int16_t SLittle(int16_t val) { return bswap16(val); }
static inline uint16_t SLittle(uint16_t val) {return bswap16(val);} static inline uint16_t SLittle(uint16_t val) { return bswap16(val); }
static inline int32_t SLittle(int32_t val) {return bswap32(val);} static inline int32_t SLittle(int32_t val) { return bswap32(val); }
static inline uint32_t SLittle(uint32_t val) {return bswap32(val);} static inline uint32_t SLittle(uint32_t val) { return bswap32(val); }
static inline int64_t SLittle(int64_t val) {return bswap64(val);} static inline int64_t SLittle(int64_t val) { return bswap64(val); }
static inline uint64_t SLittle(uint64_t val) {return bswap64(val);} static inline uint64_t SLittle(uint64_t val) { return bswap64(val); }
static inline int16_t SBig(int16_t val) {return val;} static inline int16_t SBig(int16_t val) { return val; }
static inline uint16_t SBig(uint16_t val) {return val;} static inline uint16_t SBig(uint16_t val) { return val; }
static inline int32_t SBig(int32_t val) {return val;} static inline int32_t SBig(int32_t val) { return val; }
static inline uint32_t SBig(uint32_t val) {return val;} static inline uint32_t SBig(uint32_t val) { return val; }
static inline int64_t SBig(int64_t val) {return val;} static inline int64_t SBig(int64_t val) { return val; }
static inline uint64_t SBig(uint64_t val) {return val;} static inline uint64_t SBig(uint64_t val) { return val; }
#endif #endif
#ifndef ROUND_UP_32 #ifndef ROUND_UP_32
@ -258,105 +242,92 @@ static inline uint64_t SBig(uint64_t val) {return val;}
#define ROUND_UP_16(val) (((val) + 15) & ~15) #define ROUND_UP_16(val) (((val) + 15) & ~15)
#endif #endif
enum class FileLockType enum class FileLockType { None = 0, Read, Write };
{ static inline FILE* Fopen(const SystemChar* path, const SystemChar* mode, FileLockType lock = FileLockType::None) {
None = 0,
Read,
Write
};
static inline FILE* Fopen(const SystemChar* path, const SystemChar* mode, FileLockType lock=FileLockType::None)
{
#if NOD_UCS2 #if NOD_UCS2
FILE* fp = _wfopen(path, mode); FILE* fp = _wfopen(path, mode);
if (!fp) if (!fp)
return nullptr; return nullptr;
#else #else
FILE* fp = fopen(path, mode); FILE* fp = fopen(path, mode);
if (!fp) if (!fp)
return nullptr; return nullptr;
#endif #endif
if (lock != FileLockType::None) if (lock != FileLockType::None) {
{
#if _WIN32 #if _WIN32
OVERLAPPED ov = {}; OVERLAPPED ov = {};
LockFileEx((HANDLE)(uintptr_t)_fileno(fp), (lock == FileLockType::Write) ? LOCKFILE_EXCLUSIVE_LOCK : 0, 0, 0, 1, &ov); LockFileEx((HANDLE)(uintptr_t)_fileno(fp), (lock == FileLockType::Write) ? LOCKFILE_EXCLUSIVE_LOCK : 0, 0, 0, 1,
&ov);
#else #else
if (flock(fileno(fp), ((lock == FileLockType::Write) ? LOCK_EX : LOCK_SH) | LOCK_NB)) if (flock(fileno(fp), ((lock == FileLockType::Write) ? LOCK_EX : LOCK_SH) | LOCK_NB))
LogModule.report(logvisor::Error, "flock %s: %s", path, strerror(errno)); LogModule.report(logvisor::Error, "flock %s: %s", path, strerror(errno));
#endif #endif
} }
return fp; return fp;
} }
static inline int FSeek(FILE* fp, int64_t offset, int whence) static inline int FSeek(FILE* fp, int64_t offset, int whence) {
{
#if _WIN32 #if _WIN32
return _fseeki64(fp, offset, whence); return _fseeki64(fp, offset, whence);
#elif __APPLE__ || __FreeBSD__ #elif __APPLE__ || __FreeBSD__
return fseeko(fp, offset, whence); return fseeko(fp, offset, whence);
#else #else
return fseeko64(fp, offset, whence); return fseeko64(fp, offset, whence);
#endif #endif
} }
static inline int64_t FTell(FILE* fp) static inline int64_t FTell(FILE* fp) {
{
#if _WIN32 #if _WIN32
return _ftelli64(fp); return _ftelli64(fp);
#elif __APPLE__ || __FreeBSD__ #elif __APPLE__ || __FreeBSD__
return ftello(fp); return ftello(fp);
#else #else
return ftello64(fp); return ftello64(fp);
#endif #endif
} }
static inline bool CheckFreeSpace(const SystemChar* path, size_t reqSz) static inline bool CheckFreeSpace(const SystemChar* path, size_t reqSz) {
{
#if _WIN32 #if _WIN32
ULARGE_INTEGER freeBytes; ULARGE_INTEGER freeBytes;
wchar_t buf[1024]; wchar_t buf[1024];
wchar_t* end; wchar_t* end;
DWORD ret = GetFullPathNameW(path, 1024, buf, &end); DWORD ret = GetFullPathNameW(path, 1024, buf, &end);
if (!ret || ret > 1024) if (!ret || ret > 1024) {
{ LogModule.report(logvisor::Error, _SYS_STR("GetFullPathNameW %s"), path);
LogModule.report(logvisor::Error, _SYS_STR("GetFullPathNameW %s"), path); return false;
return false; }
} if (end)
if (end) end[0] = L'\0';
end[0] = L'\0'; if (!GetDiskFreeSpaceExW(buf, &freeBytes, nullptr, nullptr)) {
if (!GetDiskFreeSpaceExW(buf, &freeBytes, nullptr, nullptr)) LogModule.report(logvisor::Error, _SYS_STR("GetDiskFreeSpaceExW %s: %d"), path, GetLastError());
{ return false;
LogModule.report(logvisor::Error, _SYS_STR("GetDiskFreeSpaceExW %s: %d"), path, GetLastError()); }
return false; return reqSz < freeBytes.QuadPart;
}
return reqSz < freeBytes.QuadPart;
#else #else
struct statvfs svfs; struct statvfs svfs;
if (statvfs(path, &svfs)) if (statvfs(path, &svfs)) {
{ LogModule.report(logvisor::Error, "statvfs %s: %s", path, strerror(errno));
LogModule.report(logvisor::Error, "statvfs %s: %s", path, strerror(errno)); return false;
return false; }
} return reqSz < svfs.f_frsize * svfs.f_bavail;
return reqSz < svfs.f_frsize * svfs.f_bavail;
#endif #endif
} }
#if __GNUC__ #if __GNUC__
__attribute__((__format__ (__printf__, 1, 2))) __attribute__((__format__(__printf__, 1, 2)))
#endif #endif
static inline void Printf(const SystemChar* fmt, ...) static inline void
{ Printf(const SystemChar* fmt, ...) {
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
#if NOD_UCS2 #if NOD_UCS2
vwprintf(fmt, args); vwprintf(fmt, args);
#else #else
vprintf(fmt, args); vprintf(fmt, args);
#endif #endif
va_end(args); va_end(args);
}
} }
} // namespace nod

View File

@ -4,19 +4,16 @@
#include <cstdlib> #include <cstdlib>
#include <memory> #include <memory>
namespace nod namespace nod {
{
class IAES class IAES {
{
public: public:
virtual ~IAES() = default; virtual ~IAES() = default;
virtual void encrypt(const uint8_t* iv, const uint8_t* inbuf, uint8_t* outbuf, size_t len)=0; virtual void encrypt(const uint8_t* iv, const uint8_t* inbuf, uint8_t* outbuf, size_t len) = 0;
virtual void decrypt(const uint8_t* iv, const uint8_t* inbuf, uint8_t* outbuf, size_t len)=0; virtual void decrypt(const uint8_t* iv, const uint8_t* inbuf, uint8_t* outbuf, size_t len) = 0;
virtual void setKey(const uint8_t* key)=0; virtual void setKey(const uint8_t* key) = 0;
}; };
std::unique_ptr<IAES> NewAES(); std::unique_ptr<IAES> NewAES();
} } // namespace nod

View File

@ -5,23 +5,20 @@
#include "logvisor/logvisor.hpp" #include "logvisor/logvisor.hpp"
#include "Util.hpp" #include "Util.hpp"
namespace nod namespace nod {
{
class DiscBase; class DiscBase;
struct ExtractionContext final struct ExtractionContext final {
{ bool force : 1;
bool force : 1; std::function<void(std::string_view, float)> progressCB;
std::function<void(std::string_view, float)> progressCB;
}; };
std::unique_ptr<DiscBase> OpenDiscFromImage(SystemStringView path); std::unique_ptr<DiscBase> OpenDiscFromImage(SystemStringView path);
std::unique_ptr<DiscBase> OpenDiscFromImage(SystemStringView path, bool& isWii); std::unique_ptr<DiscBase> OpenDiscFromImage(SystemStringView path, bool& isWii);
} } // namespace nod
#include "DiscGCN.hpp" #include "DiscGCN.hpp"
#include "DiscWii.hpp" #include "DiscWii.hpp"
#include "IDiscIO.hpp" #include "IDiscIO.hpp"

View File

@ -9,275 +9,252 @@
#include "nod/DirectoryEnumerator.hpp" #include "nod/DirectoryEnumerator.hpp"
namespace nod namespace nod {
{
DirectoryEnumerator::DirectoryEnumerator(SystemStringView path, Mode mode, DirectoryEnumerator::DirectoryEnumerator(SystemStringView path, Mode mode, bool sizeSort, bool reverse, bool noHidden) {
bool sizeSort, bool reverse, bool noHidden) Sstat theStat;
{ if (Stat(path.data(), &theStat) || !S_ISDIR(theStat.st_mode))
Sstat theStat; return;
if (Stat(path.data(), &theStat) || !S_ISDIR(theStat.st_mode))
return;
#if _WIN32 #if _WIN32
SystemString wc(path); SystemString wc(path);
wc += _SYS_STR("/*"); wc += _SYS_STR("/*");
WIN32_FIND_DATAW d; WIN32_FIND_DATAW d;
HANDLE dir = FindFirstFileW(wc.c_str(), &d); HANDLE dir = FindFirstFileW(wc.c_str(), &d);
if (dir == INVALID_HANDLE_VALUE) if (dir == INVALID_HANDLE_VALUE)
return; return;
switch (mode) switch (mode) {
{ case Mode::Native:
case Mode::Native: do {
do if (!wcscmp(d.cFileName, _SYS_STR(".")) || !wcscmp(d.cFileName, _SYS_STR("..")))
{ continue;
if (!wcscmp(d.cFileName, _SYS_STR(".")) || !wcscmp(d.cFileName, _SYS_STR(".."))) if (noHidden && (d.cFileName[0] == L'.' || (d.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0))
continue; continue;
if (noHidden && (d.cFileName[0] == L'.' || (d.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0)) SystemString fp(path);
continue; fp += _SYS_STR('/');
SystemString fp(path); fp += d.cFileName;
fp += _SYS_STR('/'); Sstat st;
fp += d.cFileName; if (Stat(fp.c_str(), &st))
Sstat st; continue;
if (Stat(fp.c_str(), &st))
continue;
size_t sz = 0; size_t sz = 0;
bool isDir = false; bool isDir = false;
if (S_ISDIR(st.st_mode)) if (S_ISDIR(st.st_mode))
isDir = true; isDir = true;
else if (S_ISREG(st.st_mode)) else if (S_ISREG(st.st_mode))
sz = st.st_size; sz = st.st_size;
else else
continue; continue;
m_entries.push_back(Entry(fp, d.cFileName, sz, isDir)); m_entries.push_back(Entry(fp, d.cFileName, sz, isDir));
} while (FindNextFileW(dir, &d)); } while (FindNextFileW(dir, &d));
break; break;
case Mode::DirsThenFilesSorted: case Mode::DirsThenFilesSorted:
case Mode::DirsSorted: case Mode::DirsSorted: {
{ std::map<SystemString, Entry, CaseInsensitiveCompare> sort;
std::map<SystemString, Entry, CaseInsensitiveCompare> sort; do {
do if (!wcscmp(d.cFileName, _SYS_STR(".")) || !wcscmp(d.cFileName, _SYS_STR("..")))
{ continue;
if (!wcscmp(d.cFileName, _SYS_STR(".")) || !wcscmp(d.cFileName, _SYS_STR(".."))) if (noHidden && (d.cFileName[0] == L'.' || (d.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0))
continue; continue;
if (noHidden && (d.cFileName[0] == L'.' || (d.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0)) SystemString fp(path);
continue; fp += _SYS_STR('/');
SystemString fp(path); fp += d.cFileName;
fp +=_SYS_STR('/'); Sstat st;
fp += d.cFileName; if (Stat(fp.c_str(), &st) || !S_ISDIR(st.st_mode))
Sstat st; continue;
if (Stat(fp.c_str(), &st) || !S_ISDIR(st.st_mode)) sort.emplace(std::make_pair(d.cFileName, Entry(fp, d.cFileName, 0, true)));
continue; } while (FindNextFileW(dir, &d));
sort.emplace(std::make_pair(d.cFileName, Entry(fp, d.cFileName, 0, true)));
} while (FindNextFileW(dir, &d));
m_entries.reserve(sort.size()); m_entries.reserve(sort.size());
if (reverse) if (reverse)
for (auto it=sort.crbegin() ; it != sort.crend() ; ++it) for (auto it = sort.crbegin(); it != sort.crend(); ++it)
m_entries.push_back(std::move(it->second)); m_entries.push_back(std::move(it->second));
else else
for (auto& e : sort) for (auto& e : sort)
m_entries.push_back(std::move(e.second)); m_entries.push_back(std::move(e.second));
if (mode == Mode::DirsSorted) if (mode == Mode::DirsSorted)
break; break;
FindClose(dir);
dir = FindFirstFileW(wc.c_str(), &d);
}
case Mode::FilesSorted:
{
if (mode == Mode::FilesSorted)
m_entries.clear();
if (sizeSort)
{
std::multimap<size_t, Entry> sort;
do
{
if (!wcscmp(d.cFileName, _SYS_STR(".")) || !wcscmp(d.cFileName, _SYS_STR("..")))
continue;
if (noHidden && (d.cFileName[0] == L'.' || (d.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0))
continue;
SystemString fp(path);
fp += _SYS_STR('/');
fp += d.cFileName;
Sstat st;
if (Stat(fp.c_str(), &st) || !S_ISREG(st.st_mode))
continue;
sort.emplace(std::make_pair(st.st_size, Entry(fp, d.cFileName, st.st_size, false)));
} while (FindNextFileW(dir, &d));
m_entries.reserve(sort.size());
if (reverse)
for (auto it=sort.crbegin() ; it != sort.crend() ; ++it)
m_entries.push_back(std::move(it->second));
else
for (auto& e : sort)
m_entries.push_back(std::move(e.second));
}
else
{
std::map<SystemString, Entry, CaseInsensitiveCompare> sort;
do
{
if (!wcscmp(d.cFileName, _SYS_STR(".")) || !wcscmp(d.cFileName, _SYS_STR("..")))
continue;
if (noHidden && (d.cFileName[0] == L'.' || (d.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0))
continue;
SystemString fp(path);
fp += _SYS_STR('/');
fp += d.cFileName;
Sstat st;
if (Stat(fp.c_str(), &st) || !S_ISREG(st.st_mode))
continue;
sort.emplace(std::make_pair(d.cFileName, Entry(fp, d.cFileName, st.st_size, false)));
} while (FindNextFileW(dir, &d));
m_entries.reserve(sort.size());
if (reverse)
for (auto it=sort.crbegin() ; it != sort.crend() ; ++it)
m_entries.push_back(std::move(it->second));
else
for (auto& e : sort)
m_entries.push_back(std::move(e.second));
}
break;
}
}
FindClose(dir); FindClose(dir);
dir = FindFirstFileW(wc.c_str(), &d);
}
case Mode::FilesSorted: {
if (mode == Mode::FilesSorted)
m_entries.clear();
if (sizeSort) {
std::multimap<size_t, Entry> sort;
do {
if (!wcscmp(d.cFileName, _SYS_STR(".")) || !wcscmp(d.cFileName, _SYS_STR("..")))
continue;
if (noHidden && (d.cFileName[0] == L'.' || (d.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0))
continue;
SystemString fp(path);
fp += _SYS_STR('/');
fp += d.cFileName;
Sstat st;
if (Stat(fp.c_str(), &st) || !S_ISREG(st.st_mode))
continue;
sort.emplace(std::make_pair(st.st_size, Entry(fp, d.cFileName, st.st_size, false)));
} while (FindNextFileW(dir, &d));
m_entries.reserve(sort.size());
if (reverse)
for (auto it = sort.crbegin(); it != sort.crend(); ++it)
m_entries.push_back(std::move(it->second));
else
for (auto& e : sort)
m_entries.push_back(std::move(e.second));
} else {
std::map<SystemString, Entry, CaseInsensitiveCompare> sort;
do {
if (!wcscmp(d.cFileName, _SYS_STR(".")) || !wcscmp(d.cFileName, _SYS_STR("..")))
continue;
if (noHidden && (d.cFileName[0] == L'.' || (d.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0))
continue;
SystemString fp(path);
fp += _SYS_STR('/');
fp += d.cFileName;
Sstat st;
if (Stat(fp.c_str(), &st) || !S_ISREG(st.st_mode))
continue;
sort.emplace(std::make_pair(d.cFileName, Entry(fp, d.cFileName, st.st_size, false)));
} while (FindNextFileW(dir, &d));
m_entries.reserve(sort.size());
if (reverse)
for (auto it = sort.crbegin(); it != sort.crend(); ++it)
m_entries.push_back(std::move(it->second));
else
for (auto& e : sort)
m_entries.push_back(std::move(e.second));
}
break;
}
}
FindClose(dir);
#else #else
DIR* dir = opendir(path.data()); DIR* dir = opendir(path.data());
if (!dir) if (!dir)
return; return;
const dirent* d; const dirent* d;
switch (mode) switch (mode) {
{ case Mode::Native:
case Mode::Native: while ((d = readdir(dir))) {
while ((d = readdir(dir))) if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
{ continue;
if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) if (noHidden && d->d_name[0] == '.')
continue; continue;
if (noHidden && d->d_name[0] == '.') SystemString fp(path);
continue; fp += '/';
SystemString fp(path); fp += d->d_name;
fp += '/'; Sstat st;
fp += d->d_name; if (Stat(fp.c_str(), &st))
Sstat st; continue;
if (Stat(fp.c_str(), &st))
continue;
size_t sz = 0; size_t sz = 0;
bool isDir = false; bool isDir = false;
if (S_ISDIR(st.st_mode)) if (S_ISDIR(st.st_mode))
isDir = true; isDir = true;
else if (S_ISREG(st.st_mode)) else if (S_ISREG(st.st_mode))
sz = st.st_size; sz = st.st_size;
else else
continue; continue;
m_entries.push_back(Entry(fp, d->d_name, sz, isDir)); m_entries.push_back(Entry(fp, d->d_name, sz, isDir));
}
break;
case Mode::DirsThenFilesSorted:
case Mode::DirsSorted:
{
std::map<SystemString, Entry, CaseInsensitiveCompare> sort;
while ((d = readdir(dir)))
{
if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
continue;
if (noHidden && d->d_name[0] == '.')
continue;
SystemString fp(path);
fp += '/';
fp += d->d_name;
Sstat st;
if (Stat(fp.c_str(), &st) || !S_ISDIR(st.st_mode))
continue;
sort.emplace(std::make_pair(d->d_name, Entry(fp, d->d_name, 0, true)));
}
m_entries.reserve(sort.size());
if (reverse)
for (auto it=sort.crbegin() ; it != sort.crend() ; ++it)
m_entries.push_back(std::move(it->second));
else
for (auto& e : sort)
m_entries.push_back(std::move(e.second));
if (mode == Mode::DirsSorted)
break;
rewinddir(dir);
} }
case Mode::FilesSorted: break;
{ case Mode::DirsThenFilesSorted:
if (mode == Mode::FilesSorted) case Mode::DirsSorted: {
m_entries.clear(); std::map<SystemString, Entry, CaseInsensitiveCompare> sort;
while ((d = readdir(dir))) {
if (sizeSort) if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
{ continue;
std::multimap<size_t, Entry> sort; if (noHidden && d->d_name[0] == '.')
while ((d = readdir(dir))) continue;
{ SystemString fp(path);
if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) fp += '/';
continue; fp += d->d_name;
if (noHidden && d->d_name[0] == '.') Sstat st;
continue; if (Stat(fp.c_str(), &st) || !S_ISDIR(st.st_mode))
SystemString fp(path); continue;
fp += '/'; sort.emplace(std::make_pair(d->d_name, Entry(fp, d->d_name, 0, true)));
fp += d->d_name;
Sstat st;
if (Stat(fp.c_str(), &st) || !S_ISREG(st.st_mode))
continue;
sort.emplace(std::make_pair(st.st_size, Entry(fp, d->d_name, st.st_size, false)));
}
m_entries.reserve(sort.size());
if (reverse)
for (auto it=sort.crbegin() ; it != sort.crend() ; ++it)
m_entries.push_back(std::move(it->second));
else
for (auto& e : sort)
m_entries.push_back(std::move(e.second));
}
else
{
std::map<SystemString, Entry, CaseInsensitiveCompare> sort;
while ((d = readdir(dir)))
{
if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
continue;
if (noHidden && d->d_name[0] == '.')
continue;
SystemString fp(path);
fp += '/';
fp += d->d_name;
Sstat st;
if (Stat(fp.c_str(), &st) || !S_ISREG(st.st_mode))
continue;
sort.emplace(std::make_pair(d->d_name, Entry(fp, d->d_name, st.st_size, false)));
}
m_entries.reserve(sort.size());
if (reverse)
for (auto it=sort.crbegin() ; it != sort.crend() ; ++it)
m_entries.push_back(std::move(it->second));
else
for (auto& e : sort)
m_entries.push_back(std::move(e.second));
}
break;
} }
m_entries.reserve(sort.size());
if (reverse)
for (auto it = sort.crbegin(); it != sort.crend(); ++it)
m_entries.push_back(std::move(it->second));
else
for (auto& e : sort)
m_entries.push_back(std::move(e.second));
if (mode == Mode::DirsSorted)
break;
rewinddir(dir);
}
case Mode::FilesSorted: {
if (mode == Mode::FilesSorted)
m_entries.clear();
if (sizeSort) {
std::multimap<size_t, Entry> sort;
while ((d = readdir(dir))) {
if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
continue;
if (noHidden && d->d_name[0] == '.')
continue;
SystemString fp(path);
fp += '/';
fp += d->d_name;
Sstat st;
if (Stat(fp.c_str(), &st) || !S_ISREG(st.st_mode))
continue;
sort.emplace(std::make_pair(st.st_size, Entry(fp, d->d_name, st.st_size, false)));
}
m_entries.reserve(sort.size());
if (reverse)
for (auto it = sort.crbegin(); it != sort.crend(); ++it)
m_entries.push_back(std::move(it->second));
else
for (auto& e : sort)
m_entries.push_back(std::move(e.second));
} else {
std::map<SystemString, Entry, CaseInsensitiveCompare> sort;
while ((d = readdir(dir))) {
if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
continue;
if (noHidden && d->d_name[0] == '.')
continue;
SystemString fp(path);
fp += '/';
fp += d->d_name;
Sstat st;
if (Stat(fp.c_str(), &st) || !S_ISREG(st.st_mode))
continue;
sort.emplace(std::make_pair(d->d_name, Entry(fp, d->d_name, st.st_size, false)));
}
m_entries.reserve(sort.size());
if (reverse)
for (auto it = sort.crbegin(); it != sort.crend(); ++it)
m_entries.push_back(std::move(it->second));
else
for (auto& e : sort)
m_entries.push_back(std::move(e.second));
} }
closedir(dir);
break;
}
}
closedir(dir);
#endif #endif
} }
} } // namespace nod

File diff suppressed because it is too large Load Diff

View File

@ -3,474 +3,414 @@
#include <cinttypes> #include <cinttypes>
#define BUFFER_SZ 0x8000 #define BUFFER_SZ 0x8000
namespace nod namespace nod {
{
class PartitionGCN : public IPartition class PartitionGCN : public IPartition {
{
public: public:
PartitionGCN(const DiscGCN& parent, uint64_t offset, bool& err) PartitionGCN(const DiscGCN& parent, uint64_t offset, bool& err)
: IPartition(parent, PartitionKind::Data, false, offset) : IPartition(parent, PartitionKind::Data, false, offset) {
{ /* GCN-specific header reads */
/* GCN-specific header reads */ std::unique_ptr<IPartReadStream> s = beginReadStream(0x0);
std::unique_ptr<IPartReadStream> s = beginReadStream(0x0); if (!s) {
if (!s) err = true;
{ return;
err = true;
return;
}
m_header.read(*s);
m_bi2Header.read(*s);
m_dolOff = m_header.m_dolOff;
m_fstOff = m_header.m_fstOff;
m_fstSz = m_header.m_fstSz;
uint32_t vals[2];
s->seek(0x2440 + 0x14);
s->read(vals, 8);
m_apploaderSz = 32 + SBig(vals[0]) + SBig(vals[1]);
/* Yay files!! */
parseFST(*s);
/* Also make DOL header and size handy */
s->seek(m_dolOff);
parseDOL(*s);
} }
m_header.read(*s);
m_bi2Header.read(*s);
m_dolOff = m_header.m_dolOff;
m_fstOff = m_header.m_fstOff;
m_fstSz = m_header.m_fstSz;
uint32_t vals[2];
s->seek(0x2440 + 0x14);
s->read(vals, 8);
m_apploaderSz = 32 + SBig(vals[0]) + SBig(vals[1]);
class PartReadStream : public IPartReadStream /* Yay files!! */
{ parseFST(*s);
const PartitionGCN& m_parent;
std::unique_ptr<IReadStream> m_dio;
uint64_t m_offset; /* Also make DOL header and size handy */
size_t m_curBlock = SIZE_MAX; s->seek(m_dolOff);
uint8_t m_buf[BUFFER_SZ]; parseDOL(*s);
}
public: class PartReadStream : public IPartReadStream {
PartReadStream(const PartitionGCN& parent, uint64_t offset, bool& err) const PartitionGCN& m_parent;
: m_parent(parent), m_offset(offset) std::unique_ptr<IReadStream> m_dio;
{
size_t block = m_offset / BUFFER_SZ;
m_dio = m_parent.m_parent.getDiscIO().beginReadStream(block * BUFFER_SZ);
if (!m_dio)
{
err = true;
return;
}
m_dio->read(m_buf, BUFFER_SZ);
m_curBlock = block;
}
void seek(int64_t offset, int whence)
{
if (whence == SEEK_SET)
m_offset = offset;
else if (whence == SEEK_CUR)
m_offset += offset;
else
return;
size_t block = m_offset / BUFFER_SZ;
if (block != m_curBlock)
{
m_dio->seek(block * BUFFER_SZ);
m_dio->read(m_buf, BUFFER_SZ);
m_curBlock = block;
}
}
uint64_t position() const {return m_offset;}
uint64_t read(void* buf, uint64_t length)
{
size_t block = m_offset / BUFFER_SZ;
size_t cacheOffset = m_offset % BUFFER_SZ;
uint64_t cacheSize;
uint64_t rem = length;
uint8_t* dst = (uint8_t*)buf;
while (rem) uint64_t m_offset;
{ size_t m_curBlock = SIZE_MAX;
if (block != m_curBlock) uint8_t m_buf[BUFFER_SZ];
{
m_dio->read(m_buf, BUFFER_SZ);
m_curBlock = block;
}
cacheSize = rem; public:
if (cacheSize + cacheOffset > BUFFER_SZ) PartReadStream(const PartitionGCN& parent, uint64_t offset, bool& err) : m_parent(parent), m_offset(offset) {
cacheSize = BUFFER_SZ - cacheOffset; size_t block = m_offset / BUFFER_SZ;
m_dio = m_parent.m_parent.getDiscIO().beginReadStream(block * BUFFER_SZ);
memmove(dst, m_buf + cacheOffset, cacheSize); if (!m_dio) {
dst += cacheSize; err = true;
rem -= cacheSize;
cacheOffset = 0;
++block;
}
m_offset += length;
return dst - (uint8_t*)buf;
}
};
std::unique_ptr<IPartReadStream> beginReadStream(uint64_t offset) const
{
bool Err = false;
auto ret = std::unique_ptr<IPartReadStream>(new PartReadStream(*this, offset, Err));
if (Err)
return {};
return ret;
}
};
DiscGCN::DiscGCN(std::unique_ptr<IDiscIO>&& dio, bool& err)
: DiscBase(std::move(dio), err)
{
if (err)
return; return;
}
/* One lone partition for GCN */ m_dio->read(m_buf, BUFFER_SZ);
m_partitions.emplace_back(new PartitionGCN(*this, 0, err)); m_curBlock = block;
}
DiscBuilderGCN DiscGCN::makeMergeBuilder(SystemStringView outPath, FProgress progressCB)
{
return DiscBuilderGCN(outPath, progressCB);
}
bool DiscGCN::extractDiscHeaderFiles(SystemStringView path, const ExtractionContext& ctx) const
{
return true;
}
class PartitionBuilderGCN : public DiscBuilderBase::PartitionBuilderBase
{
uint64_t m_curUser = 0x57058000;
public:
class PartWriteStream : public IPartWriteStream
{
const PartitionBuilderGCN& m_parent;
uint64_t m_offset;
std::unique_ptr<IFileIO::IWriteStream> m_fio;
public:
PartWriteStream(const PartitionBuilderGCN& parent, uint64_t offset, bool& err)
: m_parent(parent), m_offset(offset)
{
m_fio = m_parent.m_parent.getFileIO().beginWriteStream(offset);
if (!m_fio)
err = true;
}
void close() {m_fio.reset();}
uint64_t position() const {return m_offset;}
uint64_t write(const void* buf, uint64_t length)
{
uint64_t len = m_fio->write(buf, length);
m_offset += len;
return len;
}
void seek(size_t off)
{
m_offset = off;
m_fio = m_parent.m_parent.getFileIO().beginWriteStream(off);
}
};
PartitionBuilderGCN(DiscBuilderBase& parent)
: DiscBuilderBase::PartitionBuilderBase(parent, PartitionKind::Data, false) {}
uint64_t userAllocate(uint64_t reqSz, IPartWriteStream& ws)
{
m_curUser -= reqSz;
m_curUser &= 0xfffffffffffffff0;
if (m_curUser < 0x30000)
{
LogModule.report(logvisor::Error, "user area low mark reached");
return -1;
}
static_cast<PartWriteStream&>(ws).seek(m_curUser);
return m_curUser;
} }
void seek(int64_t offset, int whence) {
uint32_t packOffset(uint64_t offset) const if (whence == SEEK_SET)
{ m_offset = offset;
return offset; else if (whence == SEEK_CUR)
m_offset += offset;
else
return;
size_t block = m_offset / BUFFER_SZ;
if (block != m_curBlock) {
m_dio->seek(block * BUFFER_SZ);
m_dio->read(m_buf, BUFFER_SZ);
m_curBlock = block;
}
} }
uint64_t position() const { return m_offset; }
uint64_t read(void* buf, uint64_t length) {
size_t block = m_offset / BUFFER_SZ;
size_t cacheOffset = m_offset % BUFFER_SZ;
uint64_t cacheSize;
uint64_t rem = length;
uint8_t* dst = (uint8_t*)buf;
std::unique_ptr<IPartWriteStream> beginWriteStream(uint64_t offset) while (rem) {
{ if (block != m_curBlock) {
bool Err = false; m_dio->read(m_buf, BUFFER_SZ);
std::unique_ptr<IPartWriteStream> ret = std::make_unique<PartWriteStream>(*this, offset, Err); m_curBlock = block;
if (Err)
return {};
return ret;
}
bool _build(const std::function<bool(IPartWriteStream&, uint32_t, uint32_t,
uint32_t, uint32_t, uint32_t)>& headerFunc,
const std::function<bool(IPartWriteStream&)>& bi2Func,
const std::function<bool(IPartWriteStream&, size_t&)>& apploaderFunc)
{
std::unique_ptr<IPartWriteStream> ws = beginWriteStream(0x2440);
if (!ws)
return false;
size_t xferSz = 0;
if (!apploaderFunc(*ws, xferSz))
return false;
size_t fstOff = ROUND_UP_32(xferSz);
size_t fstSz = sizeof(FSTNode) * m_buildNodes.size();
for (size_t i=0 ; i<fstOff-xferSz ; ++i)
ws->write("\xff", 1);
fstOff += 0x2440;
ws->write(m_buildNodes.data(), fstSz);
for (const std::string& str : m_buildNames)
ws->write(str.data(), str.size()+1);
fstSz += m_buildNameOff;
fstSz = ROUND_UP_32(fstSz);
if (fstOff + fstSz >= m_curUser)
{
LogModule.report(logvisor::Error,
"FST flows into user area (one or the other is too big)");
return false;
} }
ws = beginWriteStream(0); cacheSize = rem;
if (!ws) if (cacheSize + cacheOffset > BUFFER_SZ)
return false; cacheSize = BUFFER_SZ - cacheOffset;
if (!headerFunc(*ws, m_dolOffset, fstOff, fstSz, m_curUser, 0x57058000 - m_curUser))
return false;
if (!bi2Func(*ws))
return false;
return true; memmove(dst, m_buf + cacheOffset, cacheSize);
dst += cacheSize;
rem -= cacheSize;
cacheOffset = 0;
++block;
}
m_offset += length;
return dst - (uint8_t*)buf;
} }
};
bool buildFromDirectory(SystemStringView dirIn) std::unique_ptr<IPartReadStream> beginReadStream(uint64_t offset) const {
{ bool Err = false;
std::unique_ptr<IPartWriteStream> ws = beginWriteStream(0); auto ret = std::unique_ptr<IPartReadStream>(new PartReadStream(*this, offset, Err));
if (!ws) if (Err)
return false; return {};
bool result = DiscBuilderBase::PartitionBuilderBase::buildFromDirectory(*ws, dirIn); return ret;
if (!result) }
return false;
SystemString dirStr(dirIn);
/* Check Apploader */
SystemString apploaderIn = dirStr + _SYS_STR("/sys/apploader.img");
Sstat apploaderStat;
if (Stat(apploaderIn.c_str(), &apploaderStat))
{
LogModule.report(logvisor::Error, _SYS_STR("unable to stat %s"), apploaderIn.c_str());
return false;
}
/* Check Boot */
SystemString bootIn = dirStr + _SYS_STR("/sys/boot.bin");
Sstat bootStat;
if (Stat(bootIn.c_str(), &bootStat))
{
LogModule.report(logvisor::Error, _SYS_STR("unable to stat %s"), bootIn.c_str());
return false;
}
/* Check BI2 */
SystemString bi2In = dirStr + _SYS_STR("/sys/bi2.bin");
Sstat bi2Stat;
if (Stat(bi2In.c_str(), &bi2Stat))
{
LogModule.report(logvisor::Error, _SYS_STR("unable to stat %s"), bi2In.c_str());
return false;
}
return _build(
[&bootIn](IPartWriteStream& ws, uint32_t dolOff, uint32_t fstOff, uint32_t fstSz,
uint32_t userOff, uint32_t userSz) -> bool
{
std::unique_ptr<IFileIO::IReadStream> rs = NewFileIO(bootIn.c_str())->beginReadStream();
if (!rs)
return false;
Header header;
header.read(*rs);
header.m_dolOff = dolOff;
header.m_fstOff = fstOff;
header.m_fstSz = fstSz;
header.m_fstMaxSz = fstSz;
header.m_userPosition = userOff;
header.m_userSz = userSz;
header.write(ws);
return true;
},
[&bi2In](IPartWriteStream& ws) -> bool
{
std::unique_ptr<IFileIO::IReadStream> rs = NewFileIO(bi2In.c_str())->beginReadStream();
if (!rs)
return false;
BI2Header bi2;
bi2.read(*rs);
bi2.write(ws);
return true;
},
[this, &apploaderIn](IPartWriteStream& ws, size_t& xferSz) -> bool
{
std::unique_ptr<IFileIO::IReadStream> rs = NewFileIO(apploaderIn.c_str())->beginReadStream();
if (!rs)
return false;
char buf[8192];
while (true)
{
size_t rdSz = rs->read(buf, 8192);
if (!rdSz)
break;
ws.write(buf, rdSz);
xferSz += rdSz;
if (0x2440 + xferSz >= m_curUser)
{
LogModule.report(logvisor::Error,
"apploader flows into user area (one or the other is too big)");
return false;
}
m_parent.m_progressCB(m_parent.getProgressFactor(), apploaderIn, xferSz);
}
++m_parent.m_progressIdx;
return true;
});
}
bool mergeFromDirectory(const PartitionGCN* partIn, SystemStringView dirIn)
{
std::unique_ptr<IPartWriteStream> ws = beginWriteStream(0);
if (!ws)
return false;
bool result = DiscBuilderBase::PartitionBuilderBase::mergeFromDirectory(*ws, partIn, dirIn);
if (!result)
return false;
return _build(
[partIn](IPartWriteStream& ws, uint32_t dolOff, uint32_t fstOff, uint32_t fstSz,
uint32_t userOff, uint32_t userSz) -> bool
{
Header header = partIn->getHeader();
header.m_dolOff = dolOff;
header.m_fstOff = fstOff;
header.m_fstSz = fstSz;
header.m_fstMaxSz = fstSz;
header.m_userPosition = userOff;
header.m_userSz = userSz;
header.write(ws);
return true;
},
[partIn](IPartWriteStream& ws) -> bool
{
partIn->getBI2().write(ws);
return true;
},
[this, partIn](IPartWriteStream& ws, size_t& xferSz) -> bool
{
std::unique_ptr<uint8_t[]> apploaderBuf = partIn->getApploaderBuf();
size_t apploaderSz = partIn->getApploaderSize();
SystemString apploaderName(_SYS_STR("<apploader>"));
ws.write(apploaderBuf.get(), apploaderSz);
xferSz += apploaderSz;
if (0x2440 + xferSz >= m_curUser)
{
LogModule.report(logvisor::Error,
"apploader flows into user area (one or the other is too big)");
return false;
}
m_parent.m_progressCB(m_parent.getProgressFactor(), apploaderName, xferSz);
++m_parent.m_progressIdx;
return true;
});
}
}; };
EBuildResult DiscBuilderGCN::buildFromDirectory(SystemStringView dirIn) DiscGCN::DiscGCN(std::unique_ptr<IDiscIO>&& dio, bool& err) : DiscBase(std::move(dio), err) {
{ if (err)
if (!m_fileIO->beginWriteStream()) return;
return EBuildResult::Failed;
if (!CheckFreeSpace(m_outPath.c_str(), 0x57058000))
{
LogModule.report(logvisor::Error, _SYS_STR("not enough free disk space for %s"), m_outPath.c_str());
return EBuildResult::DiskFull;
}
m_progressCB(getProgressFactor(), _SYS_STR("Preallocating image"), -1);
++m_progressIdx;
{
auto ws = m_fileIO->beginWriteStream(0);
if (!ws)
return EBuildResult::Failed;
char zeroBytes[1024] = {};
for (uint64_t i = 0; i < 0x57058000; i += 1024)
ws->write(zeroBytes, 1024);
}
PartitionBuilderGCN& pb = static_cast<PartitionBuilderGCN&>(*m_partitions[0]); /* One lone partition for GCN */
return pb.buildFromDirectory(dirIn) ? EBuildResult::Success : EBuildResult::Failed; m_partitions.emplace_back(new PartitionGCN(*this, 0, err));
} }
uint64_t DiscBuilderGCN::CalculateTotalSizeRequired(SystemStringView dirIn) DiscBuilderGCN DiscGCN::makeMergeBuilder(SystemStringView outPath, FProgress progressCB) {
{ return DiscBuilderGCN(outPath, progressCB);
uint64_t sz = DiscBuilderBase::PartitionBuilderBase::CalculateTotalSizeBuild(dirIn, PartitionKind::Data, false); }
if (sz == -1)
return -1; bool DiscGCN::extractDiscHeaderFiles(SystemStringView path, const ExtractionContext& ctx) const { return true; }
sz += 0x30000;
if (sz > 0x57058000) class PartitionBuilderGCN : public DiscBuilderBase::PartitionBuilderBase {
{ uint64_t m_curUser = 0x57058000;
LogModule.report(logvisor::Error, _SYS_STR("disc capacity exceeded [%" PRIu64 " / %" PRIu64 "]"), sz, 0x57058000);
return -1; public:
class PartWriteStream : public IPartWriteStream {
const PartitionBuilderGCN& m_parent;
uint64_t m_offset;
std::unique_ptr<IFileIO::IWriteStream> m_fio;
public:
PartWriteStream(const PartitionBuilderGCN& parent, uint64_t offset, bool& err)
: m_parent(parent), m_offset(offset) {
m_fio = m_parent.m_parent.getFileIO().beginWriteStream(offset);
if (!m_fio)
err = true;
} }
return sz; void close() { m_fio.reset(); }
uint64_t position() const { return m_offset; }
uint64_t write(const void* buf, uint64_t length) {
uint64_t len = m_fio->write(buf, length);
m_offset += len;
return len;
}
void seek(size_t off) {
m_offset = off;
m_fio = m_parent.m_parent.getFileIO().beginWriteStream(off);
}
};
PartitionBuilderGCN(DiscBuilderBase& parent)
: DiscBuilderBase::PartitionBuilderBase(parent, PartitionKind::Data, false) {}
uint64_t userAllocate(uint64_t reqSz, IPartWriteStream& ws) {
m_curUser -= reqSz;
m_curUser &= 0xfffffffffffffff0;
if (m_curUser < 0x30000) {
LogModule.report(logvisor::Error, "user area low mark reached");
return -1;
}
static_cast<PartWriteStream&>(ws).seek(m_curUser);
return m_curUser;
}
uint32_t packOffset(uint64_t offset) const { return offset; }
std::unique_ptr<IPartWriteStream> beginWriteStream(uint64_t offset) {
bool Err = false;
std::unique_ptr<IPartWriteStream> ret = std::make_unique<PartWriteStream>(*this, offset, Err);
if (Err)
return {};
return ret;
}
bool
_build(const std::function<bool(IPartWriteStream&, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t)>& headerFunc,
const std::function<bool(IPartWriteStream&)>& bi2Func,
const std::function<bool(IPartWriteStream&, size_t&)>& apploaderFunc) {
std::unique_ptr<IPartWriteStream> ws = beginWriteStream(0x2440);
if (!ws)
return false;
size_t xferSz = 0;
if (!apploaderFunc(*ws, xferSz))
return false;
size_t fstOff = ROUND_UP_32(xferSz);
size_t fstSz = sizeof(FSTNode) * m_buildNodes.size();
for (size_t i = 0; i < fstOff - xferSz; ++i)
ws->write("\xff", 1);
fstOff += 0x2440;
ws->write(m_buildNodes.data(), fstSz);
for (const std::string& str : m_buildNames)
ws->write(str.data(), str.size() + 1);
fstSz += m_buildNameOff;
fstSz = ROUND_UP_32(fstSz);
if (fstOff + fstSz >= m_curUser) {
LogModule.report(logvisor::Error, "FST flows into user area (one or the other is too big)");
return false;
}
ws = beginWriteStream(0);
if (!ws)
return false;
if (!headerFunc(*ws, m_dolOffset, fstOff, fstSz, m_curUser, 0x57058000 - m_curUser))
return false;
if (!bi2Func(*ws))
return false;
return true;
}
bool buildFromDirectory(SystemStringView dirIn) {
std::unique_ptr<IPartWriteStream> ws = beginWriteStream(0);
if (!ws)
return false;
bool result = DiscBuilderBase::PartitionBuilderBase::buildFromDirectory(*ws, dirIn);
if (!result)
return false;
SystemString dirStr(dirIn);
/* Check Apploader */
SystemString apploaderIn = dirStr + _SYS_STR("/sys/apploader.img");
Sstat apploaderStat;
if (Stat(apploaderIn.c_str(), &apploaderStat)) {
LogModule.report(logvisor::Error, _SYS_STR("unable to stat %s"), apploaderIn.c_str());
return false;
}
/* Check Boot */
SystemString bootIn = dirStr + _SYS_STR("/sys/boot.bin");
Sstat bootStat;
if (Stat(bootIn.c_str(), &bootStat)) {
LogModule.report(logvisor::Error, _SYS_STR("unable to stat %s"), bootIn.c_str());
return false;
}
/* Check BI2 */
SystemString bi2In = dirStr + _SYS_STR("/sys/bi2.bin");
Sstat bi2Stat;
if (Stat(bi2In.c_str(), &bi2Stat)) {
LogModule.report(logvisor::Error, _SYS_STR("unable to stat %s"), bi2In.c_str());
return false;
}
return _build(
[&bootIn](IPartWriteStream& ws, uint32_t dolOff, uint32_t fstOff, uint32_t fstSz, uint32_t userOff,
uint32_t userSz) -> bool {
std::unique_ptr<IFileIO::IReadStream> rs = NewFileIO(bootIn.c_str())->beginReadStream();
if (!rs)
return false;
Header header;
header.read(*rs);
header.m_dolOff = dolOff;
header.m_fstOff = fstOff;
header.m_fstSz = fstSz;
header.m_fstMaxSz = fstSz;
header.m_userPosition = userOff;
header.m_userSz = userSz;
header.write(ws);
return true;
},
[&bi2In](IPartWriteStream& ws) -> bool {
std::unique_ptr<IFileIO::IReadStream> rs = NewFileIO(bi2In.c_str())->beginReadStream();
if (!rs)
return false;
BI2Header bi2;
bi2.read(*rs);
bi2.write(ws);
return true;
},
[this, &apploaderIn](IPartWriteStream& ws, size_t& xferSz) -> bool {
std::unique_ptr<IFileIO::IReadStream> rs = NewFileIO(apploaderIn.c_str())->beginReadStream();
if (!rs)
return false;
char buf[8192];
while (true) {
size_t rdSz = rs->read(buf, 8192);
if (!rdSz)
break;
ws.write(buf, rdSz);
xferSz += rdSz;
if (0x2440 + xferSz >= m_curUser) {
LogModule.report(logvisor::Error, "apploader flows into user area (one or the other is too big)");
return false;
}
m_parent.m_progressCB(m_parent.getProgressFactor(), apploaderIn, xferSz);
}
++m_parent.m_progressIdx;
return true;
});
}
bool mergeFromDirectory(const PartitionGCN* partIn, SystemStringView dirIn) {
std::unique_ptr<IPartWriteStream> ws = beginWriteStream(0);
if (!ws)
return false;
bool result = DiscBuilderBase::PartitionBuilderBase::mergeFromDirectory(*ws, partIn, dirIn);
if (!result)
return false;
return _build(
[partIn](IPartWriteStream& ws, uint32_t dolOff, uint32_t fstOff, uint32_t fstSz, uint32_t userOff,
uint32_t userSz) -> bool {
Header header = partIn->getHeader();
header.m_dolOff = dolOff;
header.m_fstOff = fstOff;
header.m_fstSz = fstSz;
header.m_fstMaxSz = fstSz;
header.m_userPosition = userOff;
header.m_userSz = userSz;
header.write(ws);
return true;
},
[partIn](IPartWriteStream& ws) -> bool {
partIn->getBI2().write(ws);
return true;
},
[this, partIn](IPartWriteStream& ws, size_t& xferSz) -> bool {
std::unique_ptr<uint8_t[]> apploaderBuf = partIn->getApploaderBuf();
size_t apploaderSz = partIn->getApploaderSize();
SystemString apploaderName(_SYS_STR("<apploader>"));
ws.write(apploaderBuf.get(), apploaderSz);
xferSz += apploaderSz;
if (0x2440 + xferSz >= m_curUser) {
LogModule.report(logvisor::Error, "apploader flows into user area (one or the other is too big)");
return false;
}
m_parent.m_progressCB(m_parent.getProgressFactor(), apploaderName, xferSz);
++m_parent.m_progressIdx;
return true;
});
}
};
EBuildResult DiscBuilderGCN::buildFromDirectory(SystemStringView dirIn) {
if (!m_fileIO->beginWriteStream())
return EBuildResult::Failed;
if (!CheckFreeSpace(m_outPath.c_str(), 0x57058000)) {
LogModule.report(logvisor::Error, _SYS_STR("not enough free disk space for %s"), m_outPath.c_str());
return EBuildResult::DiskFull;
}
m_progressCB(getProgressFactor(), _SYS_STR("Preallocating image"), -1);
++m_progressIdx;
{
auto ws = m_fileIO->beginWriteStream(0);
if (!ws)
return EBuildResult::Failed;
char zeroBytes[1024] = {};
for (uint64_t i = 0; i < 0x57058000; i += 1024)
ws->write(zeroBytes, 1024);
}
PartitionBuilderGCN& pb = static_cast<PartitionBuilderGCN&>(*m_partitions[0]);
return pb.buildFromDirectory(dirIn) ? EBuildResult::Success : EBuildResult::Failed;
}
uint64_t DiscBuilderGCN::CalculateTotalSizeRequired(SystemStringView dirIn) {
uint64_t sz = DiscBuilderBase::PartitionBuilderBase::CalculateTotalSizeBuild(dirIn, PartitionKind::Data, false);
if (sz == -1)
return -1;
sz += 0x30000;
if (sz > 0x57058000) {
LogModule.report(logvisor::Error, _SYS_STR("disc capacity exceeded [%" PRIu64 " / %" PRIu64 "]"), sz, 0x57058000);
return -1;
}
return sz;
} }
DiscBuilderGCN::DiscBuilderGCN(SystemStringView outPath, FProgress progressCB) DiscBuilderGCN::DiscBuilderGCN(SystemStringView outPath, FProgress progressCB)
: DiscBuilderBase(outPath, 0x57058000, progressCB) : DiscBuilderBase(outPath, 0x57058000, progressCB) {
{ PartitionBuilderGCN* partBuilder = new PartitionBuilderGCN(*this);
PartitionBuilderGCN* partBuilder = new PartitionBuilderGCN(*this); m_partitions.emplace_back(partBuilder);
m_partitions.emplace_back(partBuilder);
} }
DiscMergerGCN::DiscMergerGCN(SystemStringView outPath, DiscGCN& sourceDisc, FProgress progressCB) DiscMergerGCN::DiscMergerGCN(SystemStringView outPath, DiscGCN& sourceDisc, FProgress progressCB)
: m_sourceDisc(sourceDisc), m_builder(sourceDisc.makeMergeBuilder(outPath, progressCB)) : m_sourceDisc(sourceDisc), m_builder(sourceDisc.makeMergeBuilder(outPath, progressCB)) {}
{}
EBuildResult DiscMergerGCN::mergeFromDirectory(SystemStringView dirIn) EBuildResult DiscMergerGCN::mergeFromDirectory(SystemStringView dirIn) {
{ if (!m_builder.getFileIO().beginWriteStream())
if (!m_builder.getFileIO().beginWriteStream()) return EBuildResult::Failed;
return EBuildResult::Failed; if (!CheckFreeSpace(m_builder.m_outPath.c_str(), 0x57058000)) {
if (!CheckFreeSpace(m_builder.m_outPath.c_str(), 0x57058000)) LogModule.report(logvisor::Error, _SYS_STR("not enough free disk space for %s"), m_builder.m_outPath.c_str());
{ return EBuildResult::DiskFull;
LogModule.report(logvisor::Error, _SYS_STR("not enough free disk space for %s"), m_builder.m_outPath.c_str()); }
return EBuildResult::DiskFull; m_builder.m_progressCB(m_builder.getProgressFactor(), _SYS_STR("Preallocating image"), -1);
} ++m_builder.m_progressIdx;
m_builder.m_progressCB(m_builder.getProgressFactor(), _SYS_STR("Preallocating image"), -1); {
++m_builder.m_progressIdx; auto ws = m_builder.m_fileIO->beginWriteStream(0);
{ if (!ws)
auto ws = m_builder.m_fileIO->beginWriteStream(0); return EBuildResult::Failed;
if (!ws) char zeroBytes[1024] = {};
return EBuildResult::Failed; for (uint64_t i = 0; i < 0x57058000; i += 1024)
char zeroBytes[1024] = {}; ws->write(zeroBytes, 1024);
for (uint64_t i = 0; i < 0x57058000; i += 1024) }
ws->write(zeroBytes, 1024);
}
PartitionBuilderGCN& pb = static_cast<PartitionBuilderGCN&>(*m_builder.m_partitions[0]); PartitionBuilderGCN& pb = static_cast<PartitionBuilderGCN&>(*m_builder.m_partitions[0]);
return pb.mergeFromDirectory(static_cast<PartitionGCN*>(m_sourceDisc.getDataPartition()), dirIn) ? return pb.mergeFromDirectory(static_cast<PartitionGCN*>(m_sourceDisc.getDataPartition()), dirIn)
EBuildResult::Success : EBuildResult::Failed; ? EBuildResult::Success
: EBuildResult::Failed;
} }
uint64_t DiscMergerGCN::CalculateTotalSizeRequired(DiscGCN& sourceDisc, SystemStringView dirIn) uint64_t DiscMergerGCN::CalculateTotalSizeRequired(DiscGCN& sourceDisc, SystemStringView dirIn) {
{ uint64_t sz = DiscBuilderBase::PartitionBuilderBase::CalculateTotalSizeMerge(sourceDisc.getDataPartition(), dirIn);
uint64_t sz = DiscBuilderBase::PartitionBuilderBase::CalculateTotalSizeMerge( if (sz == -1)
sourceDisc.getDataPartition(), dirIn); return -1;
if (sz == -1) sz += 0x30000;
return -1; if (sz > 0x57058000) {
sz += 0x30000; LogModule.report(logvisor::Error, _SYS_STR("disc capacity exceeded [%" PRIu64 " / %" PRIu64 "]"), sz, 0x57058000);
if (sz > 0x57058000) return -1;
{ }
LogModule.report(logvisor::Error, _SYS_STR("disc capacity exceeded [%" PRIu64 " / %" PRIu64 "]"), sz, 0x57058000); return sz;
return -1;
}
return sz;
} }
} } // namespace nod

View File

@ -3,67 +3,57 @@
#include "nod/IDiscIO.hpp" #include "nod/IDiscIO.hpp"
#include "nod/IFileIO.hpp" #include "nod/IFileIO.hpp"
namespace nod namespace nod {
{
class DiscIOISO : public IDiscIO {
std::unique_ptr<IFileIO> m_fio;
class DiscIOISO : public IDiscIO
{
std::unique_ptr<IFileIO> m_fio;
public: public:
DiscIOISO(SystemStringView fpin) DiscIOISO(SystemStringView fpin) : m_fio(NewFileIO(fpin)) {}
: m_fio(NewFileIO(fpin)) {}
class ReadStream : public IReadStream class ReadStream : public IReadStream {
{ friend class DiscIOISO;
friend class DiscIOISO; std::unique_ptr<IFileIO::IReadStream> fp;
std::unique_ptr<IFileIO::IReadStream> fp; ReadStream(std::unique_ptr<IFileIO::IReadStream>&& fpin, bool& err) : fp(std::move(fpin)) {
ReadStream(std::unique_ptr<IFileIO::IReadStream>&& fpin, bool& err) if (!fp)
: fp(std::move(fpin)) { if (!fp) err = true; } err = true;
public:
uint64_t read(void* buf, uint64_t length)
{return fp->read(buf, length);}
uint64_t position() const
{return fp->position();}
void seek(int64_t offset, int whence)
{fp->seek(offset, whence);}
};
std::unique_ptr<IReadStream> beginReadStream(uint64_t offset) const
{
bool Err = false;
auto ret = std::unique_ptr<IReadStream>(new ReadStream(m_fio->beginReadStream(offset), Err));
if (Err)
return {};
return ret;
} }
class WriteStream : public IWriteStream public:
{ uint64_t read(void* buf, uint64_t length) { return fp->read(buf, length); }
friend class DiscIOISO; uint64_t position() const { return fp->position(); }
std::unique_ptr<IFileIO::IWriteStream> fp; void seek(int64_t offset, int whence) { fp->seek(offset, whence); }
WriteStream(std::unique_ptr<IFileIO::IWriteStream>&& fpin, bool& err) };
: fp(std::move(fpin)) { if (!fp) err = true; }
public:
uint64_t write(const void* buf, uint64_t length)
{
return fp->write(buf, length);
}
};
std::unique_ptr<IWriteStream> beginWriteStream(uint64_t offset) const std::unique_ptr<IReadStream> beginReadStream(uint64_t offset) const {
{ bool Err = false;
bool Err = false; auto ret = std::unique_ptr<IReadStream>(new ReadStream(m_fio->beginReadStream(offset), Err));
auto ret = std::unique_ptr<IWriteStream>(new WriteStream(m_fio->beginWriteStream(offset), Err)); if (Err)
if (Err) return {};
return {}; return ret;
return ret; }
class WriteStream : public IWriteStream {
friend class DiscIOISO;
std::unique_ptr<IFileIO::IWriteStream> fp;
WriteStream(std::unique_ptr<IFileIO::IWriteStream>&& fpin, bool& err) : fp(std::move(fpin)) {
if (!fp)
err = true;
} }
public:
uint64_t write(const void* buf, uint64_t length) { return fp->write(buf, length); }
};
std::unique_ptr<IWriteStream> beginWriteStream(uint64_t offset) const {
bool Err = false;
auto ret = std::unique_ptr<IWriteStream>(new WriteStream(m_fio->beginWriteStream(offset), Err));
if (Err)
return {};
return ret;
}
}; };
std::unique_ptr<IDiscIO> NewDiscIOISO(SystemStringView path) std::unique_ptr<IDiscIO> NewDiscIOISO(SystemStringView path) { return std::unique_ptr<IDiscIO>(new DiscIOISO(path)); }
{
return std::unique_ptr<IDiscIO>(new DiscIOISO(path));
}
}
} // namespace nod

View File

@ -4,302 +4,271 @@
#include "nod/IDiscIO.hpp" #include "nod/IDiscIO.hpp"
#include "nod/IFileIO.hpp" #include "nod/IFileIO.hpp"
namespace nod namespace nod {
{
#define ALIGN_LBA(x) (((x)+p->hd_sec_sz-1)&(~(p->hd_sec_sz-1))) #define ALIGN_LBA(x) (((x) + p->hd_sec_sz - 1) & (~(p->hd_sec_sz - 1)))
static uint8_t size_to_shift(uint32_t size) static uint8_t size_to_shift(uint32_t size) {
{ uint8_t ret = 0;
uint8_t ret = 0; while (size) {
while (size) ret++;
{ size >>= 1;
ret++; }
size>>=1; return ret - 1;
}
return ret-1;
} }
class DiscIOWBFS : public IDiscIO class DiscIOWBFS : public IDiscIO {
{ SystemString filepath;
SystemString filepath;
struct WBFSHead struct WBFSHead {
{ uint32_t magic;
uint32_t magic; // parameters copied in the partition for easy dumping, and bug reports
// parameters copied in the partition for easy dumping, and bug reports uint32_t n_hd_sec; // total number of hd_sec in this partition
uint32_t n_hd_sec; // total number of hd_sec in this partition uint8_t hd_sec_sz_s; // sector size in this partition
uint8_t hd_sec_sz_s; // sector size in this partition uint8_t wbfs_sec_sz_s; // size of a wbfs sec
uint8_t wbfs_sec_sz_s; // size of a wbfs sec uint8_t padding3[2];
uint8_t padding3[2]; uint8_t disc_table[0]; // size depends on hd sector size
uint8_t disc_table[0]; // size depends on hd sector size };
}; std::unique_ptr<uint8_t[]> wbfsHead;
std::unique_ptr<uint8_t[]> wbfsHead;
struct WBFSDiscInfo struct WBFSDiscInfo {
{ uint8_t disc_header_copy[0x100];
uint8_t disc_header_copy[0x100]; uint16_t wlba_table[0];
uint16_t wlba_table[0]; };
}; std::unique_ptr<uint8_t[]> wbfsDiscInfo;
std::unique_ptr<uint8_t[]> wbfsDiscInfo;
struct WBFS struct WBFS {
{ /* hdsectors, the size of the sector provided by the hosting hard drive */
/* hdsectors, the size of the sector provided by the hosting hard drive */ uint32_t hd_sec_sz;
uint32_t hd_sec_sz; uint8_t hd_sec_sz_s; // the power of two of the last number
uint8_t hd_sec_sz_s; // the power of two of the last number uint32_t n_hd_sec; // the number of hd sector in the wbfs partition
uint32_t n_hd_sec; // the number of hd sector in the wbfs partition
/* standard wii sector (0x8000 bytes) */ /* standard wii sector (0x8000 bytes) */
uint32_t wii_sec_sz; uint32_t wii_sec_sz;
uint8_t wii_sec_sz_s; uint8_t wii_sec_sz_s;
uint32_t n_wii_sec; uint32_t n_wii_sec;
uint32_t n_wii_sec_per_disc; uint32_t n_wii_sec_per_disc;
/* The size of a wbfs sector */ /* The size of a wbfs sector */
uint32_t wbfs_sec_sz; uint32_t wbfs_sec_sz;
uint32_t wbfs_sec_sz_s; uint32_t wbfs_sec_sz_s;
uint16_t n_wbfs_sec; // this must fit in 16 bit! uint16_t n_wbfs_sec; // this must fit in 16 bit!
uint16_t n_wbfs_sec_per_disc; // size of the lookup table uint16_t n_wbfs_sec_per_disc; // size of the lookup table
uint32_t part_lba; uint32_t part_lba;
uint16_t max_disc; uint16_t max_disc;
uint32_t freeblks_lba; uint32_t freeblks_lba;
uint32_t *freeblks; uint32_t* freeblks;
uint16_t disc_info_sz; uint16_t disc_info_sz;
uint32_t n_disc_open; uint32_t n_disc_open;
} wbfs; } wbfs;
static int _wbfsReadSector(IFileIO::IReadStream& rs, uint32_t lba, uint32_t count, void* buf) static int _wbfsReadSector(IFileIO::IReadStream& rs, uint32_t lba, uint32_t count, void* buf) {
{ uint64_t off = lba;
uint64_t off = lba; off *= 512ULL;
off*=512ULL; rs.seek(off, SEEK_SET);
rs.seek(off, SEEK_SET); if (rs.read(buf, count * 512ULL) != count * 512ULL) {
if (rs.read(buf, count*512ULL) != count*512ULL) LogModule.report(logvisor::Error, "error reading disc");
{ return 1;
LogModule.report(logvisor::Error, "error reading disc");
return 1;
}
return 0;
} }
return 0;
}
public: public:
DiscIOWBFS(SystemStringView fpin) DiscIOWBFS(SystemStringView fpin) : filepath(fpin) {
: filepath(fpin) /* Temporary file handle to read LBA table */
{ std::unique_ptr<IFileIO> fio = NewFileIO(filepath);
/* Temporary file handle to read LBA table */ std::unique_ptr<IFileIO::IReadStream> rs = fio->beginReadStream();
std::unique_ptr<IFileIO> fio = NewFileIO(filepath); if (!rs)
std::unique_ptr<IFileIO::IReadStream> rs = fio->beginReadStream(); return;
if (!rs)
return;
WBFS* p = &wbfs; WBFS* p = &wbfs;
WBFSHead tmpHead; WBFSHead tmpHead;
if (rs->read(&tmpHead, sizeof(tmpHead)) != sizeof(tmpHead)) { if (rs->read(&tmpHead, sizeof(tmpHead)) != sizeof(tmpHead)) {
LogModule.report(logvisor::Error, "unable to read WBFS head"); LogModule.report(logvisor::Error, "unable to read WBFS head");
return; return;
} }
unsigned hd_sector_size = 1 << tmpHead.hd_sec_sz_s; unsigned hd_sector_size = 1 << tmpHead.hd_sec_sz_s;
unsigned num_hd_sector = SBig(tmpHead.n_hd_sec); unsigned num_hd_sector = SBig(tmpHead.n_hd_sec);
wbfsHead.reset(new uint8_t[hd_sector_size]); wbfsHead.reset(new uint8_t[hd_sector_size]);
WBFSHead* head = (WBFSHead*)wbfsHead.get(); WBFSHead* head = (WBFSHead*)wbfsHead.get();
rs->seek(0, SEEK_SET); rs->seek(0, SEEK_SET);
if (rs->read(head, hd_sector_size) != hd_sector_size) { if (rs->read(head, hd_sector_size) != hd_sector_size) {
LogModule.report(logvisor::Error, "unable to read WBFS head"); LogModule.report(logvisor::Error, "unable to read WBFS head");
return; return;
}
//constants, but put here for consistancy
p->wii_sec_sz = 0x8000;
p->wii_sec_sz_s = size_to_shift(0x8000);
p->n_wii_sec = (num_hd_sector/0x8000)*hd_sector_size;
p->n_wii_sec_per_disc = 143432*2;//support for double layers discs..
p->part_lba = 0;
if (_wbfsReadSector(*rs, p->part_lba, 1, head))
return;
if (hd_sector_size && head->hd_sec_sz_s != size_to_shift(hd_sector_size)) {
LogModule.report(logvisor::Error, "hd sector size doesn't match");
return;
}
if (num_hd_sector && head->n_hd_sec != SBig(num_hd_sector)) {
LogModule.report(logvisor::Error, "hd num sector doesn't match");
return;
}
p->hd_sec_sz = 1<<head->hd_sec_sz_s;
p->hd_sec_sz_s = head->hd_sec_sz_s;
p->n_hd_sec = SBig(head->n_hd_sec);
p->n_wii_sec = (p->n_hd_sec/p->wii_sec_sz)*(p->hd_sec_sz);
p->wbfs_sec_sz_s = head->wbfs_sec_sz_s;
p->wbfs_sec_sz = 1<<p->wbfs_sec_sz_s;
p->n_wbfs_sec = p->n_wii_sec >> (p->wbfs_sec_sz_s - p->wii_sec_sz_s);
p->n_wbfs_sec_per_disc = p->n_wii_sec_per_disc >> (p->wbfs_sec_sz_s - p->wii_sec_sz_s);
p->disc_info_sz = ALIGN_LBA(uint16_t(sizeof(WBFSDiscInfo)) + p->n_wbfs_sec_per_disc*2);
p->freeblks_lba = (p->wbfs_sec_sz - p->n_wbfs_sec/8)>>p->hd_sec_sz_s;
p->freeblks = 0; // will alloc and read only if needed
p->max_disc = (p->freeblks_lba-1)/(p->disc_info_sz>>p->hd_sec_sz_s);
if(p->max_disc > p->hd_sec_sz - sizeof(WBFSHead))
p->max_disc = p->hd_sec_sz - sizeof(WBFSHead);
p->n_disc_open = 0;
int disc_info_sz_lba = p->disc_info_sz>>p->hd_sec_sz_s;
if (head->disc_table[0])
{
wbfsDiscInfo.reset(new uint8_t[p->disc_info_sz]);
if (!wbfsDiscInfo) {
LogModule.report(logvisor::Error, "allocating memory");
return;
}
if (_wbfsReadSector(*rs, p->part_lba+1, disc_info_sz_lba, wbfsDiscInfo.get()))
return;
p->n_disc_open++;
//for(i=0;i<p->n_wbfs_sec_per_disc;i++)
// printf("%d,",wbfs_ntohs(d->header->wlba_table[i]));
}
} }
class ReadStream : public IReadStream // constants, but put here for consistancy
{ p->wii_sec_sz = 0x8000;
friend class DiscIOWBFS; p->wii_sec_sz_s = size_to_shift(0x8000);
const DiscIOWBFS& m_parent; p->n_wii_sec = (num_hd_sector / 0x8000) * hd_sector_size;
std::unique_ptr<IFileIO::IReadStream> fp; p->n_wii_sec_per_disc = 143432 * 2; // support for double layers discs..
uint64_t m_offset; p->part_lba = 0;
std::unique_ptr<uint8_t[]> m_tmpBuffer; if (_wbfsReadSector(*rs, p->part_lba, 1, head))
return;
if (hd_sector_size && head->hd_sec_sz_s != size_to_shift(hd_sector_size)) {
LogModule.report(logvisor::Error, "hd sector size doesn't match");
return;
}
if (num_hd_sector && head->n_hd_sec != SBig(num_hd_sector)) {
LogModule.report(logvisor::Error, "hd num sector doesn't match");
return;
}
p->hd_sec_sz = 1 << head->hd_sec_sz_s;
p->hd_sec_sz_s = head->hd_sec_sz_s;
p->n_hd_sec = SBig(head->n_hd_sec);
ReadStream(const DiscIOWBFS& parent, std::unique_ptr<IFileIO::IReadStream>&& fpin, uint64_t offset, bool& err) p->n_wii_sec = (p->n_hd_sec / p->wii_sec_sz) * (p->hd_sec_sz);
: m_parent(parent),
fp(std::move(fpin)),
m_offset(offset),
m_tmpBuffer(new uint8_t[parent.wbfs.hd_sec_sz]) { if (!fp) err = true; }
int wbfsReadSector(uint32_t lba, uint32_t count, void* buf) p->wbfs_sec_sz_s = head->wbfs_sec_sz_s;
{return DiscIOWBFS::_wbfsReadSector(*fp, lba, count, buf);} p->wbfs_sec_sz = 1 << p->wbfs_sec_sz_s;
p->n_wbfs_sec = p->n_wii_sec >> (p->wbfs_sec_sz_s - p->wii_sec_sz_s);
p->n_wbfs_sec_per_disc = p->n_wii_sec_per_disc >> (p->wbfs_sec_sz_s - p->wii_sec_sz_s);
p->disc_info_sz = ALIGN_LBA(uint16_t(sizeof(WBFSDiscInfo)) + p->n_wbfs_sec_per_disc * 2);
int wbfsDiscRead(uint32_t offset, uint8_t *data, uint64_t len) p->freeblks_lba = (p->wbfs_sec_sz - p->n_wbfs_sec / 8) >> p->hd_sec_sz_s;
{
const WBFS* p = &m_parent.wbfs;
const WBFSDiscInfo* d = (WBFSDiscInfo*)m_parent.wbfsDiscInfo.get();
uint16_t wlba = offset>>(p->wbfs_sec_sz_s-2);
uint32_t iwlba_shift = p->wbfs_sec_sz_s - p->hd_sec_sz_s;
uint32_t lba_mask = (p->wbfs_sec_sz-1)>>(p->hd_sec_sz_s);
uint64_t lba = (offset>>(p->hd_sec_sz_s-2))&lba_mask;
uint64_t off = offset&((p->hd_sec_sz>>2)-1);
uint16_t iwlba = SBig(d->wlba_table[wlba]);
uint64_t len_copied;
int err = 0;
uint8_t *ptr = data;
if (!iwlba)
return 1;
if (off)
{
off*=4;
err = wbfsReadSector(p->part_lba + (iwlba<<iwlba_shift) + lba, 1, m_tmpBuffer.get());
if (err)
return err;
len_copied = p->hd_sec_sz - off;
if (len < len_copied)
len_copied = len;
memcpy(ptr, m_tmpBuffer.get() + off, len_copied);
len -= len_copied;
ptr += len_copied;
lba++;
if (lba>lba_mask && len)
{
lba=0;
iwlba = SBig(d->wlba_table[++wlba]);
if (!iwlba)
return 1;
}
}
while (len>=p->hd_sec_sz)
{
uint32_t nlb = len>>(p->hd_sec_sz_s);
if (lba + nlb > p->wbfs_sec_sz) // dont cross wbfs sectors.. p->freeblks = 0; // will alloc and read only if needed
nlb = p->wbfs_sec_sz-lba; p->max_disc = (p->freeblks_lba - 1) / (p->disc_info_sz >> p->hd_sec_sz_s);
err = wbfsReadSector(p->part_lba + (iwlba<<iwlba_shift) + lba, nlb, ptr); if (p->max_disc > p->hd_sec_sz - sizeof(WBFSHead))
if (err) p->max_disc = p->hd_sec_sz - sizeof(WBFSHead);
return err;
len -= nlb<<p->hd_sec_sz_s;
ptr += nlb<<p->hd_sec_sz_s;
lba += nlb;
if (lba>lba_mask && len)
{
lba = 0;
iwlba = SBig(d->wlba_table[++wlba]);
if (!iwlba)
return 1;
}
}
if (len)
{
err = wbfsReadSector(p->part_lba + (iwlba<<iwlba_shift) + lba, 1, m_tmpBuffer.get());
if (err)
return err;
memcpy(ptr, m_tmpBuffer.get(), len);
}
return 0;
}
public: p->n_disc_open = 0;
uint64_t read(void* buf, uint64_t length)
{
uint8_t extra[4];
uint64_t rem_offset = m_offset % 4;
if (rem_offset)
{
uint64_t rem_rem = 4 - rem_offset;
if (wbfsDiscRead((uint32_t)(m_offset / 4), extra, 4))
return 0;
memcpy(buf, extra + rem_offset, rem_rem);
if (wbfsDiscRead((uint32_t)(m_offset / 4 + 1), (uint8_t*)buf + rem_rem, length - rem_rem))
return 0;
}
else
{
if (wbfsDiscRead((uint32_t)(m_offset / 4), (uint8_t*)buf, length))
return 0;
}
m_offset += length;
return length;
}
uint64_t position() const {return m_offset;}
void seek(int64_t offset, int whence)
{
if (whence == SEEK_SET)
m_offset = offset;
else if (whence == SEEK_CUR)
m_offset += offset;
}
};
std::unique_ptr<IReadStream> beginReadStream(uint64_t offset) const int disc_info_sz_lba = p->disc_info_sz >> p->hd_sec_sz_s;
{ if (head->disc_table[0]) {
bool Err = false; wbfsDiscInfo.reset(new uint8_t[p->disc_info_sz]);
auto ret = std::unique_ptr<IReadStream>(new ReadStream(*this, NewFileIO(filepath)->beginReadStream(), offset, Err)); if (!wbfsDiscInfo) {
if (Err) LogModule.report(logvisor::Error, "allocating memory");
return {}; return;
return ret; }
if (_wbfsReadSector(*rs, p->part_lba + 1, disc_info_sz_lba, wbfsDiscInfo.get()))
return;
p->n_disc_open++;
// for(i=0;i<p->n_wbfs_sec_per_disc;i++)
// printf("%d,",wbfs_ntohs(d->header->wlba_table[i]));
}
}
class ReadStream : public IReadStream {
friend class DiscIOWBFS;
const DiscIOWBFS& m_parent;
std::unique_ptr<IFileIO::IReadStream> fp;
uint64_t m_offset;
std::unique_ptr<uint8_t[]> m_tmpBuffer;
ReadStream(const DiscIOWBFS& parent, std::unique_ptr<IFileIO::IReadStream>&& fpin, uint64_t offset, bool& err)
: m_parent(parent), fp(std::move(fpin)), m_offset(offset), m_tmpBuffer(new uint8_t[parent.wbfs.hd_sec_sz]) {
if (!fp)
err = true;
} }
std::unique_ptr<IWriteStream> beginWriteStream(uint64_t offset) const int wbfsReadSector(uint32_t lba, uint32_t count, void* buf) {
{ return DiscIOWBFS::_wbfsReadSector(*fp, lba, count, buf);
return std::unique_ptr<IWriteStream>();
} }
int wbfsDiscRead(uint32_t offset, uint8_t* data, uint64_t len) {
const WBFS* p = &m_parent.wbfs;
const WBFSDiscInfo* d = (WBFSDiscInfo*)m_parent.wbfsDiscInfo.get();
uint16_t wlba = offset >> (p->wbfs_sec_sz_s - 2);
uint32_t iwlba_shift = p->wbfs_sec_sz_s - p->hd_sec_sz_s;
uint32_t lba_mask = (p->wbfs_sec_sz - 1) >> (p->hd_sec_sz_s);
uint64_t lba = (offset >> (p->hd_sec_sz_s - 2)) & lba_mask;
uint64_t off = offset & ((p->hd_sec_sz >> 2) - 1);
uint16_t iwlba = SBig(d->wlba_table[wlba]);
uint64_t len_copied;
int err = 0;
uint8_t* ptr = data;
if (!iwlba)
return 1;
if (off) {
off *= 4;
err = wbfsReadSector(p->part_lba + (iwlba << iwlba_shift) + lba, 1, m_tmpBuffer.get());
if (err)
return err;
len_copied = p->hd_sec_sz - off;
if (len < len_copied)
len_copied = len;
memcpy(ptr, m_tmpBuffer.get() + off, len_copied);
len -= len_copied;
ptr += len_copied;
lba++;
if (lba > lba_mask && len) {
lba = 0;
iwlba = SBig(d->wlba_table[++wlba]);
if (!iwlba)
return 1;
}
}
while (len >= p->hd_sec_sz) {
uint32_t nlb = len >> (p->hd_sec_sz_s);
if (lba + nlb > p->wbfs_sec_sz) // dont cross wbfs sectors..
nlb = p->wbfs_sec_sz - lba;
err = wbfsReadSector(p->part_lba + (iwlba << iwlba_shift) + lba, nlb, ptr);
if (err)
return err;
len -= nlb << p->hd_sec_sz_s;
ptr += nlb << p->hd_sec_sz_s;
lba += nlb;
if (lba > lba_mask && len) {
lba = 0;
iwlba = SBig(d->wlba_table[++wlba]);
if (!iwlba)
return 1;
}
}
if (len) {
err = wbfsReadSector(p->part_lba + (iwlba << iwlba_shift) + lba, 1, m_tmpBuffer.get());
if (err)
return err;
memcpy(ptr, m_tmpBuffer.get(), len);
}
return 0;
}
public:
uint64_t read(void* buf, uint64_t length) {
uint8_t extra[4];
uint64_t rem_offset = m_offset % 4;
if (rem_offset) {
uint64_t rem_rem = 4 - rem_offset;
if (wbfsDiscRead((uint32_t)(m_offset / 4), extra, 4))
return 0;
memcpy(buf, extra + rem_offset, rem_rem);
if (wbfsDiscRead((uint32_t)(m_offset / 4 + 1), (uint8_t*)buf + rem_rem, length - rem_rem))
return 0;
} else {
if (wbfsDiscRead((uint32_t)(m_offset / 4), (uint8_t*)buf, length))
return 0;
}
m_offset += length;
return length;
}
uint64_t position() const { return m_offset; }
void seek(int64_t offset, int whence) {
if (whence == SEEK_SET)
m_offset = offset;
else if (whence == SEEK_CUR)
m_offset += offset;
}
};
std::unique_ptr<IReadStream> beginReadStream(uint64_t offset) const {
bool Err = false;
auto ret = std::unique_ptr<IReadStream>(new ReadStream(*this, NewFileIO(filepath)->beginReadStream(), offset, Err));
if (Err)
return {};
return ret;
}
std::unique_ptr<IWriteStream> beginWriteStream(uint64_t offset) const { return std::unique_ptr<IWriteStream>(); }
}; };
std::unique_ptr<IDiscIO> NewDiscIOWBFS(SystemStringView path) std::unique_ptr<IDiscIO> NewDiscIOWBFS(SystemStringView path) { return std::unique_ptr<IDiscIO>(new DiscIOWBFS(path)); }
{
return std::unique_ptr<IDiscIO>(new DiscIOWBFS(path));
}
}
} // namespace nod

File diff suppressed because it is too large Load Diff

View File

@ -4,180 +4,140 @@
#include "nod/Util.hpp" #include "nod/Util.hpp"
#include "nod/IFileIO.hpp" #include "nod/IFileIO.hpp"
namespace nod namespace nod {
{
class FileIOFILE : public IFileIO {
SystemString m_path;
int64_t m_maxWriteSize;
class FileIOFILE : public IFileIO
{
SystemString m_path;
int64_t m_maxWriteSize;
public: public:
FileIOFILE(SystemStringView path, int64_t maxWriteSize) FileIOFILE(SystemStringView path, int64_t maxWriteSize) : m_path(path), m_maxWriteSize(maxWriteSize) {}
: m_path(path), m_maxWriteSize(maxWriteSize) {}
bool exists() bool exists() {
{ FILE* fp = Fopen(m_path.c_str(), _SYS_STR("rb"));
FILE* fp = Fopen(m_path.c_str(), _SYS_STR("rb")); if (!fp)
if (!fp) return false;
return false; fclose(fp);
fclose(fp); return true;
return true; }
}
uint64_t size() uint64_t size() {
{ FILE* fp = Fopen(m_path.c_str(), _SYS_STR("rb"));
FILE* fp = Fopen(m_path.c_str(), _SYS_STR("rb")); if (!fp)
if (!fp) return 0;
return 0; FSeek(fp, 0, SEEK_END);
FSeek(fp, 0, SEEK_END); uint64_t result = FTell(fp);
uint64_t result = FTell(fp); fclose(fp);
fclose(fp); return result;
return result; }
}
struct WriteStream : public IFileIO::IWriteStream struct WriteStream : public IFileIO::IWriteStream {
{ FILE* fp;
FILE* fp; int64_t m_maxWriteSize;
int64_t m_maxWriteSize; WriteStream(SystemStringView path, int64_t maxWriteSize, bool& err) : m_maxWriteSize(maxWriteSize) {
WriteStream(SystemStringView path, int64_t maxWriteSize, bool& err) fp = Fopen(path.data(), _SYS_STR("wb"));
: m_maxWriteSize(maxWriteSize) if (!fp) {
{ LogModule.report(logvisor::Error, _SYS_STR("unable to open '%s' for writing"), path.data());
fp = Fopen(path.data(), _SYS_STR("wb")); err = true;
if (!fp) }
{
LogModule.report(logvisor::Error, _SYS_STR("unable to open '%s' for writing"), path.data());
err = true;
}
}
WriteStream(SystemStringView path, uint64_t offset, int64_t maxWriteSize, bool& err)
: m_maxWriteSize(maxWriteSize)
{
fp = Fopen(path.data(), _SYS_STR("ab"));
if (!fp)
goto FailLoc;
fclose(fp);
fp = Fopen(path.data(), _SYS_STR("r+b"));
if (!fp)
goto FailLoc;
FSeek(fp, offset, SEEK_SET);
return;
FailLoc:
LogModule.report(logvisor::Error, _SYS_STR("unable to open '%s' for writing"), path.data());
err = true;
}
~WriteStream()
{
fclose(fp);
}
uint64_t write(const void* buf, uint64_t length)
{
if (m_maxWriteSize >= 0)
{
if (FTell(fp) + length > m_maxWriteSize)
{
LogModule.report(logvisor::Error, _SYS_STR("write operation exceeds file's %" PRIi64 "-byte limit"), m_maxWriteSize);
return 0;
}
}
return fwrite(buf, 1, length, fp);
}
};
std::unique_ptr<IWriteStream> beginWriteStream() const
{
bool Err = false;
auto ret = std::unique_ptr<IWriteStream>(new WriteStream(m_path, m_maxWriteSize, Err));
if (Err)
return {};
return ret;
} }
std::unique_ptr<IWriteStream> beginWriteStream(uint64_t offset) const WriteStream(SystemStringView path, uint64_t offset, int64_t maxWriteSize, bool& err)
{ : m_maxWriteSize(maxWriteSize) {
bool Err = false; fp = Fopen(path.data(), _SYS_STR("ab"));
auto ret = std::unique_ptr<IWriteStream>(new WriteStream(m_path, offset, m_maxWriteSize, Err)); if (!fp)
if (Err) goto FailLoc;
return {}; fclose(fp);
return ret; fp = Fopen(path.data(), _SYS_STR("r+b"));
if (!fp)
goto FailLoc;
FSeek(fp, offset, SEEK_SET);
return;
FailLoc:
LogModule.report(logvisor::Error, _SYS_STR("unable to open '%s' for writing"), path.data());
err = true;
} }
~WriteStream() { fclose(fp); }
uint64_t write(const void* buf, uint64_t length) {
if (m_maxWriteSize >= 0) {
if (FTell(fp) + length > m_maxWriteSize) {
LogModule.report(logvisor::Error, _SYS_STR("write operation exceeds file's %" PRIi64 "-byte limit"),
m_maxWriteSize);
return 0;
}
}
return fwrite(buf, 1, length, fp);
}
};
std::unique_ptr<IWriteStream> beginWriteStream() const {
bool Err = false;
auto ret = std::unique_ptr<IWriteStream>(new WriteStream(m_path, m_maxWriteSize, Err));
if (Err)
return {};
return ret;
}
std::unique_ptr<IWriteStream> beginWriteStream(uint64_t offset) const {
bool Err = false;
auto ret = std::unique_ptr<IWriteStream>(new WriteStream(m_path, offset, m_maxWriteSize, Err));
if (Err)
return {};
return ret;
}
struct ReadStream : public IFileIO::IReadStream struct ReadStream : public IFileIO::IReadStream {
{ FILE* fp;
FILE* fp; ReadStream(SystemStringView path, bool& err) {
ReadStream(SystemStringView path, bool& err) fp = Fopen(path.data(), _SYS_STR("rb"));
{ if (!fp) {
fp = Fopen(path.data(), _SYS_STR("rb")); err = true;
if (!fp) LogModule.report(logvisor::Error, _SYS_STR("unable to open '%s' for reading"), path.data());
{ }
err = true;
LogModule.report(logvisor::Error, _SYS_STR("unable to open '%s' for reading"), path.data());
}
}
ReadStream(SystemStringView path, uint64_t offset, bool& err)
: ReadStream(path, err)
{
if (err)
return;
FSeek(fp, offset, SEEK_SET);
}
~ReadStream()
{
fclose(fp);
}
void seek(int64_t offset, int whence)
{
FSeek(fp, offset, whence);
}
uint64_t position() const
{
return FTell(fp);
}
uint64_t read(void* buf, uint64_t length)
{
return fread(buf, 1, length, fp);
}
uint64_t copyToDisc(IPartWriteStream& discio, uint64_t length)
{
uint64_t written = 0;
uint8_t buf[0x7c00];
while (length)
{
uint64_t thisSz = nod::min(uint64_t(0x7c00), length);
if (read(buf, thisSz) != thisSz)
{
LogModule.report(logvisor::Error, "unable to read enough from file");
return written;
}
if (discio.write(buf, thisSz) != thisSz)
{
LogModule.report(logvisor::Error, "unable to write enough to disc");
return written;
}
length -= thisSz;
written += thisSz;
}
return written;
}
};
std::unique_ptr<IReadStream> beginReadStream() const
{
bool Err = false;
auto ret = std::unique_ptr<IReadStream>(new ReadStream(m_path, Err));
if (Err)
return {};
return ret;
} }
std::unique_ptr<IReadStream> beginReadStream(uint64_t offset) const ReadStream(SystemStringView path, uint64_t offset, bool& err) : ReadStream(path, err) {
{ if (err)
bool Err = false; return;
auto ret = std::unique_ptr<IReadStream>(new ReadStream(m_path, offset, Err)); FSeek(fp, offset, SEEK_SET);
if (Err)
return {};
return ret;
} }
~ReadStream() { fclose(fp); }
void seek(int64_t offset, int whence) { FSeek(fp, offset, whence); }
uint64_t position() const { return FTell(fp); }
uint64_t read(void* buf, uint64_t length) { return fread(buf, 1, length, fp); }
uint64_t copyToDisc(IPartWriteStream& discio, uint64_t length) {
uint64_t written = 0;
uint8_t buf[0x7c00];
while (length) {
uint64_t thisSz = nod::min(uint64_t(0x7c00), length);
if (read(buf, thisSz) != thisSz) {
LogModule.report(logvisor::Error, "unable to read enough from file");
return written;
}
if (discio.write(buf, thisSz) != thisSz) {
LogModule.report(logvisor::Error, "unable to write enough to disc");
return written;
}
length -= thisSz;
written += thisSz;
}
return written;
}
};
std::unique_ptr<IReadStream> beginReadStream() const {
bool Err = false;
auto ret = std::unique_ptr<IReadStream>(new ReadStream(m_path, Err));
if (Err)
return {};
return ret;
}
std::unique_ptr<IReadStream> beginReadStream(uint64_t offset) const {
bool Err = false;
auto ret = std::unique_ptr<IReadStream>(new ReadStream(m_path, offset, Err));
if (Err)
return {};
return ret;
}
}; };
std::unique_ptr<IFileIO> NewFileIO(SystemStringView path, int64_t maxWriteSize) std::unique_ptr<IFileIO> NewFileIO(SystemStringView path, int64_t maxWriteSize) {
{ return std::unique_ptr<IFileIO>(new FileIOFILE(path, maxWriteSize));
return std::unique_ptr<IFileIO>(new FileIOFILE(path, maxWriteSize));
} }
} } // namespace nod

View File

@ -4,222 +4,186 @@
#include "nod/Util.hpp" #include "nod/Util.hpp"
#include "nod/IFileIO.hpp" #include "nod/IFileIO.hpp"
namespace nod namespace nod {
{
class FileIOWin32 : public IFileIO {
SystemString m_path;
int64_t m_maxWriteSize;
class FileIOWin32 : public IFileIO
{
SystemString m_path;
int64_t m_maxWriteSize;
public: public:
FileIOWin32(SystemStringView path, int64_t maxWriteSize) FileIOWin32(SystemStringView path, int64_t maxWriteSize) : m_path(path), m_maxWriteSize(maxWriteSize) {}
: m_path(path), m_maxWriteSize(maxWriteSize) {}
bool exists() bool exists() {
{
#if !WINDOWS_STORE #if !WINDOWS_STORE
HANDLE fp = CreateFileW(m_path.c_str(), GENERIC_READ, FILE_SHARE_READ, HANDLE fp = CreateFileW(m_path.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING,
nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); FILE_ATTRIBUTE_NORMAL, nullptr);
#else #else
HANDLE fp = CreateFile2(m_path.c_str(), GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, nullptr); HANDLE fp = CreateFile2(m_path.c_str(), GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, nullptr);
#endif #endif
if (fp == INVALID_HANDLE_VALUE) if (fp == INVALID_HANDLE_VALUE)
return false; return false;
CloseHandle(fp); CloseHandle(fp);
return true; return true;
} }
uint64_t size() uint64_t size() {
{
#if !WINDOWS_STORE #if !WINDOWS_STORE
HANDLE fp = CreateFileW(m_path.c_str(), GENERIC_READ, FILE_SHARE_READ, HANDLE fp = CreateFileW(m_path.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING,
nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); FILE_ATTRIBUTE_NORMAL, nullptr);
#else #else
HANDLE fp = CreateFile2(m_path.c_str(), GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, nullptr); HANDLE fp = CreateFile2(m_path.c_str(), GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, nullptr);
#endif #endif
if (fp == INVALID_HANDLE_VALUE) if (fp == INVALID_HANDLE_VALUE)
return 0; return 0;
LARGE_INTEGER sz; LARGE_INTEGER sz;
if (!GetFileSizeEx(fp, &sz)) if (!GetFileSizeEx(fp, &sz)) {
{ CloseHandle(fp);
CloseHandle(fp); return 0;
return 0;
}
CloseHandle(fp);
return sz.QuadPart;
} }
CloseHandle(fp);
return sz.QuadPart;
}
struct WriteStream : public IFileIO::IWriteStream struct WriteStream : public IFileIO::IWriteStream {
{ HANDLE fp;
HANDLE fp; int64_t m_maxWriteSize;
int64_t m_maxWriteSize; WriteStream(SystemStringView path, int64_t maxWriteSize, bool& err) : m_maxWriteSize(maxWriteSize) {
WriteStream(SystemStringView path, int64_t maxWriteSize, bool& err)
: m_maxWriteSize(maxWriteSize)
{
#if !WINDOWS_STORE #if !WINDOWS_STORE
fp = CreateFileW(path.data(), GENERIC_WRITE, FILE_SHARE_WRITE, fp = CreateFileW(path.data(), GENERIC_WRITE, FILE_SHARE_WRITE, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); nullptr);
#else #else
fp = CreateFile2(path.data(), GENERIC_WRITE, FILE_SHARE_WRITE, CREATE_ALWAYS, nullptr); fp = CreateFile2(path.data(), GENERIC_WRITE, FILE_SHARE_WRITE, CREATE_ALWAYS, nullptr);
#endif #endif
if (fp == INVALID_HANDLE_VALUE) if (fp == INVALID_HANDLE_VALUE) {
{ LogModule.report(logvisor::Error, _SYS_STR("unable to open '%s' for writing"), path.data());
LogModule.report(logvisor::Error, _SYS_STR("unable to open '%s' for writing"), path.data()); err = true;
err = true; }
} }
} WriteStream(SystemStringView path, uint64_t offset, int64_t maxWriteSize, bool& err)
WriteStream(SystemStringView path, uint64_t offset, int64_t maxWriteSize, bool& err) : m_maxWriteSize(maxWriteSize) {
: m_maxWriteSize(maxWriteSize)
{
#if !WINDOWS_STORE #if !WINDOWS_STORE
fp = CreateFileW(path.data(), GENERIC_WRITE, FILE_SHARE_WRITE, fp = CreateFileW(path.data(), GENERIC_WRITE, FILE_SHARE_WRITE, nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL,
nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); nullptr);
#else #else
fp = CreateFile2(path.data(), GENERIC_WRITE, FILE_SHARE_WRITE, OPEN_ALWAYS, nullptr); fp = CreateFile2(path.data(), GENERIC_WRITE, FILE_SHARE_WRITE, OPEN_ALWAYS, nullptr);
#endif #endif
if (fp == INVALID_HANDLE_VALUE) if (fp == INVALID_HANDLE_VALUE) {
{ LogModule.report(logvisor::Error, _SYS_STR("unable to open '%s' for writing"), path.data());
LogModule.report(logvisor::Error, _SYS_STR("unable to open '%s' for writing"), path.data()); err = true;
err = true; return;
return; }
} LARGE_INTEGER lioffset;
LARGE_INTEGER lioffset; lioffset.QuadPart = offset;
lioffset.QuadPart = offset; SetFilePointerEx(fp, lioffset, nullptr, FILE_BEGIN);
SetFilePointerEx(fp, lioffset, nullptr, FILE_BEGIN); }
~WriteStream() { CloseHandle(fp); }
uint64_t write(const void* buf, uint64_t length) {
if (m_maxWriteSize >= 0) {
LARGE_INTEGER li = {};
LARGE_INTEGER res;
SetFilePointerEx(fp, li, &res, FILE_CURRENT);
if (res.QuadPart + int64_t(length) > m_maxWriteSize) {
LogModule.report(logvisor::Error, _SYS_STR("write operation exceeds file's %" PRIi64 "-byte limit"),
m_maxWriteSize);
return 0;
} }
~WriteStream() }
{
CloseHandle(fp);
}
uint64_t write(const void* buf, uint64_t length)
{
if (m_maxWriteSize >= 0)
{
LARGE_INTEGER li = {};
LARGE_INTEGER res;
SetFilePointerEx(fp, li, &res, FILE_CURRENT);
if (res.QuadPart + int64_t(length) > m_maxWriteSize)
{
LogModule.report(logvisor::Error, _SYS_STR("write operation exceeds file's %" PRIi64 "-byte limit"), m_maxWriteSize);
return 0;
}
}
DWORD ret = 0; DWORD ret = 0;
WriteFile(fp, buf, length, &ret, nullptr); WriteFile(fp, buf, length, &ret, nullptr);
return ret; return ret;
}
};
std::unique_ptr<IWriteStream> beginWriteStream() const
{
bool Err = false;
auto ret = std::unique_ptr<IWriteStream>(new WriteStream(m_path, m_maxWriteSize, Err));
if (Err)
return {};
return ret;
}
std::unique_ptr<IWriteStream> beginWriteStream(uint64_t offset) const
{
bool Err = false;
auto ret = std::unique_ptr<IWriteStream>(new WriteStream(m_path, offset, m_maxWriteSize, Err));
if (Err)
return {};
return ret;
} }
};
std::unique_ptr<IWriteStream> beginWriteStream() const {
bool Err = false;
auto ret = std::unique_ptr<IWriteStream>(new WriteStream(m_path, m_maxWriteSize, Err));
if (Err)
return {};
return ret;
}
std::unique_ptr<IWriteStream> beginWriteStream(uint64_t offset) const {
bool Err = false;
auto ret = std::unique_ptr<IWriteStream>(new WriteStream(m_path, offset, m_maxWriteSize, Err));
if (Err)
return {};
return ret;
}
struct ReadStream : public IFileIO::IReadStream struct ReadStream : public IFileIO::IReadStream {
{ HANDLE fp;
HANDLE fp; ReadStream(SystemStringView path, bool& err) {
ReadStream(SystemStringView path, bool& err)
{
#if !WINDOWS_STORE #if !WINDOWS_STORE
fp = CreateFileW(path.data(), GENERIC_READ, FILE_SHARE_READ, fp = CreateFileW(path.data(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); nullptr);
#else #else
fp = CreateFile2(path.data(), GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, nullptr); fp = CreateFile2(path.data(), GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, nullptr);
#endif #endif
if (fp == INVALID_HANDLE_VALUE) if (fp == INVALID_HANDLE_VALUE) {
{ err = true;
err = true; LogModule.report(logvisor::Error, _SYS_STR("unable to open '%s' for reading"), path.data());
LogModule.report(logvisor::Error, _SYS_STR("unable to open '%s' for reading"), path.data()); }
}
}
ReadStream(SystemStringView path, uint64_t offset, bool& err)
: ReadStream(path, err)
{
if (err)
return;
LARGE_INTEGER lioffset;
lioffset.QuadPart = offset;
SetFilePointerEx(fp, lioffset, nullptr, FILE_BEGIN);
}
~ReadStream()
{
CloseHandle(fp);
}
void seek(int64_t offset, int whence)
{
LARGE_INTEGER li;
li.QuadPart = offset;
SetFilePointerEx(fp, li, nullptr, whence);
}
uint64_t position() const
{
LARGE_INTEGER li = {};
LARGE_INTEGER res;
SetFilePointerEx(fp, li, &res, FILE_CURRENT);
return res.QuadPart;
}
uint64_t read(void* buf, uint64_t length)
{
DWORD ret = 0;
ReadFile(fp, buf, length, &ret, nullptr);
return ret;
}
uint64_t copyToDisc(IPartWriteStream& discio, uint64_t length)
{
uint64_t written = 0;
uint8_t buf[0x7c00];
while (length)
{
uint64_t thisSz = nod::min(uint64_t(0x7c00), length);
if (read(buf, thisSz) != thisSz)
{
LogModule.report(logvisor::Error, "unable to read enough from file");
return written;
}
if (discio.write(buf, thisSz) != thisSz)
{
LogModule.report(logvisor::Error, "unable to write enough to disc");
return written;
}
length -= thisSz;
written += thisSz;
}
return written;
}
};
std::unique_ptr<IReadStream> beginReadStream() const
{
bool Err = false;
auto ret = std::unique_ptr<IReadStream>(new ReadStream(m_path, Err));
if (Err)
return {};
return ret;
} }
std::unique_ptr<IReadStream> beginReadStream(uint64_t offset) const ReadStream(SystemStringView path, uint64_t offset, bool& err) : ReadStream(path, err) {
{ if (err)
bool Err = false; return;
auto ret = std::unique_ptr<IReadStream>(new ReadStream(m_path, offset, Err)); LARGE_INTEGER lioffset;
if (Err) lioffset.QuadPart = offset;
return {}; SetFilePointerEx(fp, lioffset, nullptr, FILE_BEGIN);
return ret;
} }
~ReadStream() { CloseHandle(fp); }
void seek(int64_t offset, int whence) {
LARGE_INTEGER li;
li.QuadPart = offset;
SetFilePointerEx(fp, li, nullptr, whence);
}
uint64_t position() const {
LARGE_INTEGER li = {};
LARGE_INTEGER res;
SetFilePointerEx(fp, li, &res, FILE_CURRENT);
return res.QuadPart;
}
uint64_t read(void* buf, uint64_t length) {
DWORD ret = 0;
ReadFile(fp, buf, length, &ret, nullptr);
return ret;
}
uint64_t copyToDisc(IPartWriteStream& discio, uint64_t length) {
uint64_t written = 0;
uint8_t buf[0x7c00];
while (length) {
uint64_t thisSz = nod::min(uint64_t(0x7c00), length);
if (read(buf, thisSz) != thisSz) {
LogModule.report(logvisor::Error, "unable to read enough from file");
return written;
}
if (discio.write(buf, thisSz) != thisSz) {
LogModule.report(logvisor::Error, "unable to write enough to disc");
return written;
}
length -= thisSz;
written += thisSz;
}
return written;
}
};
std::unique_ptr<IReadStream> beginReadStream() const {
bool Err = false;
auto ret = std::unique_ptr<IReadStream>(new ReadStream(m_path, Err));
if (Err)
return {};
return ret;
}
std::unique_ptr<IReadStream> beginReadStream(uint64_t offset) const {
bool Err = false;
auto ret = std::unique_ptr<IReadStream>(new ReadStream(m_path, offset, Err));
if (Err)
return {};
return ret;
}
}; };
std::unique_ptr<IFileIO> NewFileIO(SystemStringView path, int64_t maxWriteSize) std::unique_ptr<IFileIO> NewFileIO(SystemStringView path, int64_t maxWriteSize) {
{ return std::unique_ptr<IFileIO>(new FileIOWin32(path, maxWriteSize));
return std::unique_ptr<IFileIO>(new FileIOWin32(path, maxWriteSize));
} }
} } // namespace nod

File diff suppressed because it is too large Load Diff

View File

@ -2,87 +2,73 @@
#include "nod/nod.hpp" #include "nod/nod.hpp"
#include "nod/DiscBase.hpp" #include "nod/DiscBase.hpp"
namespace nod namespace nod {
{
logvisor::Module LogModule("nod"); logvisor::Module LogModule("nod");
std::unique_ptr<IDiscIO> NewDiscIOISO(SystemStringView path); std::unique_ptr<IDiscIO> NewDiscIOISO(SystemStringView path);
std::unique_ptr<IDiscIO> NewDiscIOWBFS(SystemStringView path); std::unique_ptr<IDiscIO> NewDiscIOWBFS(SystemStringView path);
std::unique_ptr<DiscBase> OpenDiscFromImage(SystemStringView path, bool& isWii) std::unique_ptr<DiscBase> OpenDiscFromImage(SystemStringView path, bool& isWii) {
{ /* Temporary file handle to determine image type */
/* Temporary file handle to determine image type */ std::unique_ptr<IFileIO> fio = NewFileIO(path);
std::unique_ptr<IFileIO> fio = NewFileIO(path); if (!fio->exists()) {
if (!fio->exists()) LogModule.report(logvisor::Error, _SYS_STR("Unable to open '%s'"), path.data());
{ return {};
LogModule.report(logvisor::Error, _SYS_STR("Unable to open '%s'"), path.data()); }
return {}; std::unique_ptr<IFileIO::IReadStream> rs = fio->beginReadStream();
} if (!rs)
std::unique_ptr<IFileIO::IReadStream> rs = fio->beginReadStream(); return {};
if (!rs)
return {};
isWii = false; isWii = false;
std::unique_ptr<IDiscIO> discIO; std::unique_ptr<IDiscIO> discIO;
uint32_t magic = 0; uint32_t magic = 0;
if (rs->read(&magic, 4) != 4) if (rs->read(&magic, 4) != 4) {
{ LogModule.report(logvisor::Error, _SYS_STR("Unable to read magic from '%s'"), path.data());
LogModule.report(logvisor::Error, _SYS_STR("Unable to read magic from '%s'"), path.data()); return {};
return {}; }
}
if (magic == nod::SBig((uint32_t)'WBFS')) if (magic == nod::SBig((uint32_t)'WBFS')) {
{ discIO = NewDiscIOWBFS(path);
discIO = NewDiscIOWBFS(path); isWii = true;
isWii = true; } else {
} rs->seek(0x18, SEEK_SET);
else rs->read(&magic, 4);
{ magic = nod::SBig(magic);
rs->seek(0x18, SEEK_SET); if (magic == 0x5D1C9EA3) {
rs->read(&magic, 4); discIO = NewDiscIOISO(path);
magic = nod::SBig(magic); isWii = true;
if (magic == 0x5D1C9EA3) } else {
{ rs->read(&magic, 4);
discIO = NewDiscIOISO(path); magic = nod::SBig(magic);
isWii = true; if (magic == 0xC2339F3D)
} discIO = NewDiscIOISO(path);
else
{
rs->read(&magic, 4);
magic = nod::SBig(magic);
if (magic == 0xC2339F3D)
discIO = NewDiscIOISO(path);
}
} }
}
if (!discIO) if (!discIO) {
{ LogModule.report(logvisor::Error, _SYS_STR("'%s' is not a valid image"), path.data());
LogModule.report(logvisor::Error, _SYS_STR("'%s' is not a valid image"), path.data()); return {};
return {}; }
}
bool Err = false; bool Err = false;
std::unique_ptr<DiscBase> ret; std::unique_ptr<DiscBase> ret;
if (isWii) if (isWii) {
{ ret = std::unique_ptr<DiscBase>(new DiscWii(std::move(discIO), Err));
ret = std::unique_ptr<DiscBase>(new DiscWii(std::move(discIO), Err));
if (Err)
return {};
return ret;
}
ret = std::unique_ptr<DiscBase>(new DiscGCN(std::move(discIO), Err));
if (Err) if (Err)
return {}; return {};
return ret; return ret;
}
ret = std::unique_ptr<DiscBase>(new DiscGCN(std::move(discIO), Err));
if (Err)
return {};
return ret;
} }
std::unique_ptr<DiscBase> OpenDiscFromImage(SystemStringView path) std::unique_ptr<DiscBase> OpenDiscFromImage(SystemStringView path) {
{ bool isWii;
bool isWii; return OpenDiscFromImage(path, isWii);
return OpenDiscFromImage(path, isWii);
}
} }
} // namespace nod

@ -1 +1 @@
Subproject commit 1b6c2ae7159fd4fd7a80b1951d5ed43e4d1a3676 Subproject commit 01e291833ba4d7f2a596c32cf6158cb6a9327ad7