* 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. // This file is part of libAthena.
// //
// libAthena is free software: you can redistribute it and/or modify // 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. // This file is part of libAthena.
// //
// libAthena is free software: you can redistribute it and/or modify // 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. // This file is part of libAthena.
// //
// libAthena is free software: you can redistribute it and/or modify // 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. // This file is part of libAthena.
// //
// libAthena is free software: you can redistribute it and/or modify // libAthena is free software: you can redistribute it and/or modify

View File

@ -166,6 +166,20 @@ public:
*/ */
bool isFile() const; 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: protected:
private: private:
atUint8 m_permissions; atUint8 m_permissions;
@ -174,6 +188,8 @@ private:
std::string m_filename; std::string m_filename;
int m_fileLen; int m_fileLen;
atUint8* m_fileData; atUint8* m_fileData;
WiiFile* m_parent;
std::vector<WiiFile*> m_children;
}; };
} // zelda } // zelda

View File

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

View File

@ -64,6 +64,7 @@ private:
WiiFile* readFile(); WiiFile* readFile();
WiiImage* readImage(atUint32 width, atUint32 height); WiiImage* readImage(atUint32 width, atUint32 height);
void readCerts(atUint32 totalSize); void readCerts(atUint32 totalSize);
WiiFile* buildTree(std::vector<WiiFile*> files);
}; };
} // io } // 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. // This file is part of libAthena.
// //
// libAthena is free software: you can redistribute it and/or modify // 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. // This file is part of libAthena.
// //
// libAthena is free software: you can redistribute it and/or modify // 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. // This file is part of libAthena.
// //
// libAthena is free software: you can redistribute it and/or modify // 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. // This file is part of libAthena.
// //
// libAthena is free software: you can redistribute it and/or modify // 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/> // along with libAthena. If not, see <http://www.gnu.org/licenses/>
#include "Athena/WiiFile.hpp" #include "Athena/WiiFile.hpp"
#include "Athena/InvalidOperationException.hpp"
#include <algorithm>
namespace Athena namespace Athena
{ {
@ -27,7 +28,8 @@ WiiFile::WiiFile() :
m_type(WiiFile::File), m_type(WiiFile::File),
m_filename(""), m_filename(""),
m_fileLen(0), m_fileLen(0),
m_fileData(NULL) m_fileData(NULL),
m_parent(NULL)
{ {
//ctor //ctor
} }
@ -38,7 +40,8 @@ WiiFile::WiiFile(const std::string& filename) :
m_type(WiiFile::File), m_type(WiiFile::File),
m_filename(filename), m_filename(filename),
m_fileLen(0), m_fileLen(0),
m_fileData(NULL) m_fileData(NULL),
m_parent(NULL)
{ {
} }
@ -56,6 +59,9 @@ WiiFile::~WiiFile()
{ {
if (m_fileData) if (m_fileData)
delete[] 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); 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 } // zelda
#endif // ATHENA_NO_SAVES #endif // ATHENA_NO_SAVES

View File

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

View File

@ -87,15 +87,15 @@ WiiSave* WiiSaveReader::readSave()
base::seek(2); base::seek(2);
base::seek(0x10); base::seek(0x10);
std::unordered_map<std::string, WiiFile*> files; std::vector<WiiFile*> files;
for (atUint32 i = 0; i < numFiles; ++i) for (atUint32 i = 0; i < numFiles; ++i)
{ {
WiiFile* file = readFile(); WiiFile* file = readFile();
if (file) if (file)
files["/"+file->filename()] = file; files.push_back(file);
} }
ret->setFiles(files); ret->setRoot(buildTree(files));
readCerts(totalSize); readCerts(totalSize);
} }
@ -313,6 +313,18 @@ void WiiSaveReader::readCerts(atUint32 totalSize)
std::cout << "done" << std::endl; 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 } // io
} // zelda } // zelda
#endif // ATHENA_NO_SAVES #endif // ATHENA_NO_SAVES

View File

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