mirror of https://github.com/AxioDL/nod.git
working file extractor; removed hard-coded paths
This commit is contained in:
parent
293b7c0ce6
commit
a1b2a262bf
|
@ -2,34 +2,53 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "NODLib.hpp"
|
#include "NODLib.hpp"
|
||||||
|
|
||||||
|
static void printHelp()
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Usage:\n"
|
||||||
|
" nodlib extract [-f] <image-in> [<dir-out>]\n"
|
||||||
|
" nodlib make <dir-in> [<image-out>]\n");
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
if (argc < 2)
|
if (argc < 3)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Usage: nodlib <image-in>\n");
|
printHelp();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<NOD::DiscBase> disc = NOD::OpenDiscFromImage(argv[1]);
|
const char* inDir = nullptr;
|
||||||
if (!disc)
|
const char* outDir = ".";
|
||||||
return -1;
|
bool force = false;
|
||||||
|
for (int a=2 ; a<argc ; ++a)
|
||||||
disc->extractToDirectory("/home/jacko/Desktop/TrilogyDump2");
|
|
||||||
|
|
||||||
const NOD::DiscBase::IPartition* dataPart = disc->getDataPartition();
|
|
||||||
if (dataPart)
|
|
||||||
{
|
{
|
||||||
for (const NOD::DiscBase::IPartition::Node& node : dataPart->getFSTRoot())
|
if (argv[a][0] == '-' && argv[a][1] == 'f')
|
||||||
{
|
force = true;
|
||||||
if (node.getKind() == NOD::DiscBase::IPartition::Node::NODE_FILE)
|
else if (!inDir)
|
||||||
printf("FILE: %s\n", node.getName().c_str());
|
inDir = argv[a];
|
||||||
else if (node.getKind() == NOD::DiscBase::IPartition::Node::NODE_DIRECTORY)
|
else
|
||||||
{
|
outDir = argv[a];
|
||||||
printf("DIR: %s\n", node.getName().c_str());
|
}
|
||||||
for (const NOD::DiscBase::IPartition::Node& subnode : node)
|
|
||||||
printf("SUBFILE: %s\n", subnode.getName().c_str());
|
if (!strcasecmp(argv[1], "extract"))
|
||||||
}
|
{
|
||||||
}
|
std::unique_ptr<NOD::DiscBase> disc = NOD::OpenDiscFromImage(inDir);
|
||||||
|
if (!disc)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
NOD::DiscBase::IPartition* dataPart = disc->getDataPartition();
|
||||||
|
if (!dataPart)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
dataPart->extractToDirectory(outDir, force);
|
||||||
|
}
|
||||||
|
else if (!strcasecmp(argv[1], "make"))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printHelp();
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
#include "Util.hpp"
|
#include "Util.hpp"
|
||||||
#include "IDiscIO.hpp"
|
#include "IDiscIO.hpp"
|
||||||
#include "IFileIO.hpp"
|
#include "IFileIO.hpp"
|
||||||
|
@ -71,8 +72,8 @@ public:
|
||||||
Kind m_kind;
|
Kind m_kind;
|
||||||
|
|
||||||
std::unique_ptr<IFileIO> m_hddFile;
|
std::unique_ptr<IFileIO> m_hddFile;
|
||||||
size_t m_discOffset;
|
uint64_t m_discOffset;
|
||||||
size_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;
|
||||||
|
@ -82,7 +83,7 @@ public:
|
||||||
Node(const IPartition& parent, const FSTNode& node, const char* name)
|
Node(const IPartition& parent, const FSTNode& node, const char* name)
|
||||||
: m_parent(parent),
|
: m_parent(parent),
|
||||||
m_kind(node.isDir() ? NODE_DIRECTORY : NODE_FILE),
|
m_kind(node.isDir() ? NODE_DIRECTORY : NODE_FILE),
|
||||||
m_discOffset(node.getOffset()),
|
m_discOffset(parent.normalizeOffset(node.getOffset())),
|
||||||
m_discLength(node.getLength()),
|
m_discLength(node.getLength()),
|
||||||
m_name(name) {}
|
m_name(name) {}
|
||||||
inline Kind getKind() const {return m_kind;}
|
inline Kind getKind() const {return m_kind;}
|
||||||
|
@ -123,25 +124,31 @@ public:
|
||||||
void extractToDirectory(const std::string& basePath, bool force=false);
|
void extractToDirectory(const std::string& basePath, bool force=false);
|
||||||
};
|
};
|
||||||
protected:
|
protected:
|
||||||
uint32_t m_dolOff;
|
uint64_t m_dolOff;
|
||||||
uint32_t m_fstOff;
|
uint64_t m_fstOff;
|
||||||
uint32_t m_fstSz;
|
uint64_t m_fstSz;
|
||||||
uint32_t m_apploaderOff;
|
uint64_t m_apploaderSz;
|
||||||
std::vector<Node> m_nodes;
|
std::vector<Node> m_nodes;
|
||||||
void parseFST(IPartReadStream& s);
|
void parseFST(IPartReadStream& s);
|
||||||
|
|
||||||
const DiscBase& m_parent;
|
const DiscBase& m_parent;
|
||||||
Kind m_kind;
|
Kind m_kind;
|
||||||
size_t m_offset;
|
uint64_t m_offset;
|
||||||
public:
|
public:
|
||||||
IPartition(const DiscBase& parent, Kind kind, size_t offset)
|
IPartition(const DiscBase& parent, Kind kind, uint64_t offset)
|
||||||
: m_parent(parent), m_kind(kind), m_offset(offset) {}
|
: m_parent(parent), m_kind(kind), m_offset(offset) {}
|
||||||
|
virtual uint64_t normalizeOffset(uint64_t anOffset) const {return anOffset;}
|
||||||
inline Kind getKind() const {return m_kind;}
|
inline Kind getKind() const {return m_kind;}
|
||||||
virtual std::unique_ptr<IPartReadStream> beginReadStream(size_t offset=0) const=0;
|
virtual std::unique_ptr<IPartReadStream> beginReadStream(uint64_t offset=0) const=0;
|
||||||
inline const Node& getFSTRoot() const {return m_nodes[0];}
|
inline const Node& getFSTRoot() const {return m_nodes[0];}
|
||||||
inline Node& getFSTRoot() {return m_nodes[0];}
|
inline Node& getFSTRoot() {return m_nodes[0];}
|
||||||
inline void extractToDirectory(const std::string& path, bool force=false)
|
std::string pathOfNode(const Node& node);
|
||||||
{m_nodes[0].extractToDirectory(path, force);}
|
void extractToDirectory(const std::string& path, bool force=false);
|
||||||
|
private:
|
||||||
|
bool _recursivePathOfNode(const std::string& basePath,
|
||||||
|
const Node& refNode,
|
||||||
|
const Node& curNode,
|
||||||
|
std::string& result);
|
||||||
};
|
};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -153,14 +160,14 @@ public:
|
||||||
virtual bool commit()=0;
|
virtual bool commit()=0;
|
||||||
inline const Header& getHeader() const {return m_header;}
|
inline const Header& getHeader() const {return m_header;}
|
||||||
inline const IDiscIO& getDiscIO() const {return *m_discIO.get();}
|
inline const IDiscIO& getDiscIO() const {return *m_discIO.get();}
|
||||||
inline const IPartition* getDataPartition() const
|
inline IPartition* getDataPartition()
|
||||||
{
|
{
|
||||||
for (const std::unique_ptr<IPartition>& part : m_partitions)
|
for (const std::unique_ptr<IPartition>& part : m_partitions)
|
||||||
if (part->getKind() == IPartition::PART_DATA)
|
if (part->getKind() == IPartition::PART_DATA)
|
||||||
return part.get();
|
return part.get();
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
inline const IPartition* getUpdatePartition() const
|
inline IPartition* getUpdatePartition()
|
||||||
{
|
{
|
||||||
for (const std::unique_ptr<IPartition>& part : m_partitions)
|
for (const std::unique_ptr<IPartition>& part : m_partitions)
|
||||||
if (part->getKind() == IPartition::PART_UPDATE)
|
if (part->getKind() == IPartition::PART_UPDATE)
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
namespace NOD
|
namespace NOD
|
||||||
{
|
{
|
||||||
|
@ -15,27 +16,27 @@ public:
|
||||||
|
|
||||||
struct IReadStream
|
struct IReadStream
|
||||||
{
|
{
|
||||||
virtual size_t read(void* buf, size_t length)=0;
|
virtual uint64_t read(void* buf, uint64_t length)=0;
|
||||||
virtual void seek(size_t offset, int whence=SEEK_SET)=0;
|
virtual void seek(int64_t offset, int whence=SEEK_SET)=0;
|
||||||
};
|
};
|
||||||
virtual std::unique_ptr<IReadStream> beginReadStream(size_t offset=0) const=0;
|
virtual std::unique_ptr<IReadStream> beginReadStream(uint64_t offset=0) const=0;
|
||||||
|
|
||||||
struct IWriteStream
|
struct IWriteStream
|
||||||
{
|
{
|
||||||
virtual size_t write(void* buf, size_t length)=0;
|
virtual uint64_t write(void* buf, uint64_t length)=0;
|
||||||
};
|
};
|
||||||
virtual std::unique_ptr<IWriteStream> beginWriteStream(size_t offset=0) const=0;
|
virtual std::unique_ptr<IWriteStream> beginWriteStream(uint64_t offset=0) const=0;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct IPartReadStream
|
struct IPartReadStream
|
||||||
{
|
{
|
||||||
virtual void seek(size_t offset, int whence=SEEK_SET)=0;
|
virtual void seek(int64_t offset, int whence=SEEK_SET)=0;
|
||||||
virtual size_t read(void* buf, size_t length)=0;
|
virtual uint64_t read(void* buf, uint64_t length)=0;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct IPartWriteStream
|
struct IPartWriteStream
|
||||||
{
|
{
|
||||||
virtual size_t write(void* buf, size_t length)=0;
|
virtual uint64_t write(void* buf, uint64_t length)=0;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,25 +12,27 @@ class IFileIO
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~IFileIO() {}
|
virtual ~IFileIO() {}
|
||||||
virtual size_t size()=0;
|
virtual uint64_t size()=0;
|
||||||
|
|
||||||
struct IWriteStream
|
struct IWriteStream
|
||||||
{
|
{
|
||||||
virtual ~IWriteStream() {}
|
virtual ~IWriteStream() {}
|
||||||
virtual size_t copyFromDisc(struct IPartReadStream& discio, size_t length)=0;
|
virtual uint64_t write(void* buf, uint64_t length)=0;
|
||||||
|
virtual uint64_t copyFromDisc(struct IPartReadStream& discio, uint64_t length)=0;
|
||||||
};
|
};
|
||||||
virtual std::unique_ptr<IWriteStream> beginWriteStream() const=0;
|
virtual std::unique_ptr<IWriteStream> beginWriteStream() const=0;
|
||||||
|
|
||||||
struct IReadStream
|
struct IReadStream
|
||||||
{
|
{
|
||||||
virtual ~IReadStream() {}
|
virtual ~IReadStream() {}
|
||||||
virtual size_t copyToDisc(struct IPartWriteStream& discio, size_t length)=0;
|
virtual uint64_t read(void* buf, 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;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<IFileIO> NewFileIO(const std::string& path);
|
std::unique_ptr<IFileIO> NewFileIO(const std::string& path);
|
||||||
std::unique_ptr<IFileIO> NewMemIO(void* buf, size_t size);
|
std::unique_ptr<IFileIO> NewMemIO(void* buf, uint64_t size);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,8 +11,8 @@ namespace NOD
|
||||||
class IAES
|
class IAES
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual void encrypt(uint8_t* iv, const uint8_t* inbuf, uint8_t* outbuf, size_t len)=0;
|
virtual void encrypt(uint8_t* iv, const uint8_t* inbuf, uint8_t* outbuf, uint64_t len)=0;
|
||||||
virtual void decrypt(uint8_t* iv, const uint8_t* inbuf, uint8_t* outbuf, size_t len)=0;
|
virtual void decrypt(uint8_t* iv, const uint8_t* inbuf, uint8_t* outbuf, uint64_t len)=0;
|
||||||
virtual void setKey(const uint8_t* key)=0;
|
virtual void setKey(const uint8_t* key)=0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,10 @@
|
||||||
#include "DiscBase.hpp"
|
#include "DiscBase.hpp"
|
||||||
#include "IFileIO.hpp"
|
#include "IFileIO.hpp"
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace NOD
|
namespace NOD
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -52,8 +56,8 @@ void DiscBase::IPartition::Node::extractToDirectory(const std::string& basePath,
|
||||||
{
|
{
|
||||||
if (mkdir(path.c_str(), 0755) && errno != EEXIST)
|
if (mkdir(path.c_str(), 0755) && errno != EEXIST)
|
||||||
throw std::runtime_error("unable to mkdir '" + path + "'");
|
throw std::runtime_error("unable to mkdir '" + path + "'");
|
||||||
for (DiscBase::IPartition::Node& subnode : *this)
|
for (Node& subnode : *this)
|
||||||
subnode.extractToDirectory(path);
|
subnode.extractToDirectory(path, force);
|
||||||
}
|
}
|
||||||
else if (m_kind == NODE_FILE)
|
else if (m_kind == NODE_FILE)
|
||||||
{
|
{
|
||||||
|
@ -68,4 +72,52 @@ void DiscBase::IPartition::Node::extractToDirectory(const std::string& basePath,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DiscBase::IPartition::_recursivePathOfNode(const std::string& basePath,
|
||||||
|
const Node& refNode,
|
||||||
|
const Node& curNode,
|
||||||
|
std::string& result)
|
||||||
|
{
|
||||||
|
std::string path = basePath + "/" + curNode.getName();
|
||||||
|
if (&refNode == &curNode)
|
||||||
|
{
|
||||||
|
result = path;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (curNode.m_kind == Node::NODE_DIRECTORY)
|
||||||
|
{
|
||||||
|
for (const Node& subnode : curNode)
|
||||||
|
if (_recursivePathOfNode(path, refNode, subnode, result))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string DiscBase::IPartition::pathOfNode(const Node& node)
|
||||||
|
{
|
||||||
|
std::string result;
|
||||||
|
_recursivePathOfNode("", node, m_nodes[0], result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DiscBase::IPartition::extractToDirectory(const std::string& path, bool force)
|
||||||
|
{
|
||||||
|
struct stat theStat;
|
||||||
|
if (mkdir(path.c_str(), 0755) && errno != EEXIST)
|
||||||
|
throw std::runtime_error("unable to mkdir '" + path + "'");
|
||||||
|
|
||||||
|
/* Extract Apploader */
|
||||||
|
std::string apploaderPath = path + "/apploader.bin";
|
||||||
|
if (force || stat(apploaderPath.c_str(), &theStat))
|
||||||
|
{
|
||||||
|
std::unique_ptr<uint8_t[]> buf(new uint8_t[m_apploaderSz]);
|
||||||
|
std::unique_ptr<IPartReadStream> rs = beginReadStream(0x2440);
|
||||||
|
rs->read(buf.get(), m_apploaderSz);
|
||||||
|
std::unique_ptr<IFileIO::IWriteStream> ws = NewFileIO(path + "/apploader.bin")->beginWriteStream();
|
||||||
|
ws->write(buf.get(), m_apploaderSz);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Extract Filesystem */
|
||||||
|
m_nodes[0].extractToDirectory(path, force);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ namespace NOD
|
||||||
class PartitionGCN : public DiscBase::IPartition
|
class PartitionGCN : public DiscBase::IPartition
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PartitionGCN(const DiscGCN& parent, Kind kind, size_t offset)
|
PartitionGCN(const DiscGCN& parent, Kind kind, uint64_t offset)
|
||||||
: IPartition(parent, kind, offset)
|
: IPartition(parent, kind, offset)
|
||||||
{
|
{
|
||||||
/* GCN-specific header reads */
|
/* GCN-specific header reads */
|
||||||
|
@ -16,6 +16,9 @@ public:
|
||||||
m_dolOff = SBig(vals[0]);
|
m_dolOff = SBig(vals[0]);
|
||||||
m_fstOff = SBig(vals[1]);
|
m_fstOff = SBig(vals[1]);
|
||||||
m_fstSz = SBig(vals[2]);
|
m_fstSz = SBig(vals[2]);
|
||||||
|
s->seek(0x2440 + 0x14);
|
||||||
|
s->read(vals, 8);
|
||||||
|
m_apploaderSz = SBig(vals[0]) + SBig(vals[1]);
|
||||||
|
|
||||||
/* Yay files!! */
|
/* Yay files!! */
|
||||||
parseFST(*s.get());
|
parseFST(*s.get());
|
||||||
|
@ -27,16 +30,16 @@ public:
|
||||||
std::unique_ptr<IDiscIO::IReadStream> m_dio;
|
std::unique_ptr<IDiscIO::IReadStream> m_dio;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PartReadStream(const PartitionGCN& parent, size_t offset)
|
PartReadStream(const PartitionGCN& parent, uint64_t offset)
|
||||||
: m_parent(parent)
|
: m_parent(parent)
|
||||||
{m_dio = m_parent.m_parent.getDiscIO().beginReadStream(offset);}
|
{m_dio = m_parent.m_parent.getDiscIO().beginReadStream(offset);}
|
||||||
void seek(size_t offset, int whence)
|
void seek(int64_t offset, int whence)
|
||||||
{m_dio->seek(offset, whence);}
|
{m_dio->seek(offset, whence);}
|
||||||
size_t read(void* buf, size_t length)
|
uint64_t read(void* buf, uint64_t length)
|
||||||
{return m_dio->read(buf, length);}
|
{return m_dio->read(buf, length);}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<IPartReadStream> beginReadStream(size_t offset) const
|
std::unique_ptr<IPartReadStream> beginReadStream(uint64_t offset) const
|
||||||
{
|
{
|
||||||
return std::unique_ptr<IPartReadStream>(new PartReadStream(*this, offset));
|
return std::unique_ptr<IPartReadStream>(new PartReadStream(*this, offset));
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,12 +20,12 @@ public:
|
||||||
: fp(fpin) {}
|
: fp(fpin) {}
|
||||||
~ReadStream() {fclose(fp);}
|
~ReadStream() {fclose(fp);}
|
||||||
public:
|
public:
|
||||||
size_t read(void* buf, size_t length)
|
uint64_t read(void* buf, uint64_t length)
|
||||||
{return fread(buf, 1, length, fp);}
|
{return fread(buf, 1, length, fp);}
|
||||||
void seek(size_t offset, int whence)
|
void seek(int64_t offset, int whence)
|
||||||
{fseek(fp, offset, whence);}
|
{fseeko(fp, offset, whence);}
|
||||||
};
|
};
|
||||||
std::unique_ptr<IReadStream> beginReadStream(size_t offset) const
|
std::unique_ptr<IReadStream> beginReadStream(uint64_t offset) const
|
||||||
{
|
{
|
||||||
FILE* fp = fopen(filepath.c_str(), "rb");
|
FILE* fp = fopen(filepath.c_str(), "rb");
|
||||||
if (!fp)
|
if (!fp)
|
||||||
|
@ -33,7 +33,7 @@ public:
|
||||||
throw std::runtime_error("Unable to open '" + filepath + "' for reading");
|
throw std::runtime_error("Unable to open '" + filepath + "' for reading");
|
||||||
return std::unique_ptr<IReadStream>();
|
return std::unique_ptr<IReadStream>();
|
||||||
}
|
}
|
||||||
fseek(fp, offset, SEEK_SET);
|
fseeko(fp, offset, SEEK_SET);
|
||||||
return std::unique_ptr<IReadStream>(new ReadStream(fp));
|
return std::unique_ptr<IReadStream>(new ReadStream(fp));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,10 +45,10 @@ public:
|
||||||
: fp(fpin) {}
|
: fp(fpin) {}
|
||||||
~WriteStream() {fclose(fp);}
|
~WriteStream() {fclose(fp);}
|
||||||
public:
|
public:
|
||||||
size_t write(void* buf, size_t length)
|
uint64_t write(void* buf, uint64_t length)
|
||||||
{return fwrite(buf, 1, length, fp);}
|
{return fwrite(buf, 1, length, fp);}
|
||||||
};
|
};
|
||||||
std::unique_ptr<IWriteStream> beginWriteStream(size_t offset) const
|
std::unique_ptr<IWriteStream> beginWriteStream(uint64_t offset) const
|
||||||
{
|
{
|
||||||
FILE* fp = fopen(filepath.c_str(), "wb");
|
FILE* fp = fopen(filepath.c_str(), "wb");
|
||||||
if (!fp)
|
if (!fp)
|
||||||
|
@ -56,7 +56,7 @@ public:
|
||||||
throw std::runtime_error("Unable to open '" + filepath + "' for writing");
|
throw std::runtime_error("Unable to open '" + filepath + "' for writing");
|
||||||
return std::unique_ptr<IWriteStream>();
|
return std::unique_ptr<IWriteStream>();
|
||||||
}
|
}
|
||||||
fseek(fp, offset, SEEK_SET);
|
fseeko(fp, offset, SEEK_SET);
|
||||||
return std::unique_ptr<IWriteStream>(new WriteStream(fp));
|
return std::unique_ptr<IWriteStream>(new WriteStream(fp));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -20,12 +20,12 @@ public:
|
||||||
: fp(fpin) {}
|
: fp(fpin) {}
|
||||||
~ReadStream() {fclose(fp);}
|
~ReadStream() {fclose(fp);}
|
||||||
public:
|
public:
|
||||||
size_t read(void* buf, size_t length)
|
uint64_t read(void* buf, uint64_t length)
|
||||||
{return fread(buf, 1, length, fp);}
|
{return fread(buf, 1, length, fp);}
|
||||||
void seek(size_t offset, int whence)
|
void seek(int64_t offset, int whence)
|
||||||
{fseek(fp, offset, whence);}
|
{fseeko(fp, offset, whence);}
|
||||||
};
|
};
|
||||||
std::unique_ptr<IReadStream> beginReadStream(size_t offset) const
|
std::unique_ptr<IReadStream> beginReadStream(uint64_t offset) const
|
||||||
{
|
{
|
||||||
FILE* fp = fopen(filepath.c_str(), "rb");
|
FILE* fp = fopen(filepath.c_str(), "rb");
|
||||||
if (!fp)
|
if (!fp)
|
||||||
|
@ -33,7 +33,7 @@ public:
|
||||||
throw std::runtime_error("Unable to open '" + filepath + "' for reading");
|
throw std::runtime_error("Unable to open '" + filepath + "' for reading");
|
||||||
return std::unique_ptr<IReadStream>();
|
return std::unique_ptr<IReadStream>();
|
||||||
}
|
}
|
||||||
fseek(fp, offset, SEEK_SET);
|
fseeko(fp, offset, SEEK_SET);
|
||||||
return std::unique_ptr<IReadStream>(new ReadStream(fp));
|
return std::unique_ptr<IReadStream>(new ReadStream(fp));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,10 +45,10 @@ public:
|
||||||
: fp(fpin) {}
|
: fp(fpin) {}
|
||||||
~WriteStream() {fclose(fp);}
|
~WriteStream() {fclose(fp);}
|
||||||
public:
|
public:
|
||||||
size_t write(void* buf, size_t length)
|
uint64_t write(void* buf, uint64_t length)
|
||||||
{return fwrite(buf, 1, length, fp);}
|
{return fwrite(buf, 1, length, fp);}
|
||||||
};
|
};
|
||||||
std::unique_ptr<IWriteStream> beginWriteStream(size_t offset) const
|
std::unique_ptr<IWriteStream> beginWriteStream(uint64_t offset) const
|
||||||
{
|
{
|
||||||
FILE* fp = fopen(filepath.c_str(), "wb");
|
FILE* fp = fopen(filepath.c_str(), "wb");
|
||||||
if (!fp)
|
if (!fp)
|
||||||
|
@ -56,7 +56,7 @@ public:
|
||||||
throw std::runtime_error("Unable to open '" + filepath + "' for writing");
|
throw std::runtime_error("Unable to open '" + filepath + "' for writing");
|
||||||
return std::unique_ptr<IWriteStream>();
|
return std::unique_ptr<IWriteStream>();
|
||||||
}
|
}
|
||||||
fseek(fp, offset, SEEK_SET);
|
fseeko(fp, offset, SEEK_SET);
|
||||||
return std::unique_ptr<IWriteStream>(new WriteStream(fp));
|
return std::unique_ptr<IWriteStream>(new WriteStream(fp));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
namespace NOD
|
namespace NOD
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/* Not much of a secret anymore I suppose */
|
||||||
static const uint8_t COMMON_KEY[] = {0xeb, 0xe4, 0x2a, 0x22,
|
static const uint8_t COMMON_KEY[] = {0xeb, 0xe4, 0x2a, 0x22,
|
||||||
0x5e, 0x85, 0x93, 0xe4,
|
0x5e, 0x85, 0x93, 0xe4,
|
||||||
0x48, 0xd9, 0xc5, 0x45,
|
0x48, 0xd9, 0xc5, 0x45,
|
||||||
|
@ -124,7 +125,7 @@ class PartitionWii : public DiscBase::IPartition
|
||||||
titleVersion = SBig(titleVersion);
|
titleVersion = SBig(titleVersion);
|
||||||
numContents = SBig(numContents);
|
numContents = SBig(numContents);
|
||||||
bootIdx = SBig(bootIdx);
|
bootIdx = SBig(bootIdx);
|
||||||
for (size_t c=0 ; c<numContents ; ++c)
|
for (uint16_t c=0 ; c<numContents ; ++c)
|
||||||
{
|
{
|
||||||
contents.emplace_back();
|
contents.emplace_back();
|
||||||
contents.back().read(s);
|
contents.back().read(s);
|
||||||
|
@ -175,11 +176,11 @@ class PartitionWii : public DiscBase::IPartition
|
||||||
Certificate m_tmdCert;
|
Certificate m_tmdCert;
|
||||||
Certificate m_ticketCert;
|
Certificate m_ticketCert;
|
||||||
|
|
||||||
size_t m_dataOff;
|
uint64_t m_dataOff;
|
||||||
uint8_t m_decKey[16];
|
uint8_t m_decKey[16];
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PartitionWii(const DiscWii& parent, Kind kind, size_t offset)
|
PartitionWii(const DiscWii& parent, Kind kind, uint64_t offset)
|
||||||
: IPartition(parent, kind, offset)
|
: IPartition(parent, kind, offset)
|
||||||
{
|
{
|
||||||
std::unique_ptr<IDiscIO::IReadStream> s = parent.getDiscIO().beginReadStream(offset);
|
std::unique_ptr<IDiscIO::IReadStream> s = parent.getDiscIO().beginReadStream(offset);
|
||||||
|
@ -233,6 +234,9 @@ public:
|
||||||
m_dolOff = SBig(vals[0]) << 2;
|
m_dolOff = SBig(vals[0]) << 2;
|
||||||
m_fstOff = SBig(vals[1]) << 2;
|
m_fstOff = SBig(vals[1]) << 2;
|
||||||
m_fstSz = SBig(vals[2]) << 2;
|
m_fstSz = SBig(vals[2]) << 2;
|
||||||
|
ds->seek(0x2440 + 0x14);
|
||||||
|
ds->read(vals, 8);
|
||||||
|
m_apploaderSz = SBig(vals[0]) + SBig(vals[1]);
|
||||||
|
|
||||||
/* Yay files!! */
|
/* Yay files!! */
|
||||||
parseFST(*ds.get());
|
parseFST(*ds.get());
|
||||||
|
@ -242,8 +246,8 @@ public:
|
||||||
{
|
{
|
||||||
std::unique_ptr<IAES> m_aes;
|
std::unique_ptr<IAES> m_aes;
|
||||||
const PartitionWii& m_parent;
|
const PartitionWii& m_parent;
|
||||||
size_t m_baseOffset;
|
uint64_t m_baseOffset;
|
||||||
size_t m_offset;
|
uint64_t m_offset;
|
||||||
std::unique_ptr<IDiscIO::IReadStream> m_dio;
|
std::unique_ptr<IDiscIO::IReadStream> m_dio;
|
||||||
|
|
||||||
size_t m_curBlock = SIZE_MAX;
|
size_t m_curBlock = SIZE_MAX;
|
||||||
|
@ -256,7 +260,7 @@ public:
|
||||||
m_aes->decrypt(&m_encBuf[0x3d0], &m_encBuf[0x400], m_decBuf, 0x7c00);
|
m_aes->decrypt(&m_encBuf[0x3d0], &m_encBuf[0x400], m_decBuf, 0x7c00);
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
PartReadStream(const PartitionWii& parent, size_t baseOffset, size_t offset)
|
PartReadStream(const PartitionWii& parent, uint64_t baseOffset, uint64_t offset)
|
||||||
: m_aes(NewAES()), m_parent(parent), m_baseOffset(baseOffset), m_offset(offset)
|
: m_aes(NewAES()), m_parent(parent), m_baseOffset(baseOffset), m_offset(offset)
|
||||||
{
|
{
|
||||||
m_aes->setKey(parent.m_decKey);
|
m_aes->setKey(parent.m_decKey);
|
||||||
|
@ -265,7 +269,7 @@ public:
|
||||||
decryptBlock();
|
decryptBlock();
|
||||||
m_curBlock = block;
|
m_curBlock = block;
|
||||||
}
|
}
|
||||||
void seek(size_t offset, int whence)
|
void seek(int64_t offset, int whence)
|
||||||
{
|
{
|
||||||
if (whence == SEEK_SET)
|
if (whence == SEEK_SET)
|
||||||
m_offset = offset;
|
m_offset = offset;
|
||||||
|
@ -281,11 +285,11 @@ public:
|
||||||
m_curBlock = block;
|
m_curBlock = block;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
size_t read(void* buf, size_t length)
|
uint64_t read(void* buf, uint64_t length)
|
||||||
{
|
{
|
||||||
size_t block = m_offset / 0x7c00;
|
size_t block = m_offset / 0x7c00;
|
||||||
size_t cacheOffset = m_offset % 0x7c00;
|
size_t cacheOffset = m_offset % 0x7c00;
|
||||||
size_t cacheSize;
|
uint64_t cacheSize;
|
||||||
uint8_t* dst = (uint8_t*)buf;
|
uint8_t* dst = (uint8_t*)buf;
|
||||||
|
|
||||||
while (length)
|
while (length)
|
||||||
|
@ -312,10 +316,12 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<IPartReadStream> beginReadStream(size_t offset) const
|
std::unique_ptr<IPartReadStream> beginReadStream(uint64_t offset) const
|
||||||
{
|
{
|
||||||
return std::unique_ptr<IPartReadStream>(new PartReadStream(*this, m_dataOff, offset));
|
return std::unique_ptr<IPartReadStream>(new PartReadStream(*this, m_dataOff, offset));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t normalizeOffset(uint64_t anOffset) const {return anOffset << 2;}
|
||||||
};
|
};
|
||||||
|
|
||||||
DiscWii::DiscWii(std::unique_ptr<IDiscIO>&& dio)
|
DiscWii::DiscWii(std::unique_ptr<IDiscIO>&& dio)
|
||||||
|
|
|
@ -18,13 +18,13 @@ public:
|
||||||
FileIOFILE(const std::string& path)
|
FileIOFILE(const std::string& path)
|
||||||
: m_path(path) {}
|
: m_path(path) {}
|
||||||
|
|
||||||
size_t size()
|
uint64_t size()
|
||||||
{
|
{
|
||||||
FILE* fp = fopen(m_path.c_str(), "rb");
|
FILE* fp = fopen(m_path.c_str(), "rb");
|
||||||
if (!fp)
|
if (!fp)
|
||||||
return 0;
|
return 0;
|
||||||
fseek(fp, 0, SEEK_END);
|
fseeko(fp, 0, SEEK_END);
|
||||||
size_t result = ftell(fp);
|
uint64_t result = ftello(fp);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -40,13 +40,15 @@ public:
|
||||||
throw std::runtime_error("unable to open '" + path + "' for writing");
|
throw std::runtime_error("unable to open '" + path + "' for writing");
|
||||||
}
|
}
|
||||||
~WriteStream() {fclose(fp);}
|
~WriteStream() {fclose(fp);}
|
||||||
size_t copyFromDisc(IPartReadStream& discio, size_t length)
|
uint64_t write(void* buf, uint64_t length)
|
||||||
|
{return fwrite(buf, 1, length, fp);}
|
||||||
|
uint64_t copyFromDisc(IPartReadStream& discio, uint64_t length)
|
||||||
{
|
{
|
||||||
size_t read = 0;
|
uint64_t read = 0;
|
||||||
while (length)
|
while (length)
|
||||||
{
|
{
|
||||||
size_t thisSz = MIN(0x7c00, length);
|
uint64_t thisSz = MIN(0x7c00, length);
|
||||||
size_t readSz = discio.read(buf, thisSz);
|
uint64_t readSz = discio.read(buf, thisSz);
|
||||||
if (thisSz != readSz)
|
if (thisSz != readSz)
|
||||||
throw std::runtime_error("unable to read enough from disc");
|
throw std::runtime_error("unable to read enough from disc");
|
||||||
if (fwrite(buf, 1, readSz, fp) != readSz)
|
if (fwrite(buf, 1, readSz, fp) != readSz)
|
||||||
|
@ -71,12 +73,14 @@ public:
|
||||||
throw std::runtime_error("unable to open '" + path + "' for reading");
|
throw std::runtime_error("unable to open '" + path + "' for reading");
|
||||||
}
|
}
|
||||||
~ReadStream() {fclose(fp);}
|
~ReadStream() {fclose(fp);}
|
||||||
size_t copyToDisc(IPartWriteStream& discio, size_t length)
|
uint64_t read(void* buf, uint64_t length)
|
||||||
|
{return fread(buf, 1, length, fp);}
|
||||||
|
uint64_t copyToDisc(IPartWriteStream& discio, uint64_t length)
|
||||||
{
|
{
|
||||||
size_t written = 0;
|
uint64_t written = 0;
|
||||||
while (length)
|
while (length)
|
||||||
{
|
{
|
||||||
size_t thisSz = MIN(0x7c00, length);
|
uint64_t thisSz = MIN(0x7c00, length);
|
||||||
if (fread(buf, 1, thisSz, fp) != thisSz)
|
if (fread(buf, 1, thisSz, fp) != thisSz)
|
||||||
throw std::runtime_error("unable to read enough from file");
|
throw std::runtime_error("unable to read enough from file");
|
||||||
if (discio.write(buf, thisSz) != thisSz)
|
if (discio.write(buf, thisSz) != thisSz)
|
||||||
|
|
|
@ -29,7 +29,7 @@ std::unique_ptr<DiscBase> OpenDiscFromImage(const char* path, bool& isWii)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fseek(fp, 0x18, SEEK_SET);
|
fseeko(fp, 0x18, SEEK_SET);
|
||||||
fread(&magic, 1, 4, fp);
|
fread(&magic, 1, 4, fp);
|
||||||
magic = NOD::SBig(magic);
|
magic = NOD::SBig(magic);
|
||||||
if (magic == 0x5D1C9EA3)
|
if (magic == 0x5D1C9EA3)
|
||||||
|
|
14
lib/aes.cpp
14
lib/aes.cpp
|
@ -76,8 +76,8 @@ protected:
|
||||||
void _decrypt(uint8_t* buff);
|
void _decrypt(uint8_t* buff);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void encrypt(uint8_t* iv, const uint8_t* inbuf, uint8_t* outbuf, size_t len);
|
void encrypt(uint8_t* iv, const uint8_t* inbuf, uint8_t* outbuf, uint64_t len);
|
||||||
void decrypt(uint8_t* iv, const uint8_t* inbuf, uint8_t* outbuf, size_t len);
|
void decrypt(uint8_t* iv, const uint8_t* inbuf, uint8_t* outbuf, uint64_t len);
|
||||||
void setKey(const uint8_t* key);
|
void setKey(const uint8_t* key);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -440,7 +440,7 @@ void SoftwareAES::decrypt(uint8_t* iv, const uint8_t* inbuf, uint8_t* outbuf, si
|
||||||
}
|
}
|
||||||
|
|
||||||
// CBC mode encryption
|
// CBC mode encryption
|
||||||
void SoftwareAES::encrypt(uint8_t* iv, const uint8_t* inbuf, uint8_t* outbuf, size_t len)
|
void SoftwareAES::encrypt(uint8_t* iv, const uint8_t* inbuf, uint8_t* outbuf, uint64_t len)
|
||||||
{
|
{
|
||||||
uint8_t block[16];
|
uint8_t block[16];
|
||||||
unsigned int blockno = 0, i;
|
unsigned int blockno = 0, i;
|
||||||
|
@ -485,10 +485,10 @@ class NiAES : public IAES
|
||||||
__m128i m_ekey[11];
|
__m128i m_ekey[11];
|
||||||
__m128i m_dkey[11];
|
__m128i m_dkey[11];
|
||||||
public:
|
public:
|
||||||
void encrypt(uint8_t* iv, const uint8_t* inbuf, uint8_t* outbuf, size_t len)
|
void encrypt(uint8_t* iv, const uint8_t* inbuf, uint8_t* outbuf, uint64_t len)
|
||||||
{
|
{
|
||||||
__m128i feedback,data;
|
__m128i feedback,data;
|
||||||
size_t i,j;
|
uint64_t i,j;
|
||||||
if (len%16)
|
if (len%16)
|
||||||
len = len/16+1;
|
len = len/16+1;
|
||||||
else
|
else
|
||||||
|
@ -505,10 +505,10 @@ public:
|
||||||
_mm_storeu_si128(&((__m128i*)outbuf)[i], feedback);
|
_mm_storeu_si128(&((__m128i*)outbuf)[i], feedback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void decrypt(uint8_t* iv, const uint8_t* inbuf, uint8_t* outbuf, size_t len)
|
void decrypt(uint8_t* iv, const uint8_t* inbuf, uint8_t* outbuf, uint64_t len)
|
||||||
{
|
{
|
||||||
__m128i data,feedback,last_in;
|
__m128i data,feedback,last_in;
|
||||||
size_t i,j;
|
uint64_t i,j;
|
||||||
if (len%16)
|
if (len%16)
|
||||||
len = len/16+1;
|
len = len/16+1;
|
||||||
else
|
else
|
||||||
|
|
Loading…
Reference in New Issue