nod/include/NOD/DiscBase.hpp

262 lines
8.9 KiB
C++
Raw Normal View History

2015-06-26 19:30:03 +00:00
#ifndef __NOD_DISC_BASE__
#define __NOD_DISC_BASE__
2015-06-28 05:43:53 +00:00
#include <vector>
2015-06-26 19:30:03 +00:00
#include <memory>
#include <string>
2015-06-30 00:07:46 +00:00
#include <stdio.h>
#include <stdint.h>
2015-06-28 05:43:53 +00:00
#include "Util.hpp"
2015-06-26 19:30:03 +00:00
#include "IDiscIO.hpp"
#include "IFileIO.hpp"
namespace NOD
{
2015-10-16 21:52:57 +00:00
struct ExtractionContext;
2015-06-26 19:30:03 +00:00
class DiscBase
{
2015-06-26 20:01:15 +00:00
public:
virtual ~DiscBase() {}
2015-06-28 05:43:53 +00:00
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);
}
};
2015-06-30 00:07:46 +00:00
class FSTNode
{
uint32_t typeAndNameOffset;
uint32_t offset;
uint32_t length;
public:
2015-07-22 19:01:28 +00:00
inline bool isDir() const {return ((SBig(typeAndNameOffset) >> 24) != 0);}
2015-06-30 00:07:46 +00:00
inline uint32_t getNameOffset() const {return SBig(typeAndNameOffset) & 0xffffff;}
inline uint32_t getOffset() const {return SBig(offset);}
inline uint32_t getLength() const {return SBig(length);}
};
2015-06-28 05:43:53 +00:00
class IPartition
2015-06-26 19:30:03 +00:00
{
2015-06-26 20:01:15 +00:00
public:
virtual ~IPartition() {}
2015-11-21 01:15:33 +00:00
enum class Kind : uint32_t
2015-06-26 19:30:03 +00:00
{
2015-11-21 01:15:33 +00:00
Data,
Update,
Channel
2015-06-26 19:30:03 +00:00
};
2015-07-03 03:49:31 +00:00
struct DOLHeader
{
uint32_t textOff[7];
uint32_t dataOff[11];
uint32_t textStarts[7];
uint32_t dataStarts[11];
uint32_t textSizes[7];
uint32_t dataSizes[11];
uint32_t bssStart;
uint32_t bssSize;
uint32_t entryPoint;
};
2015-06-28 05:43:53 +00:00
class Node
2015-06-26 19:30:03 +00:00
{
2015-06-28 05:43:53 +00:00
public:
2015-11-21 01:15:33 +00:00
enum class Kind
2015-06-28 05:43:53 +00:00
{
2015-11-21 01:15:33 +00:00
File,
Directory
2015-06-28 05:43:53 +00:00
};
private:
2015-06-30 00:07:46 +00:00
friend class IPartition;
2015-06-28 05:43:53 +00:00
const IPartition& m_parent;
Kind m_kind;
uint64_t m_discOffset;
uint64_t m_discLength;
2015-06-30 00:07:46 +00:00
std::string m_name;
2015-06-30 06:46:19 +00:00
std::vector<Node>::iterator m_childrenBegin;
std::vector<Node>::iterator m_childrenEnd;
2015-06-28 05:43:53 +00:00
2015-06-26 20:01:15 +00:00
public:
2015-06-30 00:07:46 +00:00
Node(const IPartition& parent, const FSTNode& node, const char* name)
: m_parent(parent),
2015-11-21 01:15:33 +00:00
m_kind(node.isDir() ? Kind::Directory : Kind::File),
m_discOffset(parent.normalizeOffset(node.getOffset())),
2015-06-30 00:07:46 +00:00
m_discLength(node.getLength()),
m_name(name) {}
2015-06-28 05:43:53 +00:00
inline Kind getKind() const {return m_kind;}
2015-06-30 00:07:46 +00:00
inline const std::string& getName() const {return m_name;}
inline uint64_t size() const {return m_discLength;}
2015-07-10 03:11:30 +00:00
std::unique_ptr<IPartReadStream> beginReadStream(uint64_t offset=0) const
2015-06-29 05:35:25 +00:00
{
2015-11-21 01:15:33 +00:00
if (m_kind != Kind::File)
2015-06-29 05:35:25 +00:00
{
2015-07-26 02:44:44 +00:00
LogModule.report(LogVisor::Error, "unable to stream a non-file %s", m_name.c_str());
2015-06-29 05:35:25 +00:00
return std::unique_ptr<IPartReadStream>();
}
2015-07-10 03:11:30 +00:00
return m_parent.beginReadStream(m_discOffset + offset);
2015-06-29 05:35:25 +00:00
}
std::unique_ptr<uint8_t[]> getBuf() const
{
2015-11-21 01:15:33 +00:00
if (m_kind != Kind::File)
{
2015-07-26 02:44:44 +00:00
LogModule.report(LogVisor::Error, "unable to buffer a non-file %s", m_name.c_str());
return std::unique_ptr<uint8_t[]>();
}
uint8_t* buf = new uint8_t[m_discLength];
beginReadStream()->read(buf, m_discLength);
return std::unique_ptr<uint8_t[]>(buf);
}
2015-06-30 06:46:19 +00:00
inline std::vector<Node>::iterator rawBegin() const {return m_childrenBegin;}
inline std::vector<Node>::iterator rawEnd() const {return m_childrenEnd;}
2015-06-30 00:07:46 +00:00
2015-06-30 06:46:19 +00:00
class DirectoryIterator : std::iterator<std::forward_iterator_tag, Node>
2015-06-30 00:07:46 +00:00
{
friend class Node;
2015-06-30 06:46:19 +00:00
std::vector<Node>::iterator m_it;
DirectoryIterator(const std::vector<Node>::iterator& it)
: m_it(it) {}
2015-06-30 00:07:46 +00:00
public:
inline bool operator!=(const DirectoryIterator& other) {return m_it != other.m_it;}
inline bool operator==(const DirectoryIterator& other) {return m_it == other.m_it;}
2015-06-30 00:07:46 +00:00
inline DirectoryIterator& operator++()
{
2015-11-21 01:15:33 +00:00
if (m_it->m_kind == Kind::Directory)
2015-06-30 00:07:46 +00:00
m_it = m_it->rawEnd();
else
++m_it;
return *this;
}
2015-06-30 06:46:19 +00:00
inline Node& operator*() {return *m_it;}
inline Node* operator->() {return &*m_it;}
2015-06-30 00:07:46 +00:00
};
2015-06-30 06:46:19 +00:00
inline DirectoryIterator begin() const {return DirectoryIterator(m_childrenBegin);}
inline DirectoryIterator end() const {return DirectoryIterator(m_childrenEnd);}
inline DirectoryIterator find(const std::string& name) const
{
2015-11-21 01:15:33 +00:00
if (m_kind == Kind::Directory)
{
DirectoryIterator it=begin();
for (; it != end() ; ++it)
{
if (!it->getName().compare(name))
return it;
}
return it;
}
return end();
}
2015-06-30 06:46:19 +00:00
2015-09-28 01:55:59 +00:00
bool extractToDirectory(const SystemString& basePath, const ExtractionContext& ctx) const;
2015-06-26 19:30:03 +00:00
};
2015-06-28 05:43:53 +00:00
protected:
uint64_t m_dolOff;
uint64_t m_fstOff;
uint64_t m_fstSz;
uint64_t m_apploaderSz;
2015-06-30 00:07:46 +00:00
std::vector<Node> m_nodes;
void parseFST(IPartReadStream& s);
2015-06-29 05:35:25 +00:00
2015-07-10 03:11:30 +00:00
uint64_t m_dolSz;
void parseDOL(IPartReadStream& s);
2015-06-28 05:43:53 +00:00
const DiscBase& m_parent;
2015-06-26 19:30:03 +00:00
Kind m_kind;
uint64_t m_offset;
2015-06-26 20:01:15 +00:00
public:
IPartition(const DiscBase& parent, Kind kind, uint64_t offset)
2015-06-28 05:43:53 +00:00
: m_parent(parent), m_kind(kind), m_offset(offset) {}
virtual uint64_t normalizeOffset(uint64_t anOffset) const {return anOffset;}
2015-06-28 05:43:53 +00:00
inline Kind getKind() const {return m_kind;}
virtual std::unique_ptr<IPartReadStream> beginReadStream(uint64_t offset=0) const=0;
2015-07-10 03:11:30 +00:00
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);}
2015-06-30 00:07:46 +00:00
inline const Node& getFSTRoot() const {return m_nodes[0];}
2015-06-30 06:46:19 +00:00
inline Node& getFSTRoot() {return m_nodes[0];}
2015-09-28 01:55:59 +00:00
bool extractToDirectory(const SystemString& path, const ExtractionContext& ctx);
2015-07-10 03:11:30 +00:00
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;
}
2015-06-26 19:30:03 +00:00
};
2015-06-28 05:43:53 +00:00
protected:
std::unique_ptr<IDiscIO> m_discIO;
Header m_header;
std::vector<std::unique_ptr<IPartition>> m_partitions;
public:
2015-07-03 22:40:34 +00:00
DiscBase(std::unique_ptr<IDiscIO>&& dio)
2015-08-05 21:45:25 +00:00
: m_discIO(std::move(dio)), m_header(*m_discIO) {}
2015-07-03 22:40:34 +00:00
2015-06-28 05:43:53 +00:00
virtual bool commit()=0;
2015-06-30 00:07:46 +00:00
inline const Header& getHeader() const {return m_header;}
2015-08-05 21:45:25 +00:00
inline const IDiscIO& getDiscIO() const {return *m_discIO;}
inline IPartition* getDataPartition()
2015-06-30 00:07:46 +00:00
{
for (const std::unique_ptr<IPartition>& part : m_partitions)
2015-11-21 01:15:33 +00:00
if (part->getKind() == IPartition::Kind::Data)
2015-06-30 00:07:46 +00:00
return part.get();
return nullptr;
}
inline IPartition* getUpdatePartition()
2015-06-30 00:07:46 +00:00
{
for (const std::unique_ptr<IPartition>& part : m_partitions)
2015-11-21 01:15:33 +00:00
if (part->getKind() == IPartition::Kind::Update)
2015-06-30 00:07:46 +00:00
return part.get();
return nullptr;
}
2015-09-28 01:55:59 +00:00
inline void extractToDirectory(const SystemString& path, const ExtractionContext& ctx)
2015-06-30 06:46:19 +00:00
{
for (std::unique_ptr<IPartition>& part : m_partitions)
2015-09-28 01:55:59 +00:00
part->extractToDirectory(path, ctx);
2015-06-30 06:46:19 +00:00
}
2015-06-26 19:30:03 +00:00
};
using Partition = DiscBase::IPartition;
using Node = Partition::Node;
2015-06-26 19:30:03 +00:00
}
#endif // __NOD_DISC_BASE__