quake-tools/source/quam/wad.cc

82 lines
1.6 KiB
C++

#include "quam/wad.h"
namespace Wad {
enum Compression {
CompressNone,
CompressLZSS,
};
}
struct WadHeader {
quint32 dirOffset;
quint32 dirNum;
};
struct WadEntry {
std::string name;
Arc::FileType type;
ArcFile file;
};
static WadHeader readWadHeader(std::istream &st) {
auto magic = readBytes<4>(st);
if(magic != std::array{'W', 'A', 'D', '2'}) {
throw std::runtime_error("not a wad2 file (invalid magic number)");
}
WadHeader hdr;
hdr.dirOffset = readLE<quint32>(st);
hdr.dirNum = readLE<quint32>(st);
return hdr;
}
static WadEntry readWadEntry(std::istream &st) {
auto entOffset = readLE<quint32>(st);
auto entSize = readLE<quint32>(st);
auto entCSize = readLE<quint32>(st);
auto entType = readByte(st);
auto entCompr = readByte(st);
/* padding */ readBytes<2>(st);
auto entName = readBytes<16>(st);
if(entSize != entCSize || entCompr != Wad::CompressNone) {
throw std::runtime_error("compressed files not implemented");
}
auto pos = st.tellg();
st.seekg(entOffset);
ArcFile file;
file.resize(entSize);
st.read(file.data(), entSize);
st.seekg(pos);
WadEntry ent;
ent.name = ntbsToString(entName);
ent.file = std::move(file);
ent.type = Arc::getFileType(entType);
return ent;
}
ArcDir readWad(std::istream &st) {
auto hdr = readWadHeader(st);
st.seekg(hdr.dirOffset);
ArcDir root;
for(quint32 i = 0; i < hdr.dirNum; i++) {
auto ent = readWadEntry(st);
if(root.findNode(ent.name) != root.end()) {
throw std::runtime_error("duplicate file");
}
root.emplace_back(std::move(ent.file), std::move(ent.name), ent.type);
}
return root;
}
// EOF