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; | ||||
|  |  | |||
|  | @ -21,23 +21,9 @@ | |||
|      </property> | ||||
|      <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> | ||||
|        </item> | ||||
|        <item> | ||||
|         <widget class="QTableView" name="tableView"> | ||||
|          <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) { | ||||
| 	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