diff --git a/include/Athena/SkywardSwordFile.hpp b/include/Athena/SkywardSwordFile.hpp index 61870b3..ca88153 100644 --- a/include/Athena/SkywardSwordFile.hpp +++ b/include/Athena/SkywardSwordFile.hpp @@ -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 diff --git a/include/Athena/SkywardSwordFileReader.hpp b/include/Athena/SkywardSwordFileReader.hpp index 82df715..87565ab 100644 --- a/include/Athena/SkywardSwordFileReader.hpp +++ b/include/Athena/SkywardSwordFileReader.hpp @@ -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 diff --git a/include/Athena/SkywardSwordFileWriter.hpp b/include/Athena/SkywardSwordFileWriter.hpp index 0fd186f..7c82ea9 100644 --- a/include/Athena/SkywardSwordFileWriter.hpp +++ b/include/Athena/SkywardSwordFileWriter.hpp @@ -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 diff --git a/include/Athena/SkywardSwordQuest.hpp b/include/Athena/SkywardSwordQuest.hpp index f611170..4b4a2e9 100644 --- a/include/Athena/SkywardSwordQuest.hpp +++ b/include/Athena/SkywardSwordQuest.hpp @@ -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 diff --git a/include/Athena/WiiFile.hpp b/include/Athena/WiiFile.hpp index 85c196e..3d8b4e2 100644 --- a/include/Athena/WiiFile.hpp +++ b/include/Athena/WiiFile.hpp @@ -166,14 +166,30 @@ public: */ bool isFile() const; + void addChild(WiiFile* file); + std::vector 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 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 m_children; }; } // zelda diff --git a/include/Athena/WiiSave.hpp b/include/Athena/WiiSave.hpp index e40aa8f..2bb8a57 100644 --- a/include/Athena/WiiSave.hpp +++ b/include/Athena/WiiSave.hpp @@ -59,18 +59,20 @@ public: * \param file */ void addFile(const std::string& filename, WiiFile* file); - void setFiles(std::unordered_map 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& fileList(); + WiiFile* root(); /*! * \brief setBanner @@ -84,10 +86,12 @@ public: */ WiiBanner* banner() const; + std::vector allFiles() const; + protected: private: - std::unordered_map m_files; + WiiFile* m_root; WiiBanner* m_banner; }; diff --git a/include/Athena/WiiSaveReader.hpp b/include/Athena/WiiSaveReader.hpp index 4b2d61f..3ae72d6 100644 --- a/include/Athena/WiiSaveReader.hpp +++ b/include/Athena/WiiSaveReader.hpp @@ -64,6 +64,7 @@ private: WiiFile* readFile(); WiiImage* readImage(atUint32 width, atUint32 height); void readCerts(atUint32 totalSize); + WiiFile* buildTree(std::vector files); }; } // io diff --git a/src/Athena/SkywardSwordFile.cpp b/src/Athena/SkywardSwordFile.cpp index bedd66a..cbb0367 100644 --- a/src/Athena/SkywardSwordFile.cpp +++ b/src/Athena/SkywardSwordFile.cpp @@ -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 diff --git a/src/Athena/SkywardSwordFileReader.cpp b/src/Athena/SkywardSwordFileReader.cpp index a2c4c6c..68b91f4 100644 --- a/src/Athena/SkywardSwordFileReader.cpp +++ b/src/Athena/SkywardSwordFileReader.cpp @@ -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 diff --git a/src/Athena/SkywardSwordFileWriter.cpp b/src/Athena/SkywardSwordFileWriter.cpp index 1f2bd56..faee571 100644 --- a/src/Athena/SkywardSwordFileWriter.cpp +++ b/src/Athena/SkywardSwordFileWriter.cpp @@ -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 diff --git a/src/Athena/SkywardSwordQuest.cpp b/src/Athena/SkywardSwordQuest.cpp index 41b98b0..3d7f826 100644 --- a/src/Athena/SkywardSwordQuest.cpp +++ b/src/Athena/SkywardSwordQuest.cpp @@ -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 diff --git a/src/Athena/WiiFile.cpp b/src/Athena/WiiFile.cpp index 45a2f35..39b0791 100644 --- a/src/Athena/WiiFile.cpp +++ b/src/Athena/WiiFile.cpp @@ -15,7 +15,8 @@ // along with libAthena. If not, see #include "Athena/WiiFile.hpp" - +#include "Athena/InvalidOperationException.hpp" +#include 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::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::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::allChildren() +{ + std::vector 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 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 diff --git a/src/Athena/WiiSave.cpp b/src/Athena/WiiSave.cpp index f246fd6..f0a647f 100644 --- a/src/Athena/WiiSave.cpp +++ b/src/Athena/WiiSave.cpp @@ -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 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::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::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& 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 WiiSave::allFiles() const +{ + return m_root->allChildren(); +} + } // zelda #endif // ATHENA_NO_SAVES diff --git a/src/Athena/WiiSaveReader.cpp b/src/Athena/WiiSaveReader.cpp index a2f11dd..616c796 100644 --- a/src/Athena/WiiSaveReader.cpp +++ b/src/Athena/WiiSaveReader.cpp @@ -87,15 +87,15 @@ WiiSave* WiiSaveReader::readSave() base::seek(2); base::seek(0x10); - std::unordered_map files; + std::vector 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 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 diff --git a/src/Athena/WiiSaveWriter.cpp b/src/Athena/WiiSaveWriter.cpp index 990f624..b1935c0 100644 --- a/src/Athena/WiiSaveWriter.cpp +++ b/src/Athena/WiiSaveWriter.cpp @@ -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::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);