* Added proper tree generation for WiiSave

This commit is contained in:
Phillip Stephens 2014-09-19 04:54:56 -07:00
parent 6187eb3f77
commit f92811004f
15 changed files with 233 additions and 59 deletions

View File

@ -1,4 +1,4 @@
#ifndef ATHENA_NO_SAVES
#if !defined(ATHENA_NO_SAVES) && !defined(ATHENA_NO_ZQUEST)
// This file is part of libAthena.
//
// libAthena is free software: you can redistribute it and/or modify

View File

@ -1,4 +1,4 @@
#ifndef ATHENA_NO_SAVES
#if !defined(ATHENA_NO_SAVES) && !defined(ATHENA_NO_ZQUEST)
// This file is part of libAthena.
//
// libAthena is free software: you can redistribute it and/or modify

View File

@ -1,4 +1,4 @@
#ifndef ATHENA_NO_SAVES
#if !defined(ATHENA_NO_SAVES) && !defined(ATHENA_NO_ZQUEST)
// This file is part of libAthena.
//
// libAthena is free software: you can redistribute it and/or modify

View File

@ -1,4 +1,4 @@
#ifndef ATHENA_NO_SAVES
#if !defined(ATHENA_NO_SAVES) && !defined(ATHENA_NO_ZQUEST)
// This file is part of libAthena.
//
// libAthena is free software: you can redistribute it and/or modify

View File

@ -166,14 +166,30 @@ public:
*/
bool isFile() const;
void addChild(WiiFile* file);
std::vector<WiiFile*> children();
WiiFile* child(const std::string& name);
void removeChild(const std::string& name);
void removeChild(WiiFile* file);
WiiFile* parent();
void setParent(WiiFile *parent);
atUint32 fileCount();
std::vector<WiiFile*> allChildren();
std::string fullpath();
protected:
private:
atUint8 m_permissions;
atUint8 m_attributes;
Type m_type;
std::string m_filename;
int m_fileLen;
Type m_type;
std::string m_filename;
int m_fileLen;
atUint8* m_fileData;
WiiFile* m_parent;
std::vector<WiiFile*> m_children;
};
} // zelda

View File

@ -59,18 +59,20 @@ public:
* \param file
*/
void addFile(const std::string& filename, WiiFile* file);
void setFiles(std::unordered_map<std::string, WiiFile*> files);
void setRoot(WiiFile* root);
/*!
* \brief file
* \param filename
* \return
*/
WiiFile* file(const std::string& filename) const;
WiiFile* file(const std::string& filename);
atUint32 fileCount() const;
/*!
* \brief fileList
* \return
*/
std::unordered_map<std::string, WiiFile*>& fileList();
WiiFile* root();
/*!
* \brief setBanner
@ -84,10 +86,12 @@ public:
*/
WiiBanner* banner() const;
std::vector<WiiFile*> allFiles() const;
protected:
private:
std::unordered_map<std::string, WiiFile*> m_files;
WiiFile* m_root;
WiiBanner* m_banner;
};

View File

@ -64,6 +64,7 @@ private:
WiiFile* readFile();
WiiImage* readImage(atUint32 width, atUint32 height);
void readCerts(atUint32 totalSize);
WiiFile* buildTree(std::vector<WiiFile*> files);
};
} // io

View File

@ -1,4 +1,4 @@
#ifndef ATHENA_NO_SAVES
#if !defined(ATHENA_NO_SAVES) && !defined(ATHENA_NO_ZQUEST)
// This file is part of libAthena.
//
// libAthena is free software: you can redistribute it and/or modify

View File

@ -1,4 +1,4 @@
#ifndef ATHENA_NO_SAVES
#if !defined(ATHENA_NO_SAVES) && !defined(ATHENA_NO_ZQUEST)
// This file is part of libAthena.
//
// libAthena is free software: you can redistribute it and/or modify

View File

@ -1,4 +1,4 @@
#ifndef ATHENA_NO_SAVES
#if !defined(ATHENA_NO_SAVES) && !defined(ATHENA_NO_ZQUEST)
// This file is part of libAthena.
//
// libAthena is free software: you can redistribute it and/or modify

View File

@ -1,4 +1,4 @@
#ifndef ATHENA_NO_SAVES
#if !defined(ATHENA_NO_SAVES) && !defined(ATHENA_NO_ZQUEST)
// This file is part of libAthena.
//
// libAthena is free software: you can redistribute it and/or modify

View File

@ -15,7 +15,8 @@
// along with libAthena. If not, see <http://www.gnu.org/licenses/>
#include "Athena/WiiFile.hpp"
#include "Athena/InvalidOperationException.hpp"
#include <algorithm>
namespace Athena
{
@ -27,7 +28,8 @@ WiiFile::WiiFile() :
m_type(WiiFile::File),
m_filename(""),
m_fileLen(0),
m_fileData(NULL)
m_fileData(NULL),
m_parent(NULL)
{
//ctor
}
@ -38,7 +40,8 @@ WiiFile::WiiFile(const std::string& filename) :
m_type(WiiFile::File),
m_filename(filename),
m_fileLen(0),
m_fileData(NULL)
m_fileData(NULL),
m_parent(NULL)
{
}
@ -56,6 +59,9 @@ WiiFile::~WiiFile()
{
if (m_fileData)
delete[] m_fileData;
for (WiiFile* child : m_children)
delete child;
}
@ -134,5 +140,144 @@ bool WiiFile::isFile() const
return (m_type == WiiFile::File);
}
void WiiFile::addChild(WiiFile *file)
{
if (!isDirectory())
THROW_INVALID_OPERATION_EXCEPTION("%s is not a directory", filename().c_str());
if (std::find(m_children.begin(), m_children.end(), file) != m_children.end())
return;
// Lets figure out it's place
std::string tmpName(file->filename());
// Since we only support *NIX paths this is simple
atUint32 depth = Athena::utility::countChar(tmpName, '/');
bool owned = false;
while ((depth--) > 0)
{
// add them from the beginning of the path up
tmpName = tmpName.substr(0, tmpName.find('/'));
for (int i = 0; i < m_children.size(); i++)
{
if (!m_children[i]->filename().compare(tmpName))
{
std::string newName = file->filename();
newName = newName.substr(newName.rfind("/") + 1, newName.size() - newName.rfind("/"));
file->setFilename(newName);
m_children[i]->addChild(file);
owned = true;
}
}
}
if (!owned)
{
m_children.push_back(file);
file->setParent(this);
}
}
WiiFile* WiiFile::child(const std::string &name)
{
std::vector<WiiFile*>::iterator iter = std::find_if(m_children.begin(), m_children.end(),
[&name](WiiFile* f) { return !f->filename().compare(name); });
if (iter != m_children.end())
return *iter;
std::string tmpName(name);
tmpName = tmpName.substr(tmpName.rfind('/')+1, tmpName.size() - tmpName.rfind('/'));
for (WiiFile* f : m_children)
{
if (f->isFile())
continue;
WiiFile* ret = f->child(tmpName);
if (ret)
return ret;
}
return nullptr;
}
void WiiFile::removeChild(WiiFile* file)
{
std::vector<WiiFile*>::iterator iter = std::find(m_children.begin(), m_children.end(), file);
if (iter == m_children.end())
return;
m_children.erase(iter);
}
WiiFile* WiiFile::parent()
{
return m_parent;
}
void WiiFile::setParent(WiiFile* parent)
{
if (m_parent)
m_parent->removeChild(this);
m_parent = parent;
m_parent->addChild(this);
}
atUint32 WiiFile::fileCount()
{
int ret = m_children.size();
for (WiiFile* f : m_children)
{
if (f->isFile())
continue;
ret += f->fileCount();
}
return ret;
}
std::vector<WiiFile *> WiiFile::allChildren()
{
std::vector<WiiFile*> ret;
if (m_children.size() == 0)
return ret;
// Add our children first
for (WiiFile* f : m_children)
ret.push_back(f);
// now lets add our children's children
for (WiiFile* f : m_children)
{
if (f->isFile())
continue;
std::vector<WiiFile*> tmp = f->allChildren();
if (tmp.size() == 0)
continue;
ret.insert(ret.end(), tmp.begin(), tmp.end());
}
return ret;
}
std::string WiiFile::fullpath()
{
std::string ret;
if (m_parent)
ret = m_parent->filename() + "/";
ret = ret + filename();
while (ret.at(0) == '/')
ret.erase(ret.begin());
return ret;
}
} // zelda
#endif // ATHENA_NO_SAVES

View File

@ -37,14 +37,15 @@ namespace Athena
{
WiiSave::WiiSave()
: m_banner(NULL)
: m_root(NULL),
m_banner(NULL)
{
}
WiiSave::~WiiSave()
{
m_files.clear();
delete m_root;
delete m_banner;
m_banner = NULL;
@ -52,48 +53,38 @@ WiiSave::~WiiSave()
void WiiSave::addFile(const std::string& filepath, WiiFile* file)
{
m_files[filepath] = file;
m_root->addChild(file);
}
void WiiSave::setFiles(std::unordered_map<std::string, WiiFile*> files)
void WiiSave::setRoot(WiiFile* root)
{
if (files.size() <= 0)
return;
if (root != m_root)
delete m_root;
std::cout << "Setting file map...";
if (m_files.size() > 0)
{
std::unordered_map<std::string, WiiFile*>::iterator iter = m_files.begin();
for (;iter != m_files.end(); ++iter)
{
if (iter->second)
delete iter->second;
}
m_files.clear();
}
m_files = files;
std::cout << "done" << std::endl;
m_root = root;
}
WiiFile* WiiSave::file(const std::string& filepath) const
WiiFile* WiiSave::file(const std::string& filepath)
{
std::unordered_map<std::string, WiiFile*>::const_iterator iter = m_files.begin();
if (filepath.empty())
return nullptr;
for (;iter != m_files.end(); ++iter)
{
if (iter->first == filepath)
return (WiiFile*)iter->second;
}
std::string cleanPath(filepath);
return NULL;
while (cleanPath.at(0) == '/')
cleanPath.erase(cleanPath.begin());
return m_root->child(cleanPath);
}
std::unordered_map<std::string, WiiFile*>& WiiSave::fileList()
atUint32 WiiSave::fileCount() const
{
return m_files;
return m_root->fileCount();
}
WiiFile* WiiSave::root()
{
return m_root;
}
void WiiSave::setBanner(WiiBanner* banner)
@ -106,6 +97,11 @@ WiiBanner* WiiSave::banner() const
return m_banner;
}
std::vector<WiiFile *> WiiSave::allFiles() const
{
return m_root->allChildren();
}
} // zelda
#endif // ATHENA_NO_SAVES

View File

@ -87,15 +87,15 @@ WiiSave* WiiSaveReader::readSave()
base::seek(2);
base::seek(0x10);
std::unordered_map<std::string, WiiFile*> files;
std::vector<WiiFile*> files;
for (atUint32 i = 0; i < numFiles; ++i)
{
WiiFile* file = readFile();
if (file)
files["/"+file->filename()] = file;
files.push_back(file);
}
ret->setFiles(files);
ret->setRoot(buildTree(files));
readCerts(totalSize);
}
@ -313,6 +313,18 @@ void WiiSaveReader::readCerts(atUint32 totalSize)
std::cout << "done" << std::endl;
}
WiiFile* WiiSaveReader::buildTree(std::vector<WiiFile*> files)
{
// This is simply a virtual root that will contain all the other nodes
WiiFile* root = new WiiFile("/");
root->setType(WiiFile::Directory);
for (WiiFile* f : files)
root->addChild(f);
return root;
}
} // io
} // zelda
#endif // ATHENA_NO_SAVES

View File

@ -64,7 +64,7 @@ bool WiiSaveWriter::writeSave(WiiSave *save, atUint8 *macAddress, atUint32 ngId,
base::writeUint32(0x70);
base::writeUint32(0x426B0001);
base::writeUint32(ngId); // NG-ID
base::writeUint32(save->fileList().size());
base::writeUint32(save->fileCount());
base::writeUint32(0); // Size of files;
base::seek(8);
base::writeUint32(0); // totalSize
@ -74,9 +74,9 @@ bool WiiSaveWriter::writeSave(WiiSave *save, atUint8 *macAddress, atUint32 ngId,
base::seek(2); // unknown;
base::seek(0x10); // padding;
atUint32 totalSize = 0;
for (std::unordered_map<std::string, WiiFile*>::const_iterator iter = save->fileList().begin(); iter != save->fileList().end(); ++iter)
for (WiiFile* file : save->allFiles())
{
totalSize += writeFile(iter->second);
totalSize += writeFile(file);
}
int pos = base::position();
// Write size data
@ -167,8 +167,8 @@ atUint32 WiiSaveWriter::writeFile(WiiFile *file)
atUint8 name[0x45];
utility::fillRandom(name, 0x45);
memcpy(name, file->filename().c_str(), file->filename().size());
name[file->filename().size()] = '\0';
memcpy(name, file->fullpath().c_str(), file->fullpath().size());
name[file->fullpath().size()] = '\0';
base::writeBytes((atInt8*)name, 0x45);
atUint8 iv[16];
utility::fillRandom(iv, 0x10);