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; | ||||||
|  |  | ||||||
|  | @ -21,23 +21,9 @@ | ||||||
|      </property> |      </property> | ||||||
|      <widget class="QWidget" name=""> |      <widget class="QWidget" name=""> | ||||||
|       <layout class="QVBoxLayout" name="verticalLayout_3"> |       <layout class="QVBoxLayout" name="verticalLayout_3"> | ||||||
|        <item> |  | ||||||
|         <layout class="QHBoxLayout" name="horizontalLayout_2"> |  | ||||||
|        <item> |        <item> | ||||||
|         <widget class="QLineEdit" name="dirName"/> |         <widget class="QLineEdit" name="dirName"/> | ||||||
|        </item> |        </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> | ||||||
|         <widget class="QTableView" name="tableView"> |         <widget class="QTableView" name="tableView"> | ||||||
|          <property name="verticalScrollBarPolicy"> |          <property name="verticalScrollBarPolicy"> | ||||||
|  |  | ||||||
|  | @ -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