diff --git a/README.md b/README.md index 855704c..afa38a0 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ ### NODLib -**NODLib** is a library and utility (`nodtool`) for traversing, dumping, and authoring +**NODLib** is a library and utility (`nodtool`) for traversing, dumping, and authoring *GameCube* and *Wii* optical disc images. #### Library @@ -8,23 +8,23 @@ The primary motivation of NODLib is to supply a *uniform C++11 API* for accessing data from image files directly. `NOD::DiscBase` provides a common interface for traversing partitions and individual files. Files may be individually streamed, or the whole partition may be extracted -to the user's filesystem. Raw *ISO* and *WBFS* images are supported read sources. +to the user's filesystem. Raw *ISO* and *WBFS* images are supported read sources. ```cpp bool isWii; /* Set by reference next line */ std::unique_ptr disc = NOD::OpenDiscFromImage(path, isWii); if (!disc) - return FAILURE; + return FAILURE; /* Access first data-partition on Wii, or full GameCube disc */ NOD::Partition* dataPart = disc->getDataPartition(); if (!dataPart) - return FAILURE; + return FAILURE; /* One-shot extraction to filesystem */ if (!dataPart->extractToDirectory(outDir, ctx)) - return FAILURE; - + return FAILURE; + return SUCCESS; ``` @@ -36,18 +36,18 @@ a content pipeline using the `NOD::DiscBuilderBase` interface. size_t lastIdx = -1; auto progFunc = [&](size_t idx, const NOD::SystemString& name, size_t bytes) { - if (idx != lastIdx) - { - lastIdx = idx; - /* NOD provides I/O wrappers using wchar_t on Windows; - * _S() conditionally makes string-literals wide */ - NOD::Printf(_S("\n")); - } - if (bytes != -1) - NOD::Printf(_S("\r%s %" PRISize " B"), name.c_str(), bytes); - else - NOD::Printf(_S("\r%s"), name.c_str()); - fflush(stdout); + if (idx != lastIdx) + { + lastIdx = idx; + /* NOD provides I/O wrappers using wchar_t on Windows; + * _S() conditionally makes string-literals wide */ + NOD::Printf(_S("\n")); + } + if (bytes != -1) + NOD::Printf(_S("\r%s %" PRISize " B"), name.c_str(), bytes); + else + NOD::Printf(_S("\r%s"), name.c_str()); + fflush(stdout); }; /* Making a GCN image */ diff --git a/include/NOD/IFileIO.hpp b/include/NOD/IFileIO.hpp index fe4efdc..143d58c 100644 --- a/include/NOD/IFileIO.hpp +++ b/include/NOD/IFileIO.hpp @@ -29,6 +29,7 @@ public: { virtual ~IReadStream() {} virtual void seek(int64_t offset, int whence)=0; + virtual int64_t position()=0; virtual uint64_t read(void* buf, uint64_t length)=0; virtual uint64_t copyToDisc(struct IPartWriteStream& discio, uint64_t length)=0; }; diff --git a/include/NOD/Util.hpp b/include/NOD/Util.hpp index 2a42084..e6329d1 100644 --- a/include/NOD/Util.hpp +++ b/include/NOD/Util.hpp @@ -290,6 +290,17 @@ static inline int FSeek(FILE* fp, int64_t offset, int whence) #endif } +static inline int64_t FTell(FILE* fp) +{ +#if _WIN32 + return _ftelli64(fp); +#elif __APPLE__ || __FreeBSD__ + return ftello(fp); +#else + return ftello64(fp); +#endif +} + static inline bool CheckFreeSpace(const SystemChar* path, size_t reqSz) { #if _WIN32 @@ -308,7 +319,7 @@ static inline bool CheckFreeSpace(const SystemChar* path, size_t reqSz) struct statvfs svfs; if (statvfs(path, &svfs)) LogModule.report(LogVisor::FatalError, "statvfs %s: %s", path, strerror(errno)); - return reqSz < svfs.f_bsize * svfs.f_bfree; + return reqSz < svfs.f_frsize * svfs.f_bavail; #endif } diff --git a/lib/DiscIOISO.cpp b/lib/DiscIOISO.cpp index 5cb6f5d..c4e8a33 100644 --- a/lib/DiscIOISO.cpp +++ b/lib/DiscIOISO.cpp @@ -1,146 +1,55 @@ #include #include "NOD/Util.hpp" #include "NOD/IDiscIO.hpp" +#include "NOD/IFileIO.hpp" namespace NOD { class DiscIOISO : public IDiscIO { - SystemString filepath; + std::unique_ptr m_fio; public: DiscIOISO(const SystemString& fpin) - : filepath(fpin) {} + : m_fio(std::move(NewFileIO(fpin))) {} class ReadStream : public IReadStream { friend class DiscIOISO; -#if _WIN32 - HANDLE fp; - ReadStream(HANDLE fpin) - : fp(fpin) {} - ~ReadStream() {CloseHandle(fp);} -#else - FILE* fp; - ReadStream(FILE* fpin) - : fp(fpin) {} - ~ReadStream() {fclose(fp);} -#endif + std::unique_ptr fp; + ReadStream(std::unique_ptr&& fpin) + : fp(std::move(fpin)) {} public: -#if _WIN32 uint64_t read(void* buf, uint64_t length) - { - DWORD ret = 0; - ReadFile(fp, buf, length, &ret, nullptr); - return ret; - } + {return fp->read(buf, length);} uint64_t position() const - { - LARGE_INTEGER liOfs={0}; - LARGE_INTEGER liNew={0}; - SetFilePointerEx(fp, liOfs, &liNew, FILE_CURRENT); - return liNew.QuadPart; - } + {return fp->position();} void seek(int64_t offset, int whence) - { - LARGE_INTEGER li; - li.QuadPart = offset; - SetFilePointerEx(fp, li, nullptr, whence); - } -#else - uint64_t read(void* buf, uint64_t length) - {return fread(buf, 1, length, fp);} - uint64_t position() const - {return ftello(fp);} - void seek(int64_t offset, int whence) - {FSeek(fp, offset, whence);} -#endif + {fp->seek(offset, whence);} }; -#if _WIN32 std::unique_ptr beginReadStream(uint64_t offset) const { - HANDLE fp = CreateFileW(filepath.c_str(), GENERIC_READ, FILE_SHARE_READ, - nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); - if (fp == INVALID_HANDLE_VALUE) - { - LogModule.report(LogVisor::Error, _S("Unable to open '%s' for reading"), filepath.c_str()); - return std::unique_ptr(); - } - LARGE_INTEGER li; - li.QuadPart = offset; - SetFilePointerEx(fp, li, nullptr, FILE_BEGIN); - return std::unique_ptr(new ReadStream(fp)); + return std::unique_ptr(new ReadStream(std::move(m_fio->beginReadStream(offset)))); } -#else - std::unique_ptr beginReadStream(uint64_t offset) const - { - FILE* fp = fopen(filepath.c_str(), "rb"); - if (!fp) - { - LogModule.report(LogVisor::Error, _S("Unable to open '%s' for reading"), filepath.c_str()); - return std::unique_ptr(); - } - FSeek(fp, offset, SEEK_SET); - return std::unique_ptr(new ReadStream(fp)); - } -#endif class WriteStream : public IWriteStream { friend class DiscIOISO; -#if _WIN32 - HANDLE fp; - WriteStream(HANDLE fpin) - : fp(fpin) {} - ~WriteStream() {CloseHandle(fp);} -#else - FILE* fp; - WriteStream(FILE* fpin) - : fp(fpin) {} - ~WriteStream() {fclose(fp);} -#endif + std::unique_ptr fp; + WriteStream(std::unique_ptr&& fpin) + : fp(std::move(fpin)) {} public: uint64_t write(const void* buf, uint64_t length) { -#if _WIN32 - DWORD ret = 0; - WriteFile(fp, buf, length, &ret, nullptr); - return ret; -#else - return fwrite(buf, 1, length, fp); -#endif + return fp->write(buf, length); } }; -#if _WIN32 std::unique_ptr beginWriteStream(uint64_t offset) const { - HANDLE fp = CreateFileW(filepath.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, - nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); - if (fp == INVALID_HANDLE_VALUE) - { - LogModule.report(LogVisor::Error, _S("Unable to open '%s' for writing"), filepath.c_str()); - return std::unique_ptr(); - } - LARGE_INTEGER li; - li.QuadPart = offset; - SetFilePointerEx(fp, li, nullptr, FILE_BEGIN); - return std::unique_ptr(new WriteStream(fp)); + return std::unique_ptr(new WriteStream(std::move(m_fio->beginWriteStream(offset)))); } -#else - std::unique_ptr beginWriteStream(uint64_t offset) const - { - FILE* fp = fopen(filepath.c_str(), "wb"); - if (!fp) - { - LogModule.report(LogVisor::Error, _S("Unable to open '%s' for writing"), filepath.c_str()); - return std::unique_ptr(); - } - FSeek(fp, offset, SEEK_SET); - return std::unique_ptr(new WriteStream(fp)); - } -#endif }; std::unique_ptr NewDiscIOISO(const SystemChar* path) diff --git a/lib/FileIOFILE.cpp b/lib/FileIOFILE.cpp index c498a64..87c0400 100644 --- a/lib/FileIOFILE.cpp +++ b/lib/FileIOFILE.cpp @@ -37,7 +37,6 @@ public: struct WriteStream : public IFileIO::IWriteStream { - uint8_t buf[0x7c00]; FILE* fp; WriteStream(const SystemString& path) { @@ -70,6 +69,7 @@ public: uint64_t copyFromDisc(IPartReadStream& discio, uint64_t length) { uint64_t read = 0; + uint8_t buf[0x7c00]; while (length) { uint64_t thisSz = NOD::min(uint64_t(0x7c00), length); @@ -102,7 +102,6 @@ public: struct ReadStream : public IFileIO::IReadStream { FILE* fp; - uint8_t buf[0x7c00]; ReadStream(const SystemString& path) { fp = fopen(path.c_str(), "rb"); @@ -122,6 +121,10 @@ public: { FSeek(fp, offset, whence); } + int64_t position() + { + return FTell(fp); + } uint64_t read(void* buf, uint64_t length) { return fread(buf, 1, length, fp); @@ -129,6 +132,7 @@ public: 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); diff --git a/lib/FileIOWin32.cpp b/lib/FileIOWin32.cpp index 6b17b26..0fa6f02 100644 --- a/lib/FileIOWin32.cpp +++ b/lib/FileIOWin32.cpp @@ -43,7 +43,6 @@ public: struct WriteStream : public IFileIO::IWriteStream { - uint8_t buf[0x7c00]; HANDLE fp; WriteStream(const SystemString& path) { @@ -75,6 +74,7 @@ public: uint64_t copyFromDisc(IPartReadStream& discio, uint64_t length) { uint64_t read = 0; + uint8_t buf[0x7c00]; while (length) { uint64_t thisSz = NOD::min(uint64_t(0x7c00), length); @@ -107,7 +107,6 @@ public: struct ReadStream : public IFileIO::IReadStream { HANDLE fp; - uint8_t buf[0x7c00]; ReadStream(const SystemString& path) { fp = CreateFileW(path.c_str(), GENERIC_READ, FILE_SHARE_READ, @@ -132,6 +131,13 @@ public: li.QuadPart = offset; SetFilePointerEx(fp, li, nullptr, whence); } + int64_t position() + { + 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; @@ -141,6 +147,7 @@ public: 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);