mirror of
https://github.com/AxioDL/nod.git
synced 2025-07-04 04:06:09 +00:00
lots of Wii disc parsing in place
This commit is contained in:
parent
ccb67d0d0e
commit
03a371b7bf
@ -7,6 +7,7 @@ QT =
|
|||||||
INCLUDEPATH += include
|
INCLUDEPATH += include
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
|
include/Util.hpp \
|
||||||
include/NODLib.hpp \
|
include/NODLib.hpp \
|
||||||
include/IDiscIO.hpp \
|
include/IDiscIO.hpp \
|
||||||
include/IFileIO.hpp \
|
include/IFileIO.hpp \
|
||||||
@ -16,11 +17,11 @@ HEADERS += \
|
|||||||
|
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
lib/NODLib.cpp \
|
lib/NODLib.cpp \
|
||||||
lib/DiscIOFILE.cpp \
|
|
||||||
lib/DiscIOWBFS.cpp \
|
|
||||||
lib/FileIOFILE.cpp \
|
lib/FileIOFILE.cpp \
|
||||||
lib/FileIOMEM.cpp \
|
lib/FileIOMEM.cpp \
|
||||||
lib/DiscBase.cpp \
|
lib/DiscBase.cpp \
|
||||||
lib/DiscGCN.cpp \
|
lib/DiscGCN.cpp \
|
||||||
lib/DiscWii.cpp \
|
lib/DiscWii.cpp \
|
||||||
main.cpp
|
main.cpp \
|
||||||
|
lib/DiscIOWBFS.cpp \
|
||||||
|
lib/DiscIOISO.cpp
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
#ifndef __NOD_DISC_BASE__
|
#ifndef __NOD_DISC_BASE__
|
||||||
#define __NOD_DISC_BASE__
|
#define __NOD_DISC_BASE__
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include "Util.hpp"
|
||||||
#include "IDiscIO.hpp"
|
#include "IDiscIO.hpp"
|
||||||
#include "IFileIO.hpp"
|
#include "IFileIO.hpp"
|
||||||
|
|
||||||
@ -12,56 +14,105 @@ namespace NOD
|
|||||||
|
|
||||||
class DiscBase
|
class DiscBase
|
||||||
{
|
{
|
||||||
IDiscIO& m_discIO;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
class IPartReadStream
|
struct Header
|
||||||
|
{
|
||||||
|
char gameID[6];
|
||||||
|
char discNum;
|
||||||
|
char discVersion;
|
||||||
|
char audioStreaming;
|
||||||
|
char streamBufSz;
|
||||||
|
char unk[14];
|
||||||
|
uint32_t wiiMagic;
|
||||||
|
uint32_t gcnMagic;
|
||||||
|
char gameTitle[64];
|
||||||
|
|
||||||
|
Header(IDiscIO& dio)
|
||||||
|
{
|
||||||
|
std::unique_ptr<IDiscIO::IReadStream> s = dio.beginReadStream(0);
|
||||||
|
s->read(this, sizeof(*this));
|
||||||
|
wiiMagic = SBig(wiiMagic);
|
||||||
|
gcnMagic = SBig(gcnMagic);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FSTNode
|
||||||
|
{
|
||||||
|
uint32_t typeAndNameOff;
|
||||||
|
uint32_t offset;
|
||||||
|
uint32_t length;
|
||||||
|
FSTNode(IDiscIO::IReadStream& s)
|
||||||
|
{
|
||||||
|
s.read(this, 12);
|
||||||
|
typeAndNameOff = SBig(typeAndNameOff);
|
||||||
|
offset = SBig(offset);
|
||||||
|
length = SBig(length);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct IPartReadStream
|
||||||
{
|
{
|
||||||
public:
|
|
||||||
virtual size_t read(void* buf, size_t length)=0;
|
virtual size_t read(void* buf, size_t length)=0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class IPartWriteStream
|
struct IPartWriteStream
|
||||||
{
|
{
|
||||||
public:
|
|
||||||
virtual size_t write(void* buf, size_t length)=0;
|
virtual size_t write(void* buf, size_t length)=0;
|
||||||
};
|
};
|
||||||
|
|
||||||
protected:
|
class IPartition
|
||||||
class Partition
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
enum Kind
|
enum Kind
|
||||||
{
|
{
|
||||||
PART_DATA,
|
PART_DATA,
|
||||||
PART_UPDATE
|
PART_UPDATE,
|
||||||
|
PART_CHANNEL
|
||||||
};
|
};
|
||||||
class File
|
class Node
|
||||||
{
|
{
|
||||||
const Partition& m_parent;
|
|
||||||
std::unique_ptr<IFileIO> m_hddFile;
|
|
||||||
std::string m_discPath;
|
|
||||||
size_t m_discOffset;
|
|
||||||
size_t m_discLength;
|
|
||||||
public:
|
public:
|
||||||
File(const Partition& parent, const std::string& discPath)
|
enum Kind
|
||||||
: m_parent(parent), m_discPath(discPath) {}
|
{
|
||||||
std::unique_ptr<IPartReadStream> beginReadStream();
|
NODE_FILE,
|
||||||
|
NODE_DIRECTORY
|
||||||
};
|
};
|
||||||
private:
|
private:
|
||||||
std::list<File> files;
|
const IPartition& m_parent;
|
||||||
Kind m_kind;
|
Kind m_kind;
|
||||||
|
std::string m_name;
|
||||||
|
|
||||||
|
std::unique_ptr<IFileIO> m_hddFile;
|
||||||
|
size_t m_discOffset;
|
||||||
|
size_t m_discLength;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Partition(Kind kind)
|
Node(const IPartition& parent, bool isDir, const char* name)
|
||||||
: m_kind(kind) {}
|
: m_parent(parent), m_kind(isDir ? NODE_DIRECTORY : NODE_FILE), m_name(name) {}
|
||||||
|
inline Kind getKind() const {return m_kind;}
|
||||||
|
std::unique_ptr<IPartReadStream> beginReadStream();
|
||||||
|
};
|
||||||
|
protected:
|
||||||
|
std::list<Node> files;
|
||||||
|
const DiscBase& m_parent;
|
||||||
|
Kind m_kind;
|
||||||
|
size_t m_offset;
|
||||||
|
public:
|
||||||
|
IPartition(const DiscBase& parent, Kind kind, size_t offset)
|
||||||
|
: m_parent(parent), m_kind(kind), m_offset(offset) {}
|
||||||
|
inline Kind getKind() const {return m_kind;}
|
||||||
std::unique_ptr<IPartReadStream> beginReadStream(size_t offset);
|
std::unique_ptr<IPartReadStream> beginReadStream(size_t offset);
|
||||||
};
|
};
|
||||||
std::list<Partition> partitions;
|
|
||||||
Partition& addPartition(Partition::Kind kind);
|
|
||||||
public:
|
|
||||||
DiscBase(IDiscIO& dio);
|
|
||||||
virtual bool sync()=0;
|
|
||||||
|
|
||||||
|
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);
|
||||||
|
virtual bool commit()=0;
|
||||||
|
inline Header getHeader() const {return m_header;}
|
||||||
|
inline const IDiscIO& getDiscIO() const {return *m_discIO.get();}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,8 @@ namespace NOD
|
|||||||
class DiscGCN : public DiscBase
|
class DiscGCN : public DiscBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DiscGCN(IDiscIO& discio);
|
DiscGCN(std::unique_ptr<IDiscIO>&& dio);
|
||||||
|
bool commit();
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,8 @@ namespace NOD
|
|||||||
class DiscWii : public DiscBase
|
class DiscWii : public DiscBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DiscWii(IDiscIO& discio);
|
DiscWii(std::unique_ptr<IDiscIO>&& dio);
|
||||||
|
bool commit();
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
namespace NOD
|
namespace NOD
|
||||||
{
|
{
|
||||||
@ -12,19 +13,18 @@ class IDiscIO
|
|||||||
public:
|
public:
|
||||||
virtual ~IDiscIO() {}
|
virtual ~IDiscIO() {}
|
||||||
|
|
||||||
class IReadStream
|
struct IReadStream
|
||||||
{
|
{
|
||||||
public:
|
|
||||||
virtual size_t read(void* buf, size_t length)=0;
|
virtual size_t read(void* buf, size_t length)=0;
|
||||||
|
virtual void seek(size_t offset, int whence=SEEK_SET)=0;
|
||||||
};
|
};
|
||||||
virtual std::unique_ptr<IReadStream> beginReadStream(size_t offset)=0;
|
virtual std::unique_ptr<IReadStream> beginReadStream(size_t offset=0) const=0;
|
||||||
|
|
||||||
class IWriteStream
|
struct IWriteStream
|
||||||
{
|
{
|
||||||
public:
|
|
||||||
virtual size_t write(void* buf, size_t length)=0;
|
virtual size_t write(void* buf, size_t length)=0;
|
||||||
};
|
};
|
||||||
virtual std::unique_ptr<IWriteStream> beginWriteStream(size_t offset)=0;
|
virtual std::unique_ptr<IWriteStream> beginWriteStream(size_t offset=0) const=0;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -14,17 +14,15 @@ public:
|
|||||||
virtual ~IFileIO() {}
|
virtual ~IFileIO() {}
|
||||||
virtual size_t size()=0;
|
virtual size_t size()=0;
|
||||||
|
|
||||||
class IWriteStream
|
struct IWriteStream
|
||||||
{
|
{
|
||||||
public:
|
|
||||||
virtual ~IWriteStream() {}
|
virtual ~IWriteStream() {}
|
||||||
virtual size_t copyFromDisc(IDiscIO::IReadStream& discio, size_t length)=0;
|
virtual size_t copyFromDisc(IDiscIO::IReadStream& discio, size_t length)=0;
|
||||||
};
|
};
|
||||||
virtual std::unique_ptr<IWriteStream> beginWriteStream();
|
virtual std::unique_ptr<IWriteStream> beginWriteStream();
|
||||||
|
|
||||||
class IReadStream
|
struct IReadStream
|
||||||
{
|
{
|
||||||
public:
|
|
||||||
virtual ~IReadStream() {}
|
virtual ~IReadStream() {}
|
||||||
virtual size_t copyToDisc(IDiscIO::IWriteStream& discio, size_t length)=0;
|
virtual size_t copyToDisc(IDiscIO::IWriteStream& discio, size_t length)=0;
|
||||||
};
|
};
|
||||||
|
@ -2,15 +2,19 @@
|
|||||||
#define __NOD_LIB__
|
#define __NOD_LIB__
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include "DiscGCN.hpp"
|
|
||||||
#include "DiscWii.hpp"
|
|
||||||
#include "IDiscIO.hpp"
|
|
||||||
|
|
||||||
namespace NOD
|
namespace NOD
|
||||||
{
|
{
|
||||||
|
|
||||||
std::unique_ptr<DiscBase> OpenDiscFromImage(const char* path);
|
class DiscBase;
|
||||||
|
|
||||||
|
std::unique_ptr<DiscBase> OpenDiscFromImage(const char* path, bool& isWii);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include "DiscGCN.hpp"
|
||||||
|
#include "DiscWii.hpp"
|
||||||
|
#include "IDiscIO.hpp"
|
||||||
|
#include "Util.hpp"
|
||||||
|
|
||||||
#endif // __NOD_LIB__
|
#endif // __NOD_LIB__
|
||||||
|
86
include/Util.hpp
Normal file
86
include/Util.hpp
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
#ifndef __NOD_UTIL_HPP__
|
||||||
|
#define __NOD_UTIL_HPP__
|
||||||
|
|
||||||
|
namespace NOD
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Type-sensitive byte swappers */
|
||||||
|
template <typename T>
|
||||||
|
static inline T bswap16(T val)
|
||||||
|
{
|
||||||
|
#if __GNUC__
|
||||||
|
return __builtin_bswap16(val);
|
||||||
|
#elif _WIN32
|
||||||
|
return _byteswap_ushort(val);
|
||||||
|
#else
|
||||||
|
return (val = (val << 8) | ((val >> 8) & 0xFF));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static inline T bswap32(T val)
|
||||||
|
{
|
||||||
|
#if __GNUC__
|
||||||
|
return __builtin_bswap32(val);
|
||||||
|
#elif _WIN32
|
||||||
|
return _byteswap_ulong(val);
|
||||||
|
#else
|
||||||
|
val = (val & 0x0000FFFF) << 16 | (val & 0xFFFF0000) >> 16;
|
||||||
|
val = (val & 0x00FF00FF) << 8 | (val & 0xFF00FF00) >> 8;
|
||||||
|
return val;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static inline T bswap64(T val)
|
||||||
|
{
|
||||||
|
#if __GNUC__
|
||||||
|
return __builtin_bswap64(val);
|
||||||
|
#elif _WIN32
|
||||||
|
return _byteswap_uint64(val);
|
||||||
|
#else
|
||||||
|
return ((val & 0xFF00000000000000ULL) >> 56) |
|
||||||
|
((val & 0x00FF000000000000ULL) >> 40) |
|
||||||
|
((val & 0x0000FF0000000000ULL) >> 24) |
|
||||||
|
((val & 0x000000FF00000000ULL) >> 8) |
|
||||||
|
((val & 0x00000000FF000000ULL) << 8) |
|
||||||
|
((val & 0x0000000000FF0000ULL) << 24) |
|
||||||
|
((val & 0x000000000000FF00ULL) << 40) |
|
||||||
|
((val & 0x00000000000000FFULL) << 56);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||||
|
static inline int16_t SBig(int16_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 uint32_t SBig(uint32_t val) {return bswap32(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 int16_t SLittle(int16_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 uint32_t SLittle(uint32_t val) {return val;}
|
||||||
|
static inline int64_t SLittle(int64_t val) {return val;}
|
||||||
|
static inline uint64_t SLittle(uint64_t val) {return val;}
|
||||||
|
#else
|
||||||
|
static inline int16_t SLittle(int16_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 uint32_t SLittle(uint32_t val) {return bswap32(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 int16_t SBig(int16_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 uint32_t SBig(uint32_t val) {return val;}
|
||||||
|
static inline int64_t SBig(int64_t val) {return val;}
|
||||||
|
static inline uint64_t SBig(uint64_t val) {return val;}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // __NOD_UTIL_HPP__
|
@ -3,4 +3,9 @@
|
|||||||
namespace NOD
|
namespace NOD
|
||||||
{
|
{
|
||||||
|
|
||||||
|
DiscBase::DiscBase(std::unique_ptr<IDiscIO>&& dio)
|
||||||
|
: m_discIO(std::move(dio)), m_header(*m_discIO.get())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,17 @@
|
|||||||
|
#include "DiscGCN.hpp"
|
||||||
|
|
||||||
|
namespace NOD
|
||||||
|
{
|
||||||
|
|
||||||
|
DiscGCN::DiscGCN(std::unique_ptr<IDiscIO>&& dio)
|
||||||
|
: DiscBase(std::move(dio))
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DiscGCN::commit()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -5,25 +5,27 @@
|
|||||||
namespace NOD
|
namespace NOD
|
||||||
{
|
{
|
||||||
|
|
||||||
class DiscIOFILE : public IDiscIO
|
class DiscIOISO : public IDiscIO
|
||||||
{
|
{
|
||||||
std::string filepath;
|
std::string filepath;
|
||||||
public:
|
public:
|
||||||
DiscIOFILE(const std::string& fpin)
|
DiscIOISO(const std::string& fpin)
|
||||||
: filepath(fpin) {}
|
: filepath(fpin) {}
|
||||||
|
|
||||||
class FILEReadStream : public IReadStream
|
class ReadStream : public IReadStream
|
||||||
{
|
{
|
||||||
friend class DiscIOFILE;
|
friend class DiscIOISO;
|
||||||
FILE* fp;
|
FILE* fp;
|
||||||
FILEReadStream(FILE* fpin)
|
ReadStream(FILE* fpin)
|
||||||
: fp(fpin) {}
|
: fp(fpin) {}
|
||||||
~FILEReadStream() {fclose(fp);}
|
~ReadStream() {fclose(fp);}
|
||||||
public:
|
public:
|
||||||
size_t read(void* buf, size_t length)
|
size_t read(void* buf, size_t length)
|
||||||
{return fread(buf, 1, length, fp);}
|
{return fread(buf, 1, length, fp);}
|
||||||
|
void seek(size_t offset, int whence)
|
||||||
|
{fseek(fp, offset, whence);}
|
||||||
};
|
};
|
||||||
std::unique_ptr<IReadStream> beginReadStream(size_t offset)
|
std::unique_ptr<IReadStream> beginReadStream(size_t offset) const
|
||||||
{
|
{
|
||||||
FILE* fp = fopen(filepath.c_str(), "rb");
|
FILE* fp = fopen(filepath.c_str(), "rb");
|
||||||
if (!fp)
|
if (!fp)
|
||||||
@ -32,21 +34,21 @@ public:
|
|||||||
return std::unique_ptr<IReadStream>();
|
return std::unique_ptr<IReadStream>();
|
||||||
}
|
}
|
||||||
fseek(fp, offset, SEEK_SET);
|
fseek(fp, offset, SEEK_SET);
|
||||||
return std::unique_ptr<IReadStream>(new FILEReadStream(fp));
|
return std::unique_ptr<IReadStream>(new ReadStream(fp));
|
||||||
}
|
}
|
||||||
|
|
||||||
class FILEWriteStream : public IWriteStream
|
class WriteStream : public IWriteStream
|
||||||
{
|
{
|
||||||
friend class DiscIOFILE;
|
friend class DiscIOISO;
|
||||||
FILE* fp;
|
FILE* fp;
|
||||||
FILEWriteStream(FILE* fpin)
|
WriteStream(FILE* fpin)
|
||||||
: fp(fpin) {}
|
: fp(fpin) {}
|
||||||
~FILEWriteStream() {fclose(fp);}
|
~WriteStream() {fclose(fp);}
|
||||||
public:
|
public:
|
||||||
size_t write(void* buf, size_t length)
|
size_t write(void* buf, size_t length)
|
||||||
{return fwrite(buf, 1, length, fp);}
|
{return fwrite(buf, 1, length, fp);}
|
||||||
};
|
};
|
||||||
std::unique_ptr<IWriteStream> beginWriteStream(size_t offset)
|
std::unique_ptr<IWriteStream> beginWriteStream(size_t offset) const
|
||||||
{
|
{
|
||||||
FILE* fp = fopen(filepath.c_str(), "wb");
|
FILE* fp = fopen(filepath.c_str(), "wb");
|
||||||
if (!fp)
|
if (!fp)
|
||||||
@ -55,13 +57,13 @@ public:
|
|||||||
return std::unique_ptr<IWriteStream>();
|
return std::unique_ptr<IWriteStream>();
|
||||||
}
|
}
|
||||||
fseek(fp, offset, SEEK_SET);
|
fseek(fp, offset, SEEK_SET);
|
||||||
return std::unique_ptr<IWriteStream>(new FILEWriteStream(fp));
|
return std::unique_ptr<IWriteStream>(new WriteStream(fp));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<IDiscIO> NewDiscIOFILE(const char* path)
|
std::unique_ptr<IDiscIO> NewDiscIOISO(const char* path)
|
||||||
{
|
{
|
||||||
return std::unique_ptr<IDiscIO>(new DiscIOFILE(path));
|
return std::unique_ptr<IDiscIO>(new DiscIOISO(path));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -0,0 +1,70 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include "IDiscIO.hpp"
|
||||||
|
|
||||||
|
namespace NOD
|
||||||
|
{
|
||||||
|
|
||||||
|
class DiscIOWBFS : public IDiscIO
|
||||||
|
{
|
||||||
|
std::string filepath;
|
||||||
|
public:
|
||||||
|
DiscIOWBFS(const std::string& fpin)
|
||||||
|
: filepath(fpin) {}
|
||||||
|
|
||||||
|
class ReadStream : public IReadStream
|
||||||
|
{
|
||||||
|
friend class DiscIOWBFS;
|
||||||
|
FILE* fp;
|
||||||
|
ReadStream(FILE* fpin)
|
||||||
|
: fp(fpin) {}
|
||||||
|
~ReadStream() {fclose(fp);}
|
||||||
|
public:
|
||||||
|
size_t read(void* buf, size_t length)
|
||||||
|
{return fread(buf, 1, length, fp);}
|
||||||
|
void seek(size_t offset, int whence)
|
||||||
|
{fseek(fp, offset, whence);}
|
||||||
|
};
|
||||||
|
std::unique_ptr<IReadStream> beginReadStream(size_t offset) const
|
||||||
|
{
|
||||||
|
FILE* fp = fopen(filepath.c_str(), "rb");
|
||||||
|
if (!fp)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Unable to open '" + filepath + "' for reading");
|
||||||
|
return std::unique_ptr<IReadStream>();
|
||||||
|
}
|
||||||
|
fseek(fp, offset, SEEK_SET);
|
||||||
|
return std::unique_ptr<IReadStream>(new ReadStream(fp));
|
||||||
|
}
|
||||||
|
|
||||||
|
class WriteStream : public IWriteStream
|
||||||
|
{
|
||||||
|
friend class DiscIOWBFS;
|
||||||
|
FILE* fp;
|
||||||
|
WriteStream(FILE* fpin)
|
||||||
|
: fp(fpin) {}
|
||||||
|
~WriteStream() {fclose(fp);}
|
||||||
|
public:
|
||||||
|
size_t write(void* buf, size_t length)
|
||||||
|
{return fwrite(buf, 1, length, fp);}
|
||||||
|
};
|
||||||
|
std::unique_ptr<IWriteStream> beginWriteStream(size_t offset) const
|
||||||
|
{
|
||||||
|
FILE* fp = fopen(filepath.c_str(), "wb");
|
||||||
|
if (!fp)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Unable to open '" + filepath + "' for writing");
|
||||||
|
return std::unique_ptr<IWriteStream>();
|
||||||
|
}
|
||||||
|
fseek(fp, offset, SEEK_SET);
|
||||||
|
return std::unique_ptr<IWriteStream>(new WriteStream(fp));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<IDiscIO> NewDiscIOWBFS(const char* path)
|
||||||
|
{
|
||||||
|
return std::unique_ptr<IDiscIO>(new DiscIOWBFS(path));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
252
lib/DiscWii.cpp
252
lib/DiscWii.cpp
@ -1,7 +1,259 @@
|
|||||||
|
#include <stdio.h>
|
||||||
#include "DiscWii.hpp"
|
#include "DiscWii.hpp"
|
||||||
|
|
||||||
namespace NOD
|
namespace NOD
|
||||||
{
|
{
|
||||||
|
|
||||||
|
class PartitionWii : public DiscBase::IPartition
|
||||||
|
{
|
||||||
|
struct Ticket
|
||||||
|
{
|
||||||
|
uint32_t sigType;
|
||||||
|
char sig[256];
|
||||||
|
char padding[60];
|
||||||
|
char sigIssuer[64];
|
||||||
|
char ecdh[60];
|
||||||
|
char padding1[3];
|
||||||
|
unsigned char encKey[16];
|
||||||
|
char padding2;
|
||||||
|
char ticketId[8];
|
||||||
|
char consoleId[4];
|
||||||
|
char titleId[8];
|
||||||
|
char padding3[2];
|
||||||
|
uint16_t ticketVersion;
|
||||||
|
uint32_t permittedTitlesMask;
|
||||||
|
uint32_t permitMask;
|
||||||
|
char titleExportAllowed;
|
||||||
|
char commonKeyIdx;
|
||||||
|
char padding4[48];
|
||||||
|
char contentAccessPermissions[64];
|
||||||
|
char padding5[2];
|
||||||
|
struct TimeLimit
|
||||||
|
{
|
||||||
|
uint32_t enableTimeLimit;
|
||||||
|
uint32_t timeLimit;
|
||||||
|
} timeLimits[8];
|
||||||
|
|
||||||
|
void read(IDiscIO::IReadStream& s)
|
||||||
|
{
|
||||||
|
s.read(this, 676);
|
||||||
|
sigType = SBig(sigType);
|
||||||
|
ticketVersion = SBig(ticketVersion);
|
||||||
|
permittedTitlesMask = SBig(permittedTitlesMask);
|
||||||
|
permitMask = SBig(permitMask);
|
||||||
|
for (size_t t=0 ; t<8 ; ++t)
|
||||||
|
{
|
||||||
|
timeLimits[t].enableTimeLimit = SBig(timeLimits[t].enableTimeLimit);
|
||||||
|
timeLimits[t].timeLimit = SBig(timeLimits[t].timeLimit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} m_ticket;
|
||||||
|
|
||||||
|
struct TMD
|
||||||
|
{
|
||||||
|
uint32_t sigType;
|
||||||
|
char sig[256];
|
||||||
|
char padding[60];
|
||||||
|
char sigIssuer[64];
|
||||||
|
char version;
|
||||||
|
char caCrlVersion;
|
||||||
|
char signerCrlVersion;
|
||||||
|
char padding1;
|
||||||
|
uint32_t iosIdMajor;
|
||||||
|
uint32_t iosIdMinor;
|
||||||
|
uint32_t titleIdMajor;
|
||||||
|
uint32_t titleIdMinor;
|
||||||
|
uint32_t titleType;
|
||||||
|
uint16_t groupId;
|
||||||
|
char padding2[62];
|
||||||
|
uint32_t accessFlags;
|
||||||
|
uint16_t titleVersion;
|
||||||
|
uint16_t numContents;
|
||||||
|
uint16_t bootIdx;
|
||||||
|
uint16_t padding3;
|
||||||
|
|
||||||
|
struct Content
|
||||||
|
{
|
||||||
|
uint32_t id;
|
||||||
|
uint16_t index;
|
||||||
|
uint16_t type;
|
||||||
|
uint64_t size;
|
||||||
|
char hash[20];
|
||||||
|
|
||||||
|
void read(IDiscIO::IReadStream& s)
|
||||||
|
{
|
||||||
|
s.read(this, 36);
|
||||||
|
id = SBig(id);
|
||||||
|
index = SBig(index);
|
||||||
|
type = SBig(type);
|
||||||
|
size = SBig(size);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
std::vector<Content> contents;
|
||||||
|
|
||||||
|
void read(IDiscIO::IReadStream& s)
|
||||||
|
{
|
||||||
|
s.read(this, 484);
|
||||||
|
sigType = SBig(sigType);
|
||||||
|
iosIdMajor = SBig(iosIdMajor);
|
||||||
|
iosIdMinor = SBig(iosIdMinor);
|
||||||
|
titleIdMajor = SBig(titleIdMajor);
|
||||||
|
titleIdMinor = SBig(titleIdMinor);
|
||||||
|
titleType = SBig(titleType);
|
||||||
|
groupId = SBig(groupId);
|
||||||
|
accessFlags = SBig(accessFlags);
|
||||||
|
titleVersion = SBig(titleVersion);
|
||||||
|
numContents = SBig(numContents);
|
||||||
|
bootIdx = SBig(bootIdx);
|
||||||
|
for (size_t c=0 ; c<numContents ; ++c)
|
||||||
|
{
|
||||||
|
contents.emplace_back();
|
||||||
|
contents.back().read(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} m_tmd;
|
||||||
|
|
||||||
|
struct Certificate
|
||||||
|
{
|
||||||
|
uint32_t sigType;
|
||||||
|
char sig[512];
|
||||||
|
char issuer[64];
|
||||||
|
uint32_t keyType;
|
||||||
|
char subject[64];
|
||||||
|
char key[512];
|
||||||
|
uint32_t modulus;
|
||||||
|
uint32_t pubExp;
|
||||||
|
|
||||||
|
void read(IDiscIO::IReadStream& s)
|
||||||
|
{
|
||||||
|
s.read(&sigType, 4);
|
||||||
|
sigType = SBig(sigType);
|
||||||
|
if (sigType == 0x00010000)
|
||||||
|
s.read(sig, 512);
|
||||||
|
else if (sigType == 0x00010001)
|
||||||
|
s.read(sig, 256);
|
||||||
|
else if (sigType == 0x00010002)
|
||||||
|
s.read(sig, 64);
|
||||||
|
s.seek(60, SEEK_CUR);
|
||||||
|
|
||||||
|
s.read(issuer, 64);
|
||||||
|
s.read(&keyType, 4);
|
||||||
|
s.read(subject, 64);
|
||||||
|
keyType = SBig(keyType);
|
||||||
|
if (keyType == 0x00000000)
|
||||||
|
s.read(key, 512);
|
||||||
|
else if (keyType == 0x00000001)
|
||||||
|
s.read(key, 256);
|
||||||
|
|
||||||
|
s.read(&modulus, 8);
|
||||||
|
modulus = SBig(modulus);
|
||||||
|
pubExp = SBig(pubExp);
|
||||||
|
|
||||||
|
s.seek(52, SEEK_CUR);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Certificate m_caCert;
|
||||||
|
Certificate m_tmdCert;
|
||||||
|
Certificate m_ticketCert;
|
||||||
|
|
||||||
|
public:
|
||||||
|
PartitionWii(const DiscWii& parent, Kind kind, size_t offset)
|
||||||
|
: IPartition(parent, kind, offset)
|
||||||
|
{
|
||||||
|
std::unique_ptr<IDiscIO::IReadStream> s = parent.getDiscIO().beginReadStream(offset);
|
||||||
|
m_ticket.read(*s.get());
|
||||||
|
|
||||||
|
uint32_t tmdSize;
|
||||||
|
s->read(&tmdSize, 4);
|
||||||
|
tmdSize = SBig(tmdSize);
|
||||||
|
uint32_t tmdOff;
|
||||||
|
s->read(&tmdOff, 4);
|
||||||
|
tmdOff = SBig(tmdOff) << 2;
|
||||||
|
|
||||||
|
uint32_t certChainSize;
|
||||||
|
s->read(&certChainSize, 4);
|
||||||
|
certChainSize = SBig(certChainSize);
|
||||||
|
uint32_t certChainOff;
|
||||||
|
s->read(&certChainOff, 4);
|
||||||
|
certChainOff = SBig(certChainOff) << 2;
|
||||||
|
|
||||||
|
uint32_t globalHashTableOff;
|
||||||
|
s->read(&globalHashTableOff, 4);
|
||||||
|
globalHashTableOff = SBig(globalHashTableOff) << 2;
|
||||||
|
|
||||||
|
uint32_t dataOff;
|
||||||
|
s->read(&dataOff, 4);
|
||||||
|
dataOff = SBig(dataOff) << 2;
|
||||||
|
uint32_t dataSize;
|
||||||
|
s->read(&dataSize, 4);
|
||||||
|
dataSize = SBig(dataSize) << 2;
|
||||||
|
|
||||||
|
s->seek(offset + tmdOff);
|
||||||
|
m_tmd.read(*s.get());
|
||||||
|
|
||||||
|
s->seek(offset + certChainOff);
|
||||||
|
m_caCert.read(*s.get());
|
||||||
|
m_tmdCert.read(*s.get());
|
||||||
|
m_ticketCert.read(*s.get());
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
DiscWii::DiscWii(std::unique_ptr<IDiscIO>&& dio)
|
||||||
|
: DiscBase(std::move(dio))
|
||||||
|
{
|
||||||
|
/* Read partition info */
|
||||||
|
struct PartInfo {
|
||||||
|
uint32_t partCount;
|
||||||
|
uint32_t partInfoOff;
|
||||||
|
struct Part
|
||||||
|
{
|
||||||
|
uint32_t partDataOff;
|
||||||
|
enum Type : uint32_t
|
||||||
|
{
|
||||||
|
PART_DATA = 0,
|
||||||
|
PART_UPDATE = 1,
|
||||||
|
PART_CHANNEL = 2
|
||||||
|
} partType;
|
||||||
|
} parts[4];
|
||||||
|
PartInfo(IDiscIO& dio)
|
||||||
|
{
|
||||||
|
std::unique_ptr<IDiscIO::IReadStream> s = dio.beginReadStream(0x40000);
|
||||||
|
s->read(this, 32);
|
||||||
|
partCount = SBig(partCount);
|
||||||
|
partInfoOff = SBig(partInfoOff);
|
||||||
|
|
||||||
|
s->seek(partInfoOff << 2);
|
||||||
|
for (uint32_t p=0 ; p<partCount && p<4 ; ++p)
|
||||||
|
{
|
||||||
|
s->read(&parts[p], 8);
|
||||||
|
parts[p].partDataOff = SBig(parts[p].partDataOff);
|
||||||
|
parts[p].partType = (Part::Type)SBig(parts[p].partType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} partInfo(*m_discIO.get());
|
||||||
|
|
||||||
|
/* Iterate for data partition */
|
||||||
|
m_partitions.reserve(partInfo.partCount);
|
||||||
|
for (uint32_t p=0 ; p<partInfo.partCount && p<4 ; ++p)
|
||||||
|
{
|
||||||
|
PartInfo::Part& part = partInfo.parts[p];
|
||||||
|
IPartition::Kind kind;
|
||||||
|
if (part.partType == PartInfo::Part::PART_DATA)
|
||||||
|
kind = IPartition::PART_DATA;
|
||||||
|
else if (part.partType == PartInfo::Part::PART_UPDATE)
|
||||||
|
kind = IPartition::PART_UPDATE;
|
||||||
|
else if (part.partType == PartInfo::Part::PART_CHANNEL)
|
||||||
|
kind = IPartition::PART_CHANNEL;
|
||||||
|
else
|
||||||
|
throw std::runtime_error("Invalid partition type");
|
||||||
|
m_partitions.emplace_back(new PartitionWii(*this, kind, part.partDataOff << 2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DiscWii::commit()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
21
lib/FileIOFILE.cpp
Normal file
21
lib/FileIOFILE.cpp
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#include <sys/stat.h>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include "IFileIO.hpp"
|
||||||
|
|
||||||
|
namespace NOD
|
||||||
|
{
|
||||||
|
|
||||||
|
class FileIOFILE : public IFileIO
|
||||||
|
{
|
||||||
|
const char* filepath;
|
||||||
|
public:
|
||||||
|
FileIOFILE(const char* path)
|
||||||
|
: filepath(path)
|
||||||
|
{
|
||||||
|
struct stat theStat;
|
||||||
|
if (stat(path, &theStat))
|
||||||
|
throw std::runtime_error("unable to ");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
10
lib/FileIOMEM.cpp
Normal file
10
lib/FileIOMEM.cpp
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#include "IFileIO.hpp"
|
||||||
|
|
||||||
|
namespace NOD
|
||||||
|
{
|
||||||
|
|
||||||
|
class FileIOMEM : public IFileIO
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
67
lib/NODLib.cpp
Normal file
67
lib/NODLib.cpp
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include "NODLib.hpp"
|
||||||
|
#include "DiscBase.hpp"
|
||||||
|
|
||||||
|
namespace NOD
|
||||||
|
{
|
||||||
|
std::unique_ptr<IDiscIO> NewDiscIOISO(const char* path);
|
||||||
|
std::unique_ptr<IDiscIO> NewDiscIOWBFS(const char* path);
|
||||||
|
|
||||||
|
std::unique_ptr<DiscBase> OpenDiscFromImage(const char* path, bool& isWii)
|
||||||
|
{
|
||||||
|
/* Temporary file handle to determine image type */
|
||||||
|
FILE* fp = fopen(path, "rb");
|
||||||
|
if (!fp)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Unable to open '" + std::string(path) + "'");
|
||||||
|
return std::unique_ptr<DiscBase>();
|
||||||
|
}
|
||||||
|
|
||||||
|
isWii = false;
|
||||||
|
std::unique_ptr<IDiscIO> discIO;
|
||||||
|
uint32_t magic;
|
||||||
|
fread(&magic, 1, 4, fp);
|
||||||
|
if (magic == NOD::SBig((uint32_t)'WBFS'))
|
||||||
|
{
|
||||||
|
fclose(fp);
|
||||||
|
discIO = NewDiscIOWBFS(path);
|
||||||
|
isWii = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fseek(fp, 0x18, SEEK_SET);
|
||||||
|
fread(&magic, 1, 4, fp);
|
||||||
|
magic = NOD::SBig(magic);
|
||||||
|
if (magic == 0x5D1C9EA3)
|
||||||
|
{
|
||||||
|
fclose(fp);
|
||||||
|
discIO = NewDiscIOISO(path);
|
||||||
|
isWii = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fread(&magic, 1, 4, fp);
|
||||||
|
magic = NOD::SBig(magic);
|
||||||
|
if (magic == 0xC2339F3D)
|
||||||
|
{
|
||||||
|
fclose(fp);
|
||||||
|
discIO = NewDiscIOISO(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!discIO)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("'" + std::string(path) + "' is not a valid image");
|
||||||
|
return std::unique_ptr<DiscBase>();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isWii)
|
||||||
|
return std::unique_ptr<DiscBase>(new DiscWii(std::move(discIO)));
|
||||||
|
|
||||||
|
return std::unique_ptr<DiscBase>(new DiscGCN(std::move(discIO)));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
8
main.cpp
8
main.cpp
@ -1,11 +1,17 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
#include "NODLib.hpp"
|
#include "NODLib.hpp"
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
if (argc < 2)
|
if (argc < 2)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Usage: nodlib <image-in>\n");
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
std::unique_ptr<NOD::DiscBase> disc = NOD::OpenDiscFromImage(argv[1]);
|
bool isWii;
|
||||||
|
std::unique_ptr<NOD::DiscBase> disc = NOD::OpenDiscFromImage(argv[1], isWii);
|
||||||
if (!disc)
|
if (!disc)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user