From 7213ca723a65dff8ebb0c6c08669695217e60453 Mon Sep 17 00:00:00 2001 From: Treeki Date: Sat, 9 Oct 2010 01:00:16 +0200 Subject: material bugfixes, plus the beginning of U8 archive code, and a nice little API for handling archive filesystems --- wii/archiveu8.cpp | 20 ++++++++ wii/archiveu8.h | 37 ++++++++++++++ wii/common.cpp | 110 ++++++++++++++++++++++++++++++++++++++++++ wii/common.h | 97 +++++++++++++++++++++++++++++++++++++ wii/filesystem.cpp | 138 +++++++++++++++++++++++++++++++++++++++++++++++++++++ wii/filesystem.h | 73 ++++++++++++++++++++++++++++ 6 files changed, 475 insertions(+) create mode 100644 wii/archiveu8.cpp create mode 100644 wii/archiveu8.h create mode 100644 wii/common.cpp create mode 100644 wii/common.h create mode 100644 wii/filesystem.cpp create mode 100644 wii/filesystem.h (limited to 'wii') diff --git a/wii/archiveu8.cpp b/wii/archiveu8.cpp new file mode 100644 index 0000000..aeb3aac --- /dev/null +++ b/wii/archiveu8.cpp @@ -0,0 +1,20 @@ +/******************************************************************************* + 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 . +*******************************************************************************/ + +#include "archiveu8.h" + + diff --git a/wii/archiveu8.h b/wii/archiveu8.h new file mode 100644 index 0000000..66f3fbe --- /dev/null +++ b/wii/archiveu8.h @@ -0,0 +1,37 @@ +/******************************************************************************* + 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 . +*******************************************************************************/ + +#ifndef WIIARCHIVEU8_H +#define WIIARCHIVEU8_H + +#include "common.h" +#include "filesystem.h" + + + + +class WiiArchiveU8 { +public: + WiiArchiveU8(); + WiiArchiveU8(QDataStream &stream); + + WiiDirectory root; + + void writeToDataStream(QDataStream &out); +}; + +#endif // WIIARCHIVEU8_H diff --git a/wii/common.cpp b/wii/common.cpp new file mode 100644 index 0000000..f4a961c --- /dev/null +++ b/wii/common.cpp @@ -0,0 +1,110 @@ +/******************************************************************************* + 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 . +*******************************************************************************/ + +#include "common.h" + +QByteArray PadByteArray(QByteArray original, int newLength, char padWith) { + QByteArray newArray = original; + + if (original.length() > newLength) { + // the original array is longer than the length desired, so truncate it + newArray.truncate(newLength); + + } else if (original.length() < newLength) { + // the original array is shorter, so pad it + int oldLength = original.length(); + newArray.resize(newLength); + + for (int i = oldLength; i < newLength; i++) { + newArray[i] = '\0'; + } + } + + return newArray; +} + +QStringList ReadStringList(QDataStream &in) { + QStringList output; + + quint16 count; + in >> (quint16&)count; + in.skipRawData(2); // padding + + QVector stringOffsets(count); + + // save the initial offset so we can get the strings later + // string offsets are based on the first offset entry (after the count) + // NOT on the section offset + qint64 savedPos = in.device()->pos(); + + for (int i = 0; i < count; i++) { + quint32 offset; + in >> (quint32&)offset; + in.skipRawData(4); // unused? + + stringOffsets[i] = offset; + } + + // ok, now we can get the strings + for (int i = 0; i < count; i++) { + in.device()->seek(savedPos + stringOffsets[i]); + + // how fun: no length is stored for each string, they're just zero + // terminated. so let's try to figure it out! + int stringLength = 0; + char check; + + in >> (quint8&)check; + while (check != 0) { + stringLength += 1; + in >> (quint8&)check; + } + + // now read the string + char *buffer = new char[stringLength]; + + in.device()->seek(savedPos + stringOffsets[i]); + in.readRawData(buffer, stringLength); + + output.append(QString::fromAscii(buffer, stringLength)); + + delete[] buffer; + + + qDebug() << "Read string:" << output.last(); + } + + return output; +} + +QString ReadFixedLengthASCII(QDataStream &in, int length) { + QByteArray readStr(length, '\0'); + in.readRawData(readStr.data(), readStr.length()); + + QString str = QString::fromAscii(readStr.data(), readStr.length()); + if (str.contains(QChar('\0'))) + str.truncate(str.indexOf(QChar('\0'))); + + return str; +} + +void WriteFixedLengthASCII(QDataStream &out, QString str, int length) { + QByteArray paddedStr = PadByteArray(str.toAscii(), length); + out.writeRawData(paddedStr.constData(), paddedStr.length()); +} + + diff --git a/wii/common.h b/wii/common.h new file mode 100644 index 0000000..aa7dce0 --- /dev/null +++ b/wii/common.h @@ -0,0 +1,97 @@ +#ifndef WIICOMMON_H +#define WIICOMMON_H + +#include +#include +#include +#include +#include +#include +#include +#include + +inline quint32 BitExtract(quint32 value, int count, int start) { + // this function relies on heavy compiler optimisation to be efficient :p + quint32 mask = 0; + for (int i = start; i < start+count; i++) { + mask |= (0x80000000 >> i); + } + + return (value & mask) >> (32 - (start + count)); +} + +inline quint32 BitInsert(quint32 value, int newValue, int count, int start) { + quint32 mask = 0; + for (int i = start; i < start+count; i++) { + mask |= (0x80000000 >> i); + } + + value &= ~mask; + value |= (newValue << (32 - (start + count))) & mask; + return value; +} + + + + + +QByteArray PadByteArray(QByteArray original, int newLength, char padWith='\0'); + +inline quint32 ColorToRGBA(QColor col) { + return (col.red() << 24) | (col.green() << 16) | (col.blue() << 8) | (col.alpha()); +} + +inline QColor RGBAToColor(quint32 col) { + return QColor(col >> 24, (col >> 16) & 0xFF, (col >> 8) & 0xFF, col & 0xFF); +} + +inline void ReadRGBA8Color(QColor &out, QDataStream &in) { + quint32 col; + in >> (quint32&)col; + out = RGBAToColor(col); +} + +inline void WriteRGBA8Color(QColor &in, QDataStream &out) { + out << (quint32)ColorToRGBA(in); +} + +inline void ReadS10Color(QColor &out, QDataStream &in) { + quint16 r, g, b, a; + in >> (quint16&)r; + in >> (quint16&)g; + in >> (quint16&)b; + in >> (quint16&)a; + out.setRgb(r, g, b, a); +} + +inline void WriteS10Color(QColor &in, QDataStream &out) { + out << (quint16)in.red(); + out << (quint16)in.green(); + out << (quint16)in.blue(); + out << (quint16)in.alpha(); +} + +inline void ReadPointF(QDataStream &stream, QPointF &point) { + float x, y; + stream >> x; + stream >> y; + point.setX(x); + point.setY(y); +} + +inline void WritePointF(QDataStream &stream, const QPointF &point) { + stream << (float)point.x(); + stream << (float)point.y(); +} + +inline void InitDataStream(QDataStream &stream) { + stream.setByteOrder(QDataStream::BigEndian); + stream.setVersion(QDataStream::Qt_4_5); +} + +QStringList ReadStringList(QDataStream &in); + +QString ReadFixedLengthASCII(QDataStream &in, int length); +void WriteFixedLengthASCII(QDataStream &out, QString str, int length); + +#endif // WIICOMMON_H diff --git a/wii/filesystem.cpp b/wii/filesystem.cpp new file mode 100644 index 0000000..9926109 --- /dev/null +++ b/wii/filesystem.cpp @@ -0,0 +1,138 @@ +/******************************************************************************* + 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 . +*******************************************************************************/ + +#include "filesystem.h" + + +/******************************************************************************/ + +WiiFSObject::WiiFSObject() { parent = 0; } +WiiFSObject::~WiiFSObject() { } + + + +void WiiFSObject::unlinkFromParent() { + if (this->parent == 0) + return; + + if (this->parent->isDirectory()) { + WiiDirectory *p = (WiiDirectory *)this->parent; + if (p->children.contains(this)) + p->children.removeAt(p->children.indexOf(this)); + } + + this->parent = 0; +} + +bool WiiFSObject::nameIsEqual(QString check) { + return (bool)(QString::compare(this->name, check, Qt::CaseInsensitive)); +} + +bool WiiFSObject::isFile() { return false; } +bool WiiFSObject::isDirectory() { return false; } + +/******************************************************************************/ + +bool WiiFile::isFile() { return true; } + +/******************************************************************************/ + +WiiDirectory::~WiiDirectory() { + foreach (WiiFSObject *ptr, children) + delete ptr; +} + +bool WiiDirectory::isDirectory() { return true; } + +WiiFSObject *WiiDirectory::findByName(QString name, bool recursive) { + foreach (WiiFSObject *obj, children) { + if (obj->nameIsEqual(name)) + return obj; + + if (recursive && obj->isDirectory()) { + WiiDirectory *dir = (WiiDirectory*)obj; + WiiFSObject *tryThis = dir->findByName(name, recursive); + + if (tryThis) + return tryThis; + } + } + + return 0; +} + +WiiFSObject *WiiDirectory::resolvePath(QString path) { + QStringList pathComponents = path.split('/'); + WiiDirectory *currentDir = this; + + // special case: handle absolute paths + if (pathComponents.at(0) == "") { + while (currentDir->parent != 0) + currentDir = currentDir->parent; + + pathComponents.removeFirst(); + } + + // now we can loop through the path + while (!pathComponents.isEmpty()) { + QString next = pathComponents.takeFirst(); + + // get the next object in the path + if (next == ".") { + next = currentDir; + } else if (next == "..") { + next = currentDir->parent; + } else { + WiiFSObject *nextObj = currentDir->findByName(next, false); + } + + if (nextObj == 0) { + qWarning() << "Failed to resolve path" << path << ": missing component" << next; + return 0; + } + + if (pathComponents.isEmpty()) { + // we've reached the end \o/ + return nextObj; + } + + // verify that this object is a directory + if (!nextObj->isDirectory()) { + qWarning() << "Failed to resolve path" << path << ": component" << next << "is not a directory"; + } + + // ok, this has to be a directory, so let's just continue + currentDir = (WiiDirectory *)nextObj; + } + + // we should not reach here + return 0; +} + +bool WiiDirectory::addChild(WiiFSObject *obj) { + // verify to make sure an object does not exist with this name + if (this->findByName(obj->name, false) != 0) + return false; + + obj->unlinkFromParent(); + + this->children.append(obj); + obj->parent = this; + + return true; +} + diff --git a/wii/filesystem.h b/wii/filesystem.h new file mode 100644 index 0000000..1a7ecfa --- /dev/null +++ b/wii/filesystem.h @@ -0,0 +1,73 @@ +/******************************************************************************* + 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 . +*******************************************************************************/ + +#ifndef WIIFILESYSTEM_H +#define WIIFILESYSTEM_H + +#include "common.h" + + +class WiiFSObject { + // abstract base class of all filesystem objects +public: + virtual ~WiiFSObject(); + + WiiFSObject *parent; + + QString name; + + + void unlinkFromParent(); + bool nameIsEqual(QString check); + + virtual bool isFile(); + virtual bool isDirectory(); + + +protected: + WiiFSObject(); // don't instantiate this class directly! +}; + + +/******************************************************************************/ + +class WiiFile : public WiiFSObject { +public: + QByteArray data; + + + bool isFile(); +}; + +/******************************************************************************/ + +class WiiDirectory : public WiiFSObject { +public: + ~WiiDirectory(); + + QList children; + + + bool isDirectory(); + + WiiFSObject *findByName(QString name, bool recursive); + WiiFSObject *resolvePath(QString path); + bool addChild(WiiFSObject *obj); +}; + + +#endif // FILESYSTEM_H -- cgit v1.2.3