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