more crime spaghetti
This commit is contained in:
		
							parent
							
								
									4c118e2b63
								
							
						
					
					
						commit
						f5d408f02f
					
				| 
						 | 
					@ -28,12 +28,18 @@ using Option = std::optional<T>;
 | 
				
			||||||
template<typename... Ts>
 | 
					template<typename... Ts>
 | 
				
			||||||
using Variant = std::variant<Ts...>;
 | 
					using Variant = std::variant<Ts...>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using Path = std::filesystem::path;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template<typename T>
 | 
				
			||||||
 | 
					using UniquePtr = std::unique_ptr<T>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct Error : public std::runtime_error {
 | 
					struct Error : public std::runtime_error {
 | 
				
			||||||
	using std::runtime_error::runtime_error;
 | 
						using std::runtime_error::runtime_error;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct EnumError          : public Error {using Error::Error;};
 | 
					struct EnumError          : public Error {using Error::Error;};
 | 
				
			||||||
struct FileFormatError    : public Error {using Error::Error;};
 | 
					struct FileFormatError    : public Error {using Error::Error;};
 | 
				
			||||||
 | 
					struct FileSystemError    : public Error {using Error::Error;};
 | 
				
			||||||
struct UnimplementedError : public Error {using Error::Error;};
 | 
					struct UnimplementedError : public Error {using Error::Error;};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct MemoryStreamBuf : public std::streambuf {
 | 
					struct MemoryStreamBuf : public std::streambuf {
 | 
				
			||||||
| 
						 | 
					@ -98,7 +104,7 @@ static inline std::array<char, N> readBytes(std::istream &st) {
 | 
				
			||||||
	return std::move(b);
 | 
						return std::move(b);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline std::ifstream openReadBin(std::filesystem::path path) {
 | 
					static inline std::ifstream openReadBin(Path path) {
 | 
				
			||||||
	return std::ifstream{path, std::ios_base::in | std::ios_base::binary};
 | 
						return std::ifstream{path, std::ios_base::in | std::ios_base::binary};
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -150,4 +156,14 @@ static inline QDebug operator<<(QDebug debug, Option<T> const &t) {
 | 
				
			||||||
	return debug;
 | 
						return debug;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template<typename T>
 | 
				
			||||||
 | 
					static inline QDebug operator<<(QDebug debug, UniquePtr<T> const &t) {
 | 
				
			||||||
 | 
						if(t) {
 | 
				
			||||||
 | 
							debug << *t;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							debug << "nullptr";
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return debug;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// EOF
 | 
					// EOF
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,6 +18,24 @@ namespace Arc {
 | 
				
			||||||
		return None;
 | 
							return None;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Node::Node(std::string _name, Dir *_parent) :
 | 
				
			||||||
 | 
							name(_name),
 | 
				
			||||||
 | 
							parent(_parent)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Node::~Node() {
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Dir::Dir(std::string _name, Dir *_parent) :
 | 
				
			||||||
 | 
							Node(_name, _parent),
 | 
				
			||||||
 | 
							baseType()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Dir::~Dir() {
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Dir Dir::readArchive(std::istream &st, ArcType type) {
 | 
						Dir Dir::readArchive(std::istream &st, ArcType type) {
 | 
				
			||||||
		switch(type) {
 | 
							switch(type) {
 | 
				
			||||||
			case ArcType::Pack: return readPack(st);
 | 
								case ArcType::Pack: return readPack(st);
 | 
				
			||||||
| 
						 | 
					@ -25,6 +43,23 @@ namespace Arc {
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Node *Dir::findNode(std::string const &name) {
 | 
				
			||||||
 | 
							auto it = std::find_if(begin(), end(),
 | 
				
			||||||
 | 
								[&name](auto const &node) {
 | 
				
			||||||
 | 
									return node->name == name;
 | 
				
			||||||
 | 
								});
 | 
				
			||||||
 | 
							return it != end() ? &**it : nullptr;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						File::File(std::string _name, Dir *_parent) :
 | 
				
			||||||
 | 
							Node(_name, _parent),
 | 
				
			||||||
 | 
							baseType()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						File::~File() {
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ArcInfo::ArcInfo(ArcType arcType) noexcept :
 | 
						ArcInfo::ArcInfo(ArcType arcType) noexcept :
 | 
				
			||||||
		type{arcType}
 | 
							type{arcType}
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
| 
						 | 
					@ -54,27 +89,6 @@ namespace Arc {
 | 
				
			||||||
	Arc::~Arc() {
 | 
						Arc::~Arc() {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Node *Dir::findNode(std::string const &name) {
 | 
					 | 
				
			||||||
		auto it = std::find_if(begin(), end(), [&name](Node &node) {
 | 
					 | 
				
			||||||
			return node.name == name;
 | 
					 | 
				
			||||||
		});
 | 
					 | 
				
			||||||
		return it != end() ? &*it : nullptr;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	Node::Node(Dir &&f, std::string &&n, FileType t) :
 | 
					 | 
				
			||||||
		superType(std::move(f)),
 | 
					 | 
				
			||||||
		name(std::move(n)),
 | 
					 | 
				
			||||||
		type(t)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	Node::Node(File &&f, std::string &&n, FileType t) :
 | 
					 | 
				
			||||||
		superType(std::move(f)),
 | 
					 | 
				
			||||||
		name(std::move(n)),
 | 
					 | 
				
			||||||
		type(t)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	Model::Model(QObject *parent) :
 | 
						Model::Model(QObject *parent) :
 | 
				
			||||||
		QAbstractItemModel{parent},
 | 
							QAbstractItemModel{parent},
 | 
				
			||||||
		m_dir{nullptr}
 | 
							m_dir{nullptr}
 | 
				
			||||||
| 
						 | 
					@ -95,21 +109,23 @@ namespace Arc {
 | 
				
			||||||
		switch(role) {
 | 
							switch(role) {
 | 
				
			||||||
			case Qt::DecorationRole:
 | 
								case Qt::DecorationRole:
 | 
				
			||||||
				if(col == Column::Name) {
 | 
									if(col == Column::Name) {
 | 
				
			||||||
					auto icon =
 | 
										auto icon = node->getDir() ? "folder" : "text-x-generic";
 | 
				
			||||||
						std::holds_alternative<Dir>(*node) ? "folder"
 | 
					 | 
				
			||||||
						                                   : "text-x-generic";
 | 
					 | 
				
			||||||
					return QVariant{QIcon::fromTheme(icon)};
 | 
										return QVariant{QIcon::fromTheme(icon)};
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				break;
 | 
									break;
 | 
				
			||||||
			case Qt::DisplayRole:
 | 
								case Qt::DisplayRole:
 | 
				
			||||||
				switch(col) {
 | 
									switch(col) {
 | 
				
			||||||
					case Column::Size:
 | 
										case Column::Size:
 | 
				
			||||||
						if(auto file = std::get_if<File>(node)) {
 | 
											if(auto file = node->getFile()) {
 | 
				
			||||||
							return QVariant{QString::number(file->size())};
 | 
												return QVariant{QString::number(file->size())};
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
						break;
 | 
											break;
 | 
				
			||||||
					case Column::Type:
 | 
										case Column::Type:
 | 
				
			||||||
						return QVariant{tr(enumToString(node->type))};
 | 
											if(auto file = node->getFile()) {
 | 
				
			||||||
 | 
												return QVariant{tr(enumToString(file->type))};
 | 
				
			||||||
 | 
											} else {
 | 
				
			||||||
 | 
												return QVariant{tr("Directory")};
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
					case Column::Name:
 | 
										case Column::Name:
 | 
				
			||||||
						return QVariant{tr(node->name.data())};
 | 
											return QVariant{tr(node->name.data())};
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
| 
						 | 
					@ -151,7 +167,7 @@ namespace Arc {
 | 
				
			||||||
		if(!m_dir || !hasIndex(row, col, parent) || row > m_dir->size()) {
 | 
							if(!m_dir || !hasIndex(row, col, parent) || row > m_dir->size()) {
 | 
				
			||||||
			return QModelIndex{};
 | 
								return QModelIndex{};
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			return createIndex(row, col, &m_dir->at(row));
 | 
								return createIndex(row, col, &*m_dir->at(row));
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -188,10 +204,19 @@ namespace Arc {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void Model::setDirToIndex(QModelIndex const &ind) {
 | 
						void Model::setDirToIndex(QModelIndex const &ind) {
 | 
				
			||||||
		auto node = static_cast<Node *>(ind.data(Qt::UserRole).value<void *>());
 | 
							auto node = static_cast<Node *>(ind.data(Qt::UserRole).value<void *>());
 | 
				
			||||||
		if(auto dir = std::get_if<Dir>(node)) {
 | 
							if(auto dir = node->getDir()) {
 | 
				
			||||||
			setDir(dir);
 | 
								setDir(dir);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool Model::dirUp() {
 | 
				
			||||||
 | 
							if(m_dir && m_dir->parent) {
 | 
				
			||||||
 | 
								setDir(m_dir->parent);
 | 
				
			||||||
 | 
								return true;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// EOF
 | 
					// EOF
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -35,33 +35,62 @@ namespace Arc {
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	Q_ENUM_NS(ArcType)
 | 
						Q_ENUM_NS(ArcType)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct Node;
 | 
						class Dir;
 | 
				
			||||||
 | 
						class File;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct Dir : public std::vector<Node> {
 | 
						class Node {
 | 
				
			||||||
		using std::vector<Node>::vector;
 | 
						public:
 | 
				
			||||||
 | 
							Node()             = delete;
 | 
				
			||||||
 | 
							Node(Node const &) = delete;
 | 
				
			||||||
 | 
							Node(Node &&)      = default;
 | 
				
			||||||
 | 
							virtual ~Node();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							virtual Dir  const *getDir()  const = 0;
 | 
				
			||||||
 | 
							virtual Dir        *getDir()        = 0;
 | 
				
			||||||
 | 
							virtual File const *getFile() const = 0;
 | 
				
			||||||
 | 
							virtual File       *getFile()       = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Dir        *parent{nullptr};
 | 
				
			||||||
 | 
							std::string name;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						protected:
 | 
				
			||||||
 | 
							Node(std::string name, Dir *parent);
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						class Dir : public Node, public std::vector<UniquePtr<Node>> {
 | 
				
			||||||
 | 
						public:
 | 
				
			||||||
 | 
							using baseType = std::vector<UniquePtr<Node>>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Dir(std::string name, Dir *parent = nullptr);
 | 
				
			||||||
 | 
							Dir(Dir const &) = delete;
 | 
				
			||||||
 | 
							Dir(Dir &&)      = default;
 | 
				
			||||||
 | 
							virtual ~Dir();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Dir  const *getDir()  const override {return this;}
 | 
				
			||||||
 | 
							Dir        *getDir()        override {return this;}
 | 
				
			||||||
 | 
							File const *getFile() const override {return nullptr;}
 | 
				
			||||||
 | 
							File       *getFile()       override {return nullptr;}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Node *findNode(std::string const &name);
 | 
							Node *findNode(std::string const &name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		static Dir readArchive(std::istream &st, ArcType type);
 | 
							static Dir readArchive(std::istream &st, ArcType type);
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct File : public QByteArray {
 | 
						class File : public Node, public QByteArray {
 | 
				
			||||||
		using QByteArray::QByteArray;
 | 
						public:
 | 
				
			||||||
	};
 | 
							using baseType = QByteArray;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct Node : public Variant<Dir, File> {
 | 
							File(std::string name, Dir *parent = nullptr);
 | 
				
			||||||
		using superType = Variant<Dir, File>;
 | 
							File(File const &) = delete;
 | 
				
			||||||
 | 
							File(File &&)      = default;
 | 
				
			||||||
 | 
							virtual ~File();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Node() = default;
 | 
							Dir  const *getDir()  const override {return nullptr;}
 | 
				
			||||||
 | 
							Dir        *getDir()        override {return nullptr;}
 | 
				
			||||||
 | 
							File const *getFile() const override {return this;}
 | 
				
			||||||
 | 
							File       *getFile()       override {return this;}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Node(Dir  &&f, std::string &&n, FileType t = FileType::Normal);
 | 
							FileType type{FileType::Normal};
 | 
				
			||||||
		Node(File &&f, std::string &&n, FileType t = FileType::Normal);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Node(Node const &) = default;
 | 
					 | 
				
			||||||
		Node(Node &&) = default;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		std::string name;
 | 
					 | 
				
			||||||
		FileType    type;
 | 
					 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	class Model : public QAbstractItemModel {
 | 
						class Model : public QAbstractItemModel {
 | 
				
			||||||
| 
						 | 
					@ -89,6 +118,7 @@ namespace Arc {
 | 
				
			||||||
	public slots:
 | 
						public slots:
 | 
				
			||||||
		void setDir(Dir *dir);
 | 
							void setDir(Dir *dir);
 | 
				
			||||||
		void setDirToIndex(QModelIndex const &ind);
 | 
							void setDirToIndex(QModelIndex const &ind);
 | 
				
			||||||
 | 
							bool dirUp();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	signals:
 | 
						signals:
 | 
				
			||||||
		void dirChanged(Dir *from, Dir *to);
 | 
							void dirChanged(Dir *from, Dir *to);
 | 
				
			||||||
| 
						 | 
					@ -97,7 +127,8 @@ namespace Arc {
 | 
				
			||||||
		Dir *m_dir;
 | 
							Dir *m_dir;
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct ArcInfo {
 | 
						class ArcInfo {
 | 
				
			||||||
 | 
						public:
 | 
				
			||||||
		ArcInfo(ArcType arcType) noexcept;
 | 
							ArcInfo(ArcType arcType) noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		ArcType     type;
 | 
							ArcType     type;
 | 
				
			||||||
| 
						 | 
					@ -119,14 +150,24 @@ namespace Arc {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Option<ArcType> getArchiveType(std::istream &st) noexcept;
 | 
						Option<ArcType> getArchiveType(std::istream &st) noexcept;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
Q_DECLARE_METATYPE(Arc::Dir)
 | 
					
 | 
				
			||||||
Q_DECLARE_METATYPE(Arc::File)
 | 
					static inline QDebug operator<<(QDebug debug, Arc::Dir const &t) {
 | 
				
			||||||
Q_DECLARE_METATYPE(Arc::Node)
 | 
						debug << static_cast<Arc::Dir::baseType const &>(t);
 | 
				
			||||||
 | 
						return debug;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline QDebug operator<<(QDebug debug, Arc::File const &t) {
 | 
				
			||||||
 | 
						debug << static_cast<Arc::File::baseType const &>(t);
 | 
				
			||||||
 | 
						return debug;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline QDebug operator<<(QDebug debug, Arc::Node const &t) {
 | 
					static inline QDebug operator<<(QDebug debug, Arc::Node const &t) {
 | 
				
			||||||
	debug << "Arc::Node(" << t.name << ", ";
 | 
						debug << "Arc::Node(" << t.name << ", ";
 | 
				
			||||||
	std::visit([&](auto &&arg) {debug << arg;},
 | 
						if(auto v = t.getDir()) {
 | 
				
			||||||
	           static_cast<Variant<Arc::Dir, Arc::File>>(t));
 | 
							debug << *v;
 | 
				
			||||||
 | 
						} else if(auto v = t.getFile()) {
 | 
				
			||||||
 | 
							debug << *v;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	debug << ")";
 | 
						debug << ")";
 | 
				
			||||||
	return debug;
 | 
						return debug;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -51,7 +51,17 @@
 | 
				
			||||||
    <addaction name="separator"/>
 | 
					    <addaction name="separator"/>
 | 
				
			||||||
    <addaction name="actionQuit"/>
 | 
					    <addaction name="actionQuit"/>
 | 
				
			||||||
   </widget>
 | 
					   </widget>
 | 
				
			||||||
 | 
					   <widget class="QMenu" name="menuGo">
 | 
				
			||||||
 | 
					    <property name="title">
 | 
				
			||||||
 | 
					     <string>Go</string>
 | 
				
			||||||
 | 
					    </property>
 | 
				
			||||||
 | 
					    <addaction name="actionUp"/>
 | 
				
			||||||
 | 
					    <addaction name="actionBack"/>
 | 
				
			||||||
 | 
					    <addaction name="actionForward"/>
 | 
				
			||||||
 | 
					    <addaction name="actionTop"/>
 | 
				
			||||||
 | 
					   </widget>
 | 
				
			||||||
   <addaction name="menuFile"/>
 | 
					   <addaction name="menuFile"/>
 | 
				
			||||||
 | 
					   <addaction name="menuGo"/>
 | 
				
			||||||
  </widget>
 | 
					  </widget>
 | 
				
			||||||
  <widget class="QStatusBar" name="statusbar"/>
 | 
					  <widget class="QStatusBar" name="statusbar"/>
 | 
				
			||||||
  <action name="actionOpen">
 | 
					  <action name="actionOpen">
 | 
				
			||||||
| 
						 | 
					@ -81,6 +91,38 @@
 | 
				
			||||||
    <string>&Close</string>
 | 
					    <string>&Close</string>
 | 
				
			||||||
   </property>
 | 
					   </property>
 | 
				
			||||||
  </action>
 | 
					  </action>
 | 
				
			||||||
 | 
					  <action name="actionUp">
 | 
				
			||||||
 | 
					   <property name="icon">
 | 
				
			||||||
 | 
					    <iconset theme="go-up"/>
 | 
				
			||||||
 | 
					   </property>
 | 
				
			||||||
 | 
					   <property name="text">
 | 
				
			||||||
 | 
					    <string>Up</string>
 | 
				
			||||||
 | 
					   </property>
 | 
				
			||||||
 | 
					  </action>
 | 
				
			||||||
 | 
					  <action name="actionBack">
 | 
				
			||||||
 | 
					   <property name="icon">
 | 
				
			||||||
 | 
					    <iconset theme="go-previous"/>
 | 
				
			||||||
 | 
					   </property>
 | 
				
			||||||
 | 
					   <property name="text">
 | 
				
			||||||
 | 
					    <string>Back</string>
 | 
				
			||||||
 | 
					   </property>
 | 
				
			||||||
 | 
					  </action>
 | 
				
			||||||
 | 
					  <action name="actionForward">
 | 
				
			||||||
 | 
					   <property name="icon">
 | 
				
			||||||
 | 
					    <iconset theme="go-next"/>
 | 
				
			||||||
 | 
					   </property>
 | 
				
			||||||
 | 
					   <property name="text">
 | 
				
			||||||
 | 
					    <string>Forward</string>
 | 
				
			||||||
 | 
					   </property>
 | 
				
			||||||
 | 
					  </action>
 | 
				
			||||||
 | 
					  <action name="actionTop">
 | 
				
			||||||
 | 
					   <property name="icon">
 | 
				
			||||||
 | 
					    <iconset theme="go-top"/>
 | 
				
			||||||
 | 
					   </property>
 | 
				
			||||||
 | 
					   <property name="text">
 | 
				
			||||||
 | 
					    <string>Top</string>
 | 
				
			||||||
 | 
					   </property>
 | 
				
			||||||
 | 
					  </action>
 | 
				
			||||||
 </widget>
 | 
					 </widget>
 | 
				
			||||||
 <resources/>
 | 
					 <resources/>
 | 
				
			||||||
 <connections>
 | 
					 <connections>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,18 +1,8 @@
 | 
				
			||||||
#include "quam/pack.h"
 | 
					#include "quam/pack.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct PackHeader {
 | 
					 | 
				
			||||||
	quint32 dirOffset;
 | 
					 | 
				
			||||||
	quint32 dirNum;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct PackEntry {
 | 
					 | 
				
			||||||
	std::string name;
 | 
					 | 
				
			||||||
	Arc::File   file;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static constexpr quint32 sizeOfPackEntry = 64;
 | 
					static constexpr quint32 sizeOfPackEntry = 64;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static PackHeader readPackHeader(std::istream &st) {
 | 
					static std::pair<quint32, quint32> readPackHeader(std::istream &st) {
 | 
				
			||||||
	auto magic = readBytes<4>(st);
 | 
						auto magic = readBytes<4>(st);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if(magic != std::array{'P', 'A', 'C', 'K'}) {
 | 
						if(magic != std::array{'P', 'A', 'C', 'K'}) {
 | 
				
			||||||
| 
						 | 
					@ -26,13 +16,10 @@ static PackHeader readPackHeader(std::istream &st) {
 | 
				
			||||||
		throw FileFormatError("invalid directory size");
 | 
							throw FileFormatError("invalid directory size");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	PackHeader hdr;
 | 
						return std::make_pair(dirOffset, dirSize / sizeOfPackEntry);
 | 
				
			||||||
	hdr.dirOffset = dirOffset;
 | 
					 | 
				
			||||||
	hdr.dirNum    = dirSize / sizeOfPackEntry;
 | 
					 | 
				
			||||||
	return hdr;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static PackEntry readPackEntry(std::istream &st) {
 | 
					static Arc::File readPackEntry(std::istream &st) {
 | 
				
			||||||
	auto entName   = readBytes<56>(st);
 | 
						auto entName   = readBytes<56>(st);
 | 
				
			||||||
	auto entOffset = readLE<quint32>(st);
 | 
						auto entOffset = readLE<quint32>(st);
 | 
				
			||||||
	auto entSize   = readLE<quint32>(st);
 | 
						auto entSize   = readLE<quint32>(st);
 | 
				
			||||||
| 
						 | 
					@ -41,25 +28,20 @@ static PackEntry readPackEntry(std::istream &st) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	st.seekg(entOffset);
 | 
						st.seekg(entOffset);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Arc::File file;
 | 
						Arc::File file{ntbsToString(entName)};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	file.resize(entSize);
 | 
						file.resize(entSize);
 | 
				
			||||||
	st.read(file.data(), entSize);
 | 
						st.read(file.data(), entSize);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	st.seekg(pos);
 | 
						st.seekg(pos);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	std::string name = ntbsToString(entName);
 | 
						if(file.name.front() == '/') {
 | 
				
			||||||
 | 
					 | 
				
			||||||
	if(name.front() == '/') {
 | 
					 | 
				
			||||||
		throw FileFormatError("empty root directory name");
 | 
							throw FileFormatError("empty root directory name");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	PackEntry ent;
 | 
						return file;
 | 
				
			||||||
	ent.name = std::move(name);
 | 
					 | 
				
			||||||
	ent.file = std::move(file);
 | 
					 | 
				
			||||||
	return ent;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void insertFile(Arc::Dir &dir, std::string &name, Arc::File &file) {
 | 
					static void insertFile(Arc::Dir &dir, Arc::File &file, std::string name) {
 | 
				
			||||||
	Option<std::string> next;
 | 
						Option<std::string> next;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if(auto slash = name.find('/'); slash != std::string::npos) {
 | 
						if(auto slash = name.find('/'); slash != std::string::npos) {
 | 
				
			||||||
| 
						 | 
					@ -69,11 +51,16 @@ static void insertFile(Arc::Dir &dir, std::string &name, Arc::File &file) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	auto existing = dir.findNode(name);
 | 
						auto existing = dir.findNode(name);
 | 
				
			||||||
	if(next) {
 | 
						if(next) {
 | 
				
			||||||
		auto &ref = existing ? *existing
 | 
							Arc::Node *ref;
 | 
				
			||||||
		                     : dir.emplace_back(Arc::Dir{}, std::move(name));
 | 
							if(existing) {
 | 
				
			||||||
		insertFile(std::get<Arc::Dir>(ref), *next, file);
 | 
								ref = existing;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								ref = &*dir.emplace_back(new Arc::Dir(name, &dir));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							insertFile(*ref->getDir(), file, *next);
 | 
				
			||||||
	} else if(!existing) {
 | 
						} else if(!existing) {
 | 
				
			||||||
		dir.emplace_back(std::move(file), std::move(name));
 | 
							file.name = name;
 | 
				
			||||||
 | 
							dir.emplace_back(new Arc::File(std::move(file)));
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		throw FileFormatError("duplicate file");
 | 
							throw FileFormatError("duplicate file");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -81,13 +68,13 @@ static void insertFile(Arc::Dir &dir, std::string &name, Arc::File &file) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Arc::Dir readPack(std::istream &st) {
 | 
					Arc::Dir readPack(std::istream &st) {
 | 
				
			||||||
	auto hdr = readPackHeader(st);
 | 
						auto hdr = readPackHeader(st);
 | 
				
			||||||
	st.seekg(hdr.dirOffset);
 | 
						st.seekg(hdr.first);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Arc::Dir root;
 | 
						Arc::Dir root{std::string{}};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for(quint32 i = 0; i < hdr.dirNum; i++) {
 | 
						for(quint32 i = 0; i < hdr.second; i++) {
 | 
				
			||||||
		auto ent = readPackEntry(st);
 | 
							auto file = readPackEntry(st);
 | 
				
			||||||
		insertFile(root, ent.name, ent.file);
 | 
							insertFile(root, file, file.name);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return root;
 | 
						return root;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,7 +10,6 @@ Project::Project(std::istream &st, QErrorMessage *errors, QMdiArea *parent) :
 | 
				
			||||||
	Ui::Project{},
 | 
						Ui::Project{},
 | 
				
			||||||
	m_arc{new Arc::Arc{st, this}},
 | 
						m_arc{new Arc::Arc{st, this}},
 | 
				
			||||||
	m_root{&m_arc->root},
 | 
						m_root{&m_arc->root},
 | 
				
			||||||
	m_lastDir{nullptr},
 | 
					 | 
				
			||||||
	m_errors{errors},
 | 
						m_errors{errors},
 | 
				
			||||||
	m_model{new Arc::Model{this}},
 | 
						m_model{new Arc::Model{this}},
 | 
				
			||||||
	m_sorter{new QSortFilterProxyModel{this}}
 | 
						m_sorter{new QSortFilterProxyModel{this}}
 | 
				
			||||||
| 
						 | 
					@ -26,6 +25,7 @@ Project::Project(std::istream &st, QErrorMessage *errors, QMdiArea *parent) :
 | 
				
			||||||
	connect(tableView, &QAbstractItemView::doubleClicked,
 | 
						connect(tableView, &QAbstractItemView::doubleClicked,
 | 
				
			||||||
	        m_model,   &Arc::Model::setDirToIndex);
 | 
						        m_model,   &Arc::Model::setDirToIndex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dirName->setValidator(m_arc->validator);
 | 
				
			||||||
	m_sorter->setSourceModel(m_model);
 | 
						m_sorter->setSourceModel(m_model);
 | 
				
			||||||
	tableView->setModel(m_sorter);
 | 
						tableView->setModel(m_sorter);
 | 
				
			||||||
	m_model->setDir(m_root);
 | 
						m_model->setDir(m_root);
 | 
				
			||||||
| 
						 | 
					@ -35,8 +35,11 @@ Project::~Project() {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Project::dirChanged(Arc::Dir *from, Arc::Dir *to) {
 | 
					void Project::dirChanged(Arc::Dir *from, Arc::Dir *to) {
 | 
				
			||||||
	m_lastDir = from;
 | 
					 | 
				
			||||||
	tableView->resizeColumnsToContents();
 | 
						tableView->resizeColumnsToContents();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool Project::dirUp() {
 | 
				
			||||||
 | 
						return m_model->dirUp();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// EOF
 | 
					// EOF
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -20,12 +20,15 @@ public:
 | 
				
			||||||
	explicit Project(std::istream &st, QErrorMessage *errors, QMdiArea *parent);
 | 
						explicit Project(std::istream &st, QErrorMessage *errors, QMdiArea *parent);
 | 
				
			||||||
	virtual ~Project();
 | 
						virtual ~Project();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public slots:
 | 
				
			||||||
 | 
						bool dirUp();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private slots:
 | 
					private slots:
 | 
				
			||||||
	void dirChanged(Arc::Dir *from, Arc::Dir *to);
 | 
						void dirChanged(Arc::Dir *from, Arc::Dir *to);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
	Arc::Arc              *m_arc;
 | 
						Arc::Arc              *m_arc;
 | 
				
			||||||
	Arc::Dir              *m_root, *m_lastDir;
 | 
						Arc::Dir              *m_root;
 | 
				
			||||||
	QErrorMessage         *m_errors;
 | 
						QErrorMessage         *m_errors;
 | 
				
			||||||
	Arc::Model            *m_model;
 | 
						Arc::Model            *m_model;
 | 
				
			||||||
	QSortFilterProxyModel *m_sorter;
 | 
						QSortFilterProxyModel *m_sorter;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -22,21 +22,7 @@
 | 
				
			||||||
     <widget class="QWidget" name="">
 | 
					     <widget class="QWidget" name="">
 | 
				
			||||||
      <layout class="QVBoxLayout" name="verticalLayout_3">
 | 
					      <layout class="QVBoxLayout" name="verticalLayout_3">
 | 
				
			||||||
       <item>
 | 
					       <item>
 | 
				
			||||||
        <layout class="QHBoxLayout" name="horizontalLayout_2">
 | 
					        <widget class="QLineEdit" name="dirName"/>
 | 
				
			||||||
         <item>
 | 
					 | 
				
			||||||
          <widget class="QLineEdit" name="dirName"/>
 | 
					 | 
				
			||||||
         </item>
 | 
					 | 
				
			||||||
         <item>
 | 
					 | 
				
			||||||
          <widget class="QPushButton" name="buttonUp">
 | 
					 | 
				
			||||||
           <property name="icon">
 | 
					 | 
				
			||||||
            <iconset theme="go-up"/>
 | 
					 | 
				
			||||||
           </property>
 | 
					 | 
				
			||||||
           <property name="flat">
 | 
					 | 
				
			||||||
            <bool>true</bool>
 | 
					 | 
				
			||||||
           </property>
 | 
					 | 
				
			||||||
          </widget>
 | 
					 | 
				
			||||||
         </item>
 | 
					 | 
				
			||||||
        </layout>
 | 
					 | 
				
			||||||
       </item>
 | 
					       </item>
 | 
				
			||||||
       <item>
 | 
					       <item>
 | 
				
			||||||
        <widget class="QTableView" name="tableView">
 | 
					        <widget class="QTableView" name="tableView">
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,17 +7,6 @@ namespace Wad2 {
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct Wad2Header {
 | 
					 | 
				
			||||||
	quint32 dirNum;
 | 
					 | 
				
			||||||
	quint32 dirOffset;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct Wad2Entry {
 | 
					 | 
				
			||||||
	std::string   name;
 | 
					 | 
				
			||||||
	Arc::FileType type;
 | 
					 | 
				
			||||||
	Arc::File     file;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static Arc::FileType getFileType(int n) {
 | 
					static Arc::FileType getFileType(int n) {
 | 
				
			||||||
	switch(n) {
 | 
						switch(n) {
 | 
				
			||||||
		case 0:  return Arc::FileType::Normal;
 | 
							case 0:  return Arc::FileType::Normal;
 | 
				
			||||||
| 
						 | 
					@ -31,20 +20,19 @@ static Arc::FileType getFileType(int n) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static Wad2Header readWad2Header(std::istream &st) {
 | 
					static std::pair<quint32, quint32> readWad2Header(std::istream &st) {
 | 
				
			||||||
	auto magic = readBytes<4>(st);
 | 
						auto magic = readBytes<4>(st);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if(magic != std::array{'W', 'A', 'D', '2'}) {
 | 
						if(magic != std::array{'W', 'A', 'D', '2'}) {
 | 
				
			||||||
		throw FileFormatError("not a wad2 file (invalid magic number)");
 | 
							throw FileFormatError("not a wad2 file (invalid magic number)");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Wad2Header hdr;
 | 
						auto dirNum    = readLE<quint32>(st);
 | 
				
			||||||
	hdr.dirNum    = readLE<quint32>(st);
 | 
						auto dirOffset = readLE<quint32>(st);
 | 
				
			||||||
	hdr.dirOffset = readLE<quint32>(st);
 | 
						return std::make_pair(dirOffset, dirNum);
 | 
				
			||||||
	return hdr;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static Wad2Entry readWad2Entry(std::istream &st) {
 | 
					static Arc::File readWad2Entry(std::istream &st) {
 | 
				
			||||||
	auto entOffset = readLE<quint32>(st);
 | 
						auto entOffset = readLE<quint32>(st);
 | 
				
			||||||
	auto entSize   = readLE<quint32>(st);
 | 
						auto entSize   = readLE<quint32>(st);
 | 
				
			||||||
	auto entCSize  = readLE<quint32>(st);
 | 
						auto entCSize  = readLE<quint32>(st);
 | 
				
			||||||
| 
						 | 
					@ -61,28 +49,25 @@ static Wad2Entry readWad2Entry(std::istream &st) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	st.seekg(entOffset);
 | 
						st.seekg(entOffset);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Arc::File file;
 | 
						Arc::File file{ntbsToString(entName)};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	file.resize(entSize);
 | 
						file.resize(entSize);
 | 
				
			||||||
	st.read(file.data(), entSize);
 | 
						st.read(file.data(), entSize);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	st.seekg(pos);
 | 
						st.seekg(pos);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Wad2Entry ent;
 | 
						file.type = getFileType(entType);
 | 
				
			||||||
	ent.name = ntbsToString(entName);
 | 
					
 | 
				
			||||||
	ent.file = std::move(file);
 | 
						return file;
 | 
				
			||||||
	ent.type = getFileType(entType);
 | 
					 | 
				
			||||||
	return ent;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Arc::Dir readWad2(std::istream &st) {
 | 
					Arc::Dir readWad2(std::istream &st) {
 | 
				
			||||||
	auto hdr = readWad2Header(st);
 | 
						auto hdr = readWad2Header(st);
 | 
				
			||||||
	st.seekg(hdr.dirOffset);
 | 
						st.seekg(hdr.first);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Arc::Dir root;
 | 
						Arc::Dir root{std::string{}};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for(quint32 i = 0; i < hdr.dirNum; i++) {
 | 
						for(quint32 i = 0; i < hdr.second; i++) {
 | 
				
			||||||
		auto ent = readWad2Entry(st);
 | 
							root.emplace_back(new Arc::File(readWad2Entry(st)));
 | 
				
			||||||
		root.emplace_back(std::move(ent.file), std::move(ent.name), ent.type);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return root;
 | 
						return root;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user