diff options
author | Treeki <treeki@gmail.com> | 2010-10-14 03:15:41 +0200 |
---|---|---|
committer | Treeki <treeki@gmail.com> | 2010-10-14 03:15:41 +0200 |
commit | fdf8cfec2b795393d7ee901abaf747575067068b (patch) | |
tree | 1eb3a65765c1c43c4ea91530462cd15d54f995d1 | |
parent | 7213ca723a65dff8ebb0c6c08669695217e60453 (diff) | |
download | LayoutStudio-fdf8cfec2b795393d7ee901abaf747575067068b.tar.gz LayoutStudio-fdf8cfec2b795393d7ee901abaf747575067068b.zip |
bugfixes; working U8 archive support for reading/writing
Diffstat (limited to '')
-rw-r--r-- | LayoutStudio.pro | 8 | ||||
-rw-r--r-- | README.markdown | 2 | ||||
-rw-r--r-- | lyt/archivepackage.cpp | 168 | ||||
-rw-r--r-- | lyt/archivepackage.h | 62 | ||||
-rw-r--r-- | lyt/directorypackage.cpp | 2 | ||||
-rw-r--r-- | lyt/packagebase.cpp | 3 | ||||
-rw-r--r-- | lyt/packagebase.h | 1 | ||||
-rw-r--r-- | main.cpp | 19 | ||||
-rw-r--r-- | wii/archiveu8.cpp | 243 | ||||
-rw-r--r-- | wii/archiveu8.h | 24 | ||||
-rw-r--r-- | wii/common.h | 13 | ||||
-rw-r--r-- | wii/filesystem.cpp | 13 | ||||
-rw-r--r-- | wii/stringtablebuilder.cpp | 25 | ||||
-rw-r--r-- | wii/stringtablebuilder.h | 22 |
14 files changed, 594 insertions, 11 deletions
diff --git a/LayoutStudio.pro b/LayoutStudio.pro index 9c5df61..0b6a395 100644 --- a/LayoutStudio.pro +++ b/LayoutStudio.pro @@ -30,7 +30,9 @@ SOURCES += main.cpp \ lyt/materials/blendmode.cpp \ wii/common.cpp \ wii/archiveu8.cpp \ - wii/filesystem.cpp + wii/filesystem.cpp \ + lyt/archivepackage.cpp \ + wii/stringtablebuilder.cpp HEADERS += lsmainwindow.h \ lsglobals.h \ lyt/packagebase.h \ @@ -57,7 +59,9 @@ HEADERS += lsmainwindow.h \ lyt/materials/blendmode.h \ wii/archiveu8.h \ wii/common.h \ - wii/filesystem.h + wii/filesystem.h \ + lyt/archivepackage.h \ + wii/stringtablebuilder.h FORMS += lsmainwindow.ui RESOURCES += resources.qrc diff --git a/README.markdown b/README.markdown index 0aa3ff0..9a3852d 100644 --- a/README.markdown +++ b/README.markdown @@ -16,6 +16,7 @@ GX GPU emulation in the [Dolphin][dol] GameCube/Wii emulator. ### Implemented Features ### - BRLYT reading (materials are not yet fully implemented) - Simple API for manipulating layout files from other code +- Wii filesystem API (currently only supports U8 archives) ### Planned Features ### @@ -31,7 +32,6 @@ GX GPU emulation in the [Dolphin][dol] GameCube/Wii emulator. - Test code for material structs - Add usd1 handling - Add LYTLayout packing -- Add U8 archive support - Add TPL file support diff --git a/lyt/archivepackage.cpp b/lyt/archivepackage.cpp new file mode 100644 index 0000000..6b5a476 --- /dev/null +++ b/lyt/archivepackage.cpp @@ -0,0 +1,168 @@ +/******************************************************************************* + This file is part of LayoutStudio (http://github.com/Treeki/LayoutStudio) + Copyright (c) 2010 Treeki (treeki@gmail.com) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, version 2.0. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License 2.0 for more details. + + You should have received a copy of the GNU General Public License 2.0 + along with this program. If not, see <http://www.gnu.org/licenses/>. +*******************************************************************************/ + +#include "archivepackage.h" + +#include <QtCore/QFile> + +LYTArchivePackage::LYTArchivePackage() : LYTPackageBase() { + m_archive = new WiiArchiveU8; +} + +LYTArchivePackage::LYTArchivePackage(QString filename) : LYTPackageBase() { + m_filename = filename; + + QFile file(filename); + file.open(QFile::ReadOnly); + QByteArray data = file.readAll(); + + QDataStream stream(data); + m_archive = new WiiArchiveU8(stream); +} + +LYTArchivePackage::~LYTArchivePackage() { + delete m_archive; +} + + + +WiiArchiveU8 *LYTArchivePackage::archive() { + return m_archive; +} + +QString LYTArchivePackage::filename() { + return m_filename; +} + + + +QStringList LYTArchivePackage::listSubDirIfExists(QString dirName) { + WiiFSObject *obj = this->m_archive->root.resolvePath(dirName); + + if (obj && obj->isDirectory()) { + QStringList output; + + foreach (WiiFSObject *ptr, ((WiiDirectory*)obj)->children) { + output.append(ptr->name); + } + + return output; + } + + return QStringList(); +} + + +QByteArray LYTArchivePackage::getFileFromSubDirIfExists(QString dirName, QString fileName) { + WiiFSObject *obj = this->m_archive->root.resolvePath(QString("%1/%2").arg(dirName, fileName)); + + if (obj && obj->isFile()) { + return ((WiiFile*)obj)->data; + } + + return QByteArray(); +} + + +bool LYTArchivePackage::writeFileToSubDir(QString dirName, QString fileName, QByteArray data) { + WiiFSObject *obj = this->m_archive->root.resolvePath(QString("%1/%2").arg(dirName, fileName)); + + if (obj && obj->isFile()) { + ((WiiFile*)obj)->data = data; + return true; + } + + return false; +} + + + + +QStringList LYTArchivePackage::listAnims() { + return this->listSubDirIfExists("arc/anim"); +} + +QStringList LYTArchivePackage::listLayouts() { + return this->listSubDirIfExists("arc/blyt"); +} + +QStringList LYTArchivePackage::listTextures() { + return this->listSubDirIfExists("arc/timg"); +} + +QStringList LYTArchivePackage::listFonts() { + return this->listSubDirIfExists("arc/font"); +} + + + +QByteArray LYTArchivePackage::getAnim(QString name) { + return this->getFileFromSubDirIfExists("arc/anim", name); +} + +QByteArray LYTArchivePackage::getLayout(QString name) { + return this->getFileFromSubDirIfExists("arc/blyt", name); +} + +QByteArray LYTArchivePackage::getTexture(QString name) { + return this->getFileFromSubDirIfExists("arc/timg", name); +} + +QByteArray LYTArchivePackage::getFont(QString name) { + return this->getFileFromSubDirIfExists("arc/font", name); +} + + + +bool LYTArchivePackage::writeAnim(QString name, QByteArray data) { + return this->writeFileToSubDir("arc/anim", name, data); +} + +bool LYTArchivePackage::writeLayout(QString name, QByteArray data) { + return this->writeFileToSubDir("arc/blyt", name, data); +} + +bool LYTArchivePackage::writeTexture(QString name, QByteArray data) { + return this->writeFileToSubDir("arc/timg", name, data); +} + +bool LYTArchivePackage::writeFont(QString name, QByteArray data) { + return this->writeFileToSubDir("arc/font", name, data); +} + + + +bool LYTArchivePackage::savePackage() { + QFile file(m_filename); + + if (file.open(QFile::WriteOnly)) { + QByteArray data; + QDataStream stream(&data, QIODevice::ReadWrite); + + m_archive->writeToDataStream(stream); + file.write(data); + + return true; + } + + return false; +} + + +QString LYTArchivePackage::description() { + return m_filename; +} diff --git a/lyt/archivepackage.h b/lyt/archivepackage.h new file mode 100644 index 0000000..7ef1abd --- /dev/null +++ b/lyt/archivepackage.h @@ -0,0 +1,62 @@ +/******************************************************************************* + This file is part of LayoutStudio (http://github.com/Treeki/LayoutStudio) + Copyright (c) 2010 Treeki (treeki@gmail.com) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, version 2.0. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License 2.0 for more details. + + You should have received a copy of the GNU General Public License 2.0 + along with this program. If not, see <http://www.gnu.org/licenses/>. +*******************************************************************************/ + +#ifndef LYTARCHIVEPACKAGE_H +#define LYTARCHIVEPACKAGE_H + +#include "packagebase.h" +#include "wii/archiveu8.h" + +class LYTArchivePackage : public LYTPackageBase { +public: + LYTArchivePackage(); + LYTArchivePackage(QString filename); + + ~LYTArchivePackage(); + + QStringList listAnims(); + QStringList listLayouts(); + QStringList listTextures(); + QStringList listFonts(); + + QByteArray getAnim(QString name); + QByteArray getLayout(QString name); + QByteArray getTexture(QString name); + QByteArray getFont(QString name); + + bool writeAnim(QString name, QByteArray data); + bool writeLayout(QString name, QByteArray data); + bool writeTexture(QString name, QByteArray data); + bool writeFont(QString name, QByteArray data); + + bool savePackage(); + QString description(); + + WiiArchiveU8 *archive(); + QString filename(); + + +protected: + QStringList listSubDirIfExists(QString dirName); + QByteArray getFileFromSubDirIfExists(QString dirName, QString fileName); + bool writeFileToSubDir(QString dirName, QString fileName, QByteArray data); + + WiiArchiveU8 *m_archive; + QString m_filename; +}; + +#endif // LYTARCHIVEPACKAGE_H diff --git a/lyt/directorypackage.cpp b/lyt/directorypackage.cpp index 84287e6..e8f31b9 100644 --- a/lyt/directorypackage.cpp +++ b/lyt/directorypackage.cpp @@ -17,7 +17,7 @@ #include "directorypackage.h" -#include <QDir> +#include <QtCore/QDir> LYTDirectoryPackage::LYTDirectoryPackage(QString path) : LYTPackageBase() { QDir fix_path(path); diff --git a/lyt/packagebase.cpp b/lyt/packagebase.cpp index c9004e7..e186435 100644 --- a/lyt/packagebase.cpp +++ b/lyt/packagebase.cpp @@ -20,3 +20,6 @@ LYTPackageBase::LYTPackageBase() { // do nothing } + +LYTPackageBase::~LYTPackageBase() { +} diff --git a/lyt/packagebase.h b/lyt/packagebase.h index 3de3e58..9ad45c0 100644 --- a/lyt/packagebase.h +++ b/lyt/packagebase.h @@ -25,6 +25,7 @@ class LYTPackageBase { public: LYTPackageBase(); + virtual ~LYTPackageBase(); virtual QStringList listAnims() = 0; virtual QStringList listLayouts() = 0; @@ -20,18 +20,33 @@ #include "lsglobals.h" #include "lyt/directorypackage.h" +#include "lyt/archivepackage.h" #include "lyt/layout.h" +#include <QtCore/QFile> + +#include "wii/archiveu8.h" + int main(int argc, char *argv[]) { QApplication a(argc, argv); LSGlobals::setup(); + /*QFile file("H:\\ISOs\\NSMBWii\\Extracted\\Layout\\continue\\continue.arc"); + file.open(QFile::ReadOnly); + QByteArray arc = file.readAll(); + file.close();*/ + + LYTArchivePackage package("H:\\ISOs\\NSMBWii\\Extracted\\Layout\\continue\\continue.arc"); + LYTLayout layout(package, "continue_05.brlyt"); + package.savePackage(); + + //LYTDirectoryPackage package("H:\\ISOs\\NSMBWii\\Extracted\\Layout\\continue\\continue\\arc"); //LYTLayout layout(package, "continue_05.brlyt"); - LYTDirectoryPackage package("H:\\ISOs\\TP\\banner\\arc_extr"); - LYTLayout layout(package, "banner.brlyt"); + //LYTDirectoryPackage package("H:\\ISOs\\TP\\banner\\arc_extr"); + //LYTLayout layout(package, "banner.brlyt"); LSMainWindow w; w.show(); diff --git a/wii/archiveu8.cpp b/wii/archiveu8.cpp index aeb3aac..5e0ad5d 100644 --- a/wii/archiveu8.cpp +++ b/wii/archiveu8.cpp @@ -18,3 +18,246 @@ #include "archiveu8.h" + + + + +WiiArchiveU8::WiiArchiveU8() { } + +WiiArchiveU8::WiiArchiveU8(QDataStream &stream) { + U8ReadInfo info; + info.startPos = stream.device()->pos(); + + quint32 magic; + stream >> (quint32&)magic; + + if (magic != 0x55AA382D) + qWarning() << "WiiArchiveU8: tried to load an archive without the U8 magic"; + + quint32 fstStart, fstSize, dataOffset; + stream >> (quint32&)fstStart; + stream >> (quint32&)fstSize; + stream >> (quint32&)dataOffset; + + // read the FST + stream.device()->seek(info.startPos + fstStart); + + // read the root node + quint32 rootNodeLastChild; + + stream.skipRawData(8); // ignore type, nameOffset and dataOffset + stream >> (quint32&)rootNodeLastChild; + + // but before we do this, read the string table + qint64 savePos = stream.device()->pos(); + stream.device()->seek(savePos + ((rootNodeLastChild - 1) * 12)); + + int stringTableLength = fstSize - (rootNodeLastChild * 12); + + QByteArray rawStringTable; + rawStringTable.resize(stringTableLength); + stream.readRawData(rawStringTable.data(), stringTableLength); + + info.stringTable = QString::fromAscii(rawStringTable.constData(), stringTableLength); + + // now read the root node + stream.device()->seek(savePos); + + qDebug() << "Reading root node: last child is" << rootNodeLastChild; + info.currentNode = 1; + this->readDir(stream, this->root, rootNodeLastChild, info); +} + + +void WiiArchiveU8::readDir(QDataStream &in, WiiDirectory &dir, int lastChild, U8ReadInfo &info) { + // read every node in this directory + + while (info.currentNode < lastChild) { + info.currentNode++; + + //qDebug() << "Reading @ pos" << in.device()->pos(); + + quint32 value, dataOffset, size; + in >> (quint32&)value; + in >> (quint32&)dataOffset; + in >> (quint32&)size; + + int nameOffset = value & 0xFFFFFF; + int type = value >> 24; + + WiiFSObject *newObj; + if (type == 0) + newObj = new WiiFile; + else if (type == 1) + newObj = new WiiDirectory; + else + qFatal("WiiArchiveU8::readDir: Unknown fs obj type %d", type); + + // get the name + int nameSize = info.stringTable.indexOf(QChar::Null, nameOffset) - nameOffset; + newObj->name = info.stringTable.mid(nameOffset, nameSize); + + qDebug() << "Reading node" << info.currentNode << newObj->name << "- type:" << type << "size:" << size << "offset:" << dataOffset; + + // read the contents + if (newObj->isFile()) { + // get the file data + qint64 savePos = in.device()->pos(); + in.device()->seek(info.startPos + dataOffset); + + WiiFile *file = (WiiFile*)newObj; + file->data.resize(size); + in.readRawData(file->data.data(), size); + + in.device()->seek(savePos); + + } else if (newObj->isDirectory()) { + // read the children + this->readDir(in, *((WiiDirectory*)newObj), size, info); + + } + + qDebug() << "Adding" << newObj->name << "to" << dir.name; + dir.addChild(newObj); + }; +} + + + +void WiiArchiveU8::writeToDataStream(QDataStream &out) { + U8WriteInfo info; + + // first off, before we do anything else, create the string table + this->addNodeToStringTable(this->root, info.stringTableBuilder); + + QByteArray stringTable = info.stringTableBuilder.pack(); + + // calculate various fun offsets/sizes + int nodeCount = 0; + this->countNode(this->root, &nodeCount); + + info.startPos = out.device()->pos(); + + quint32 fstStart = 0x20; + quint32 nodeDataSize = nodeCount * 12; + quint32 stringTableSize = stringTable.length(); + quint32 fstSize = nodeDataSize + stringTableSize; + quint32 dataOffset = AlignUp(fstStart + fstSize, 0x20); + + qDebug() << "Writing: fstStart" << fstStart << "nodeCount" << nodeCount; + qDebug() << "nodeDataSize" << nodeDataSize << "stringTableSize" << stringTableSize; + qDebug() << "fstSize" << fstSize << "dataOffset" << dataOffset; + + // now write the header + out << (quint32)0x55AA382D; + out << (quint32)fstStart; + out << (quint32)fstSize; + out << (quint32)dataOffset; + + WritePadding(0x10, out); + + // write root node + info.currentNode = 1; // root node is 1 + info.currentRecursionLevel = 0; + info.nextDataOffset = dataOffset; + + out << (quint32)(0x01000000 << info.stringTableBuilder.add("")); + out << (quint32)0; + out << (quint32)nodeCount; + + this->writeDir(out, this->root, info); + + // write string table + out.writeRawData(stringTable.constData(), stringTable.length()); + + // write data (after padding) + WritePadding(dataOffset - fstSize - fstStart, out); + + this->writeNodeData(out, this->root); + + // looks like we are finally done +} + + +void WiiArchiveU8::addNodeToStringTable(WiiFSObject &node, WiiStringTableBuilder &table) { + table.add(node.name); + + if (node.isDirectory()) { + WiiDirectory *dir = (WiiDirectory*)&node; + + foreach (WiiFSObject *p, dir->children) + this->addNodeToStringTable(*p, table); + } +} + + +void WiiArchiveU8::countNode(WiiFSObject &node, int *countPtr) { + (*countPtr)++; + + if (node.isDirectory()) { + WiiDirectory *dir = (WiiDirectory*)&node; + + foreach (WiiFSObject *p, dir->children) + this->countNode(*p, countPtr); + } +} + + +void WiiArchiveU8::writeDir(QDataStream &out, WiiDirectory &dir, U8WriteInfo &info) { + foreach (WiiFSObject *p, dir.children) { + info.currentNode++; + + if (p->isDirectory()) { + // write directory + WiiDirectory *thisDir = (WiiDirectory*)p; + + out << (quint32)(0x01000000 | info.stringTableBuilder.add(thisDir->name)); + out << (quint32)info.currentRecursionLevel; + + qint64 lastChildFieldPos = out.device()->pos(); + out << (quint32)0; // placeholder + + info.currentRecursionLevel++; + + this->writeDir(out, *thisDir, info); + + info.currentRecursionLevel--; + + // write lastChild field + qint64 dirEndPos = out.device()->pos(); + + out.device()->seek(lastChildFieldPos); + out << (quint32)info.currentNode; + out.device()->seek(dirEndPos); + + } else if (p->isFile()) { + // write file + WiiFile *thisFile = (WiiFile*)p; + + out << (quint32)info.stringTableBuilder.add(thisFile->name); + out << (quint32)info.nextDataOffset; + out << (quint32)thisFile->data.size(); + + info.nextDataOffset = AlignUp(info.nextDataOffset + thisFile->data.size(), 0x20); + } + } +} + + +void WiiArchiveU8::writeNodeData(QDataStream &out, WiiFSObject &node) { + if (node.isDirectory()) { + // write all the children's data + WiiDirectory *thisDir = (WiiDirectory*)&node; + + foreach (WiiFSObject *p, thisDir->children) + this->writeNodeData(out, *p); + + } else if (node.isFile()) { + // write this file's data + WiiFile *thisFile = (WiiFile*)&node; + + int len = thisFile->data.length(); + out.writeRawData(thisFile->data.constData(), len); + WritePadding(AlignUp(len, 0x20) - len, out); + } +} diff --git a/wii/archiveu8.h b/wii/archiveu8.h index 66f3fbe..6f54ba2 100644 --- a/wii/archiveu8.h +++ b/wii/archiveu8.h @@ -20,8 +20,22 @@ #include "common.h" #include "filesystem.h" +#include "stringtablebuilder.h" +struct U8ReadInfo { + qint64 startPos; + QString stringTable; + int currentNode; +}; + +struct U8WriteInfo { + qint64 startPos; + WiiStringTableBuilder stringTableBuilder; + int currentRecursionLevel; + int currentNode; + int nextDataOffset; +}; class WiiArchiveU8 { @@ -32,6 +46,16 @@ public: WiiDirectory root; void writeToDataStream(QDataStream &out); + +private: + void readDir(QDataStream &in, WiiDirectory &dir, int lastChild, U8ReadInfo &info); + + void addNodeToStringTable(WiiFSObject &node, WiiStringTableBuilder &table); + void countNode(WiiFSObject &node, int *countPtr); + + void writeDir(QDataStream &out, WiiDirectory &dir, U8WriteInfo &info); + + void writeNodeData(QDataStream &out, WiiFSObject &node); }; #endif // WIIARCHIVEU8_H diff --git a/wii/common.h b/wii/common.h index aa7dce0..34f1526 100644 --- a/wii/common.h +++ b/wii/common.h @@ -10,6 +10,15 @@ #include <QtCore/QDebug> #include <QtCore/QVector> +inline quint32 AlignUp(quint32 value, quint32 alignTo) { + return (value + alignTo - 1) & ~(alignTo - 1); +} + +inline quint32 AlignDown(quint32 value, quint32 alignTo) { + return value & ~(alignTo - 1); +} + + inline quint32 BitExtract(quint32 value, int count, int start) { // this function relies on heavy compiler optimisation to be efficient :p quint32 mask = 0; @@ -31,6 +40,10 @@ inline quint32 BitInsert(quint32 value, int newValue, int count, int start) { return value; } +inline void WritePadding(int num, QDataStream &out) { + for (int i = 0; i < num; i++) + out << (quint8)0; +} diff --git a/wii/filesystem.cpp b/wii/filesystem.cpp index 9926109..09fe207 100644 --- a/wii/filesystem.cpp +++ b/wii/filesystem.cpp @@ -39,7 +39,7 @@ void WiiFSObject::unlinkFromParent() { } bool WiiFSObject::nameIsEqual(QString check) { - return (bool)(QString::compare(this->name, check, Qt::CaseInsensitive)); + return (bool)(QString::compare(this->name, check, Qt::CaseInsensitive) == 0); } bool WiiFSObject::isFile() { return false; } @@ -82,7 +82,7 @@ WiiFSObject *WiiDirectory::resolvePath(QString path) { // special case: handle absolute paths if (pathComponents.at(0) == "") { while (currentDir->parent != 0) - currentDir = currentDir->parent; + currentDir = (WiiDirectory*)currentDir->parent; pathComponents.removeFirst(); } @@ -90,14 +90,15 @@ WiiFSObject *WiiDirectory::resolvePath(QString path) { // now we can loop through the path while (!pathComponents.isEmpty()) { QString next = pathComponents.takeFirst(); + WiiFSObject *nextObj; // get the next object in the path if (next == ".") { - next = currentDir; + nextObj = currentDir; } else if (next == "..") { - next = currentDir->parent; + nextObj = currentDir->parent; } else { - WiiFSObject *nextObj = currentDir->findByName(next, false); + nextObj = currentDir->findByName(next, false); } if (nextObj == 0) { @@ -113,6 +114,7 @@ WiiFSObject *WiiDirectory::resolvePath(QString path) { // verify that this object is a directory if (!nextObj->isDirectory()) { qWarning() << "Failed to resolve path" << path << ": component" << next << "is not a directory"; + return 0; } // ok, this has to be a directory, so let's just continue @@ -120,6 +122,7 @@ WiiFSObject *WiiDirectory::resolvePath(QString path) { } // we should not reach here + qWarning() << "Failed to resolve path" << path << ": unknown error"; return 0; } diff --git a/wii/stringtablebuilder.cpp b/wii/stringtablebuilder.cpp new file mode 100644 index 0000000..679247c --- /dev/null +++ b/wii/stringtablebuilder.cpp @@ -0,0 +1,25 @@ +#include "stringtablebuilder.h" + +WiiStringTableBuilder::WiiStringTableBuilder() { + m_nextOffset = 0; + m_data = ""; +} + +quint32 WiiStringTableBuilder::add(QString str) { + if (m_lookup.contains(str)) + return m_lookup.value(str); + + quint32 added = m_nextOffset; + m_lookup.insert(str, added); + + m_data.append(str.toAscii()); + m_data.append('\0'); + + m_nextOffset = m_data.length(); + + return added; +} + +QByteArray WiiStringTableBuilder::pack() { + return m_data; +} diff --git a/wii/stringtablebuilder.h b/wii/stringtablebuilder.h new file mode 100644 index 0000000..f416a37 --- /dev/null +++ b/wii/stringtablebuilder.h @@ -0,0 +1,22 @@ +#ifndef STRINGTABLEBUILDER_H +#define STRINGTABLEBUILDER_H + +#include "common.h" +#include <QtCore/QString> +#include <QtCore/QHash> +#include <QtCore/QByteArray> + +class WiiStringTableBuilder { +public: + WiiStringTableBuilder(); + + quint32 add(QString str); + QByteArray pack(); + +protected: + int m_nextOffset; + QByteArray m_data; + QHash<QString, quint32> m_lookup; +}; + +#endif // STRINGTABLEBUILDER_H |