Support TES4 in esmtool dump

pull/3226/head
elsid 2 years ago
parent 4b28d51d5e
commit d2510284ec
No known key found for this signature in database
GPG Key ID: B845CB9FEE18AB40

@ -4,6 +4,9 @@ set(ESMTOOL
labels.cpp
record.hpp
record.cpp
arguments.hpp
tes4.hpp
tes4.cpp
)
source_group(apps\\esmtool FILES ${ESMTOOL})

@ -0,0 +1,28 @@
#ifndef OPENMW_ESMTOOL_ARGUMENTS_H
#define OPENMW_ESMTOOL_ARGUMENTS_H
#include <vector>
#include <optional>
#include <components/esm/format.hpp>
namespace EsmTool
{
struct Arguments
{
std::optional<ESM::Format> mRawFormat;
bool quiet_given;
bool loadcells_given;
bool plain_given;
std::string mode;
std::string encoding;
std::string filename;
std::string outname;
std::vector<std::string> types;
std::string name;
};
}
#endif

@ -7,17 +7,29 @@
#include <fstream>
#include <cmath>
#include <memory>
#include <optional>
#include <iomanip>
#include <boost/program_options.hpp>
#include <components/esm3/esmreader.hpp>
#include <components/esm3/esmwriter.hpp>
#include <components/esm/records.hpp>
#include <components/esm/format.hpp>
#include <components/files/openfile.hpp>
#include "record.hpp"
#include "labels.hpp"
#include "arguments.hpp"
#include "tes4.hpp"
namespace
{
#define ESMTOOL_VERSION 1.2
using namespace EsmTool;
constexpr unsigned majorVersion = 1;
constexpr unsigned minorVersion = 3;
// Create a local alias for brevity
namespace bpo = boost::program_options;
@ -36,23 +48,6 @@ struct ESMData
};
// Based on the legacy struct
struct Arguments
{
bool raw_given;
bool quiet_given;
bool loadcells_given;
bool plain_given;
std::string mode;
std::string encoding;
std::string filename;
std::string outname;
std::vector<std::string> types;
std::string name;
};
bool parseOptions (int argc, char** argv, Arguments &info)
{
bpo::options_description desc("Inspect and extract from Morrowind ES files (ESM, ESP, ESS)\nSyntax: esmtool [options] mode infile [outfile]\nAllowed modes:\n dump\t Dumps all readable data from the input file.\n clone\t Clones the input file to the output file.\n comp\t Compares the given files.\n\nAllowed options");
@ -60,7 +55,10 @@ bool parseOptions (int argc, char** argv, Arguments &info)
desc.add_options()
("help,h", "print help message.")
("version,v", "print version information and quit.")
("raw,r", "Show an unformatted list of all records and subrecords.")
("raw,r", bpo::value<std::string>(),
"Show an unformatted list of all records and subrecords of given format:\n"
"\n\tTES3"
"\n\tTES4")
// The intention is that this option would interact better
// with other modes including clone, dump, and raw.
("type,t", bpo::value< std::vector<std::string> >(),
@ -122,7 +120,7 @@ bool parseOptions (int argc, char** argv, Arguments &info)
}
if (variables.count ("version"))
{
std::cout << "ESMTool version " << ESMTOOL_VERSION << std::endl;
std::cout << "ESMTool version " << majorVersion << '.' << minorVersion << std::endl;
return false;
}
if (!variables.count("mode"))
@ -164,7 +162,9 @@ bool parseOptions (int argc, char** argv, Arguments &info)
if (variables["input-file"].as< std::vector<std::string> >().size() > 1)
info.outname = variables["input-file"].as< std::vector<std::string> >()[1];
info.raw_given = variables.count ("raw") != 0;
if (const auto it = variables.find("raw"); it != variables.end())
info.mRawFormat = ESM::parseFormat(it->second.as<std::string>());
info.quiet_given = variables.count ("quiet") != 0;
info.loadcells_given = variables.count ("loadcells") != 0;
info.plain_given = variables.count("plain") != 0;
@ -181,13 +181,14 @@ bool parseOptions (int argc, char** argv, Arguments &info)
return true;
}
void printRaw(ESM::ESMReader &esm);
void loadCell(const Arguments& info, ESM::Cell &cell, ESM::ESMReader &esm, ESMData* data);
int load(const Arguments& info, ESMData* data);
int clone(const Arguments& info);
int comp(const Arguments& info);
}
int main(int argc, char**argv)
{
try
@ -217,6 +218,9 @@ int main(int argc, char**argv)
return 0;
}
namespace
{
void loadCell(const Arguments& info, ESM::Cell &cell, ESM::ESMReader &esm, ESMData* data)
{
bool quiet = (info.quiet_given || info.mode == "clone");
@ -284,8 +288,11 @@ void loadCell(const Arguments& info, ESM::Cell &cell, ESM::ESMReader &esm, ESMDa
}
}
void printRaw(ESM::ESMReader &esm)
void printRawTes3(const std::string& path)
{
std::cout << "TES3 RAW file listing: " << path << '\n';
ESM::ESMReader esm;
esm.openRaw(path);
while(esm.hasMoreRecs())
{
ESM::NAME n = esm.getRecName();
@ -305,35 +312,23 @@ void printRaw(ESM::ESMReader &esm)
}
}
int load(const Arguments& info, ESMData* data)
int loadTes3(const Arguments& info, std::unique_ptr<std::ifstream>&& stream, ESMData* data)
{
std::cout << "Loading TES3 file: " << info.filename << '\n';
ESM::ESMReader esm;
ToUTF8::Utf8Encoder encoder (ToUTF8::calculateEncoding(info.encoding));
esm.setEncoder(&encoder);
std::string filename = info.filename;
std::cout << "Loading file: " << filename << '\n';
std::unordered_set<uint32_t> skipped;
try {
if(info.raw_given && info.mode == "dump")
{
std::cout << "RAW file listing:\n";
esm.openRaw(filename);
printRaw(esm);
return 0;
}
try
{
bool quiet = (info.quiet_given || info.mode == "clone");
bool loadCells = (info.loadcells_given || info.mode == "clone");
bool save = (info.mode == "clone");
esm.open(filename);
esm.open(std::move(stream), info.filename);
if (data != nullptr)
{
@ -422,7 +417,49 @@ int load(const Arguments& info, ESMData* data)
return 0;
}
#include <iomanip>
int load(const Arguments& info, ESMData* data)
{
if (info.mRawFormat.has_value() && info.mode == "dump")
{
switch (*info.mRawFormat)
{
case ESM::Format::Tes3:
printRawTes3(info.filename);
break;
case ESM::Format::Tes4:
std::cout << "Printing raw TES4 file is not supported: " << info.filename << "\n";
break;
}
return 0;
}
auto stream = Files::openBinaryInputFileStream(info.filename);
if (!stream->is_open())
{
std::cout << "Failed to open file: " << std::strerror(errno) << '\n';
return -1;
}
const ESM::Format format = ESM::readFormat(*stream);
stream->seekg(0);
switch (format)
{
case ESM::Format::Tes3:
return loadTes3(info, std::move(stream), data);
case ESM::Format::Tes4:
if (data != nullptr)
{
std::cout << "Collecting data from esm file is not supported for TES4\n";
return -1;
}
return loadTes4(info, std::move(stream));
}
std::cout << "Unsupported ESM format: " << ESM::NAME(format).toStringView() << '\n';
return -1;
}
int clone(const Arguments& info)
{
@ -526,9 +563,6 @@ int comp(const Arguments& info)
Arguments fileOne;
Arguments fileTwo;
fileOne.raw_given = false;
fileTwo.raw_given = false;
fileOne.mode = "clone";
fileTwo.mode = "clone";
@ -560,3 +594,5 @@ int comp(const Arguments& info)
return 0;
}
}

@ -0,0 +1,329 @@
#include "tes4.hpp"
#include "arguments.hpp"
#include "labels.hpp"
#include <fstream>
#include <iostream>
#include <type_traits>
#include <components/esm/esmcommon.hpp>
#include <components/esm4/reader.hpp>
#include <components/esm4/records.hpp>
namespace EsmTool
{
namespace
{
struct Params
{
const bool mQuite;
explicit Params(const Arguments& info)
: mQuite(info.quiet_given || info.mode == "clone")
{}
};
std::string toString(ESM4::GroupType type)
{
switch (type)
{
case ESM4::Grp_RecordType: return "RecordType";
case ESM4::Grp_WorldChild: return "WorldChild";
case ESM4::Grp_InteriorCell: return "InteriorCell";
case ESM4::Grp_InteriorSubCell: return "InteriorSubCell";
case ESM4::Grp_ExteriorCell: return "ExteriorCell";
case ESM4::Grp_ExteriorSubCell: return "ExteriorSubCell";
case ESM4::Grp_CellChild: return "CellChild";
case ESM4::Grp_TopicChild: return "TopicChild";
case ESM4::Grp_CellPersistentChild: return "CellPersistentChild";
case ESM4::Grp_CellTemporaryChild: return "CellTemporaryChild";
case ESM4::Grp_CellVisibleDistChild: return "CellVisibleDistChild";
}
return "Unknown (" + std::to_string(type) + ")";
}
template <class T, class = std::void_t<>>
struct HasFormId : std::false_type {};
template <class T>
struct HasFormId<T, std::void_t<decltype(T::mFormId)>> : std::true_type {};
template <class T>
constexpr bool hasFormId = HasFormId<T>::value;
template <class T, class = std::void_t<>>
struct HasFlags : std::false_type {};
template <class T>
struct HasFlags<T, std::void_t<decltype(T::mFlags)>> : std::true_type {};
template <class T>
constexpr bool hasFlags = HasFlags<T>::value;
template <class T>
void readTypedRecord(const Params& params, ESM4::Reader& reader)
{
reader.getRecordData();
T value;
value.load(reader);
if (params.mQuite)
return;
std::cout << "\n Record: " << ESM::NAME(reader.hdr().record.typeId).toStringView();
if constexpr (hasFormId<T>)
std::cout << ' ' << value.mFormId;
if constexpr (hasFlags<T>)
std::cout << "\n Record flags: " << recordFlags(value.mFlags);
std::cout << '\n';
}
void readRecord(const Params& params, ESM4::Reader& reader)
{
switch (static_cast<ESM4::RecordTypes>(reader.hdr().record.typeId))
{
case ESM4::REC_AACT: break;
case ESM4::REC_ACHR: return readTypedRecord<ESM4::ActorCharacter>(params, reader);
case ESM4::REC_ACRE: return readTypedRecord<ESM4::ActorCreature>(params, reader);
case ESM4::REC_ACTI: return readTypedRecord<ESM4::Activator>(params, reader);
case ESM4::REC_ADDN: break;
case ESM4::REC_ALCH: return readTypedRecord<ESM4::Potion>(params, reader);
case ESM4::REC_ALOC: return readTypedRecord<ESM4::MediaLocationController>(params, reader);
case ESM4::REC_AMMO: return readTypedRecord<ESM4::Ammunition>(params, reader);
case ESM4::REC_ANIO: return readTypedRecord<ESM4::AnimObject>(params, reader);
case ESM4::REC_APPA: return readTypedRecord<ESM4::Apparatus>(params, reader);
case ESM4::REC_ARMA: return readTypedRecord<ESM4::ArmorAddon>(params, reader);
case ESM4::REC_ARMO: return readTypedRecord<ESM4::Armor>(params, reader);
case ESM4::REC_ARTO: break;
case ESM4::REC_ASPC: return readTypedRecord<ESM4::AcousticSpace>(params, reader);
case ESM4::REC_ASTP: break;
case ESM4::REC_AVIF: break;
case ESM4::REC_BOOK: return readTypedRecord<ESM4::Book>(params, reader);
case ESM4::REC_BPTD: return readTypedRecord<ESM4::BodyPartData>(params, reader);
case ESM4::REC_CAMS: break;
case ESM4::REC_CCRD: break;
case ESM4::REC_CELL: return readTypedRecord<ESM4::Cell>(params, reader);
case ESM4::REC_CLAS: return readTypedRecord<ESM4::Class>(params, reader);
case ESM4::REC_CLFM: return readTypedRecord<ESM4::Colour>(params, reader);
case ESM4::REC_CLMT: break;
case ESM4::REC_CLOT: return readTypedRecord<ESM4::Clothing>(params, reader);
case ESM4::REC_CMNY: break;
case ESM4::REC_COBJ: break;
case ESM4::REC_COLL: break;
case ESM4::REC_CONT: return readTypedRecord<ESM4::Container>(params, reader);
case ESM4::REC_CPTH: break;
case ESM4::REC_CREA: return readTypedRecord<ESM4::Creature>(params, reader);
case ESM4::REC_CSTY: break;
case ESM4::REC_DEBR: break;
case ESM4::REC_DIAL: return readTypedRecord<ESM4::Dialogue>(params, reader);
case ESM4::REC_DLBR: break;
case ESM4::REC_DLVW: break;
case ESM4::REC_DOBJ: return readTypedRecord<ESM4::DefaultObj>(params, reader);
case ESM4::REC_DOOR: return readTypedRecord<ESM4::Door>(params, reader);
case ESM4::REC_DUAL: break;
case ESM4::REC_ECZN: break;
case ESM4::REC_EFSH: break;
case ESM4::REC_ENCH: break;
case ESM4::REC_EQUP: break;
case ESM4::REC_EXPL: break;
case ESM4::REC_EYES: return readTypedRecord<ESM4::Eyes>(params, reader);
case ESM4::REC_FACT: break;
case ESM4::REC_FLOR: return readTypedRecord<ESM4::Flora>(params, reader);
case ESM4::REC_FLST: return readTypedRecord<ESM4::FormIdList>(params, reader);
case ESM4::REC_FSTP: break;
case ESM4::REC_FSTS: break;
case ESM4::REC_FURN: return readTypedRecord<ESM4::Furniture>(params, reader);
case ESM4::REC_GLOB: return readTypedRecord<ESM4::GlobalVariable>(params, reader);
case ESM4::REC_GMST: break;
case ESM4::REC_GRAS: return readTypedRecord<ESM4::Grass>(params, reader);
case ESM4::REC_GRUP: break;
case ESM4::REC_HAIR: return readTypedRecord<ESM4::Hair>(params, reader);
case ESM4::REC_HAZD: break;
case ESM4::REC_HDPT: return readTypedRecord<ESM4::HeadPart>(params, reader);
case ESM4::REC_IDLE:
// FIXME: ESM4::IdleAnimation::load does not work with Oblivion.esm
// return readTypedRecord<ESM4::IdleAnimation>(params, reader);
break;
case ESM4::REC_IDLM: return readTypedRecord<ESM4::IdleMarker>(params, reader);
case ESM4::REC_IMAD: break;
case ESM4::REC_IMGS: break;
case ESM4::REC_IMOD: return readTypedRecord<ESM4::ItemMod>(params, reader);
case ESM4::REC_INFO: return readTypedRecord<ESM4::DialogInfo>(params, reader);
case ESM4::REC_INGR: return readTypedRecord<ESM4::Ingredient>(params, reader);
case ESM4::REC_IPCT: break;
case ESM4::REC_IPDS: break;
case ESM4::REC_KEYM: return readTypedRecord<ESM4::Key>(params, reader);
case ESM4::REC_KYWD: break;
case ESM4::REC_LAND: return readTypedRecord<ESM4::Land>(params, reader);
case ESM4::REC_LCRT: break;
case ESM4::REC_LCTN: break;
case ESM4::REC_LGTM: return readTypedRecord<ESM4::LightingTemplate>(params, reader);
case ESM4::REC_LIGH: return readTypedRecord<ESM4::Light>(params, reader);
case ESM4::REC_LSCR: break;
case ESM4::REC_LTEX: return readTypedRecord<ESM4::LandTexture>(params, reader);
case ESM4::REC_LVLC: return readTypedRecord<ESM4::LevelledCreature>(params, reader);
case ESM4::REC_LVLI: return readTypedRecord<ESM4::LevelledItem>(params, reader);
case ESM4::REC_LVLN: return readTypedRecord<ESM4::LevelledNpc>(params, reader);
case ESM4::REC_LVSP: break;
case ESM4::REC_MATO: return readTypedRecord<ESM4::Material>(params, reader);
case ESM4::REC_MATT: break;
case ESM4::REC_MESG: break;
case ESM4::REC_MGEF: break;
case ESM4::REC_MISC: return readTypedRecord<ESM4::MiscItem>(params, reader);
case ESM4::REC_MOVT: break;
case ESM4::REC_MSET: return readTypedRecord<ESM4::MediaSet>(params, reader);
case ESM4::REC_MSTT: return readTypedRecord<ESM4::MovableStatic>(params, reader);
case ESM4::REC_MUSC: return readTypedRecord<ESM4::Music>(params, reader);
case ESM4::REC_MUST: break;
case ESM4::REC_NAVI: return readTypedRecord<ESM4::Navigation>(params, reader);
case ESM4::REC_NAVM: return readTypedRecord<ESM4::NavMesh>(params, reader);
case ESM4::REC_NOTE: return readTypedRecord<ESM4::Note>(params, reader);
case ESM4::REC_NPC_: return readTypedRecord<ESM4::Npc>(params, reader);
case ESM4::REC_OTFT: return readTypedRecord<ESM4::Outfit>(params, reader);
case ESM4::REC_PACK: return readTypedRecord<ESM4::AIPackage>(params, reader);
case ESM4::REC_PERK: break;
case ESM4::REC_PGRD: return readTypedRecord<ESM4::Pathgrid>(params, reader);
case ESM4::REC_PGRE: return readTypedRecord<ESM4::PlacedGrenade>(params, reader);
case ESM4::REC_PHZD: break;
case ESM4::REC_PROJ: break;
case ESM4::REC_PWAT: return readTypedRecord<ESM4::PlaceableWater>(params, reader);
case ESM4::REC_QUST: return readTypedRecord<ESM4::Quest>(params, reader);
case ESM4::REC_RACE: return readTypedRecord<ESM4::Race>(params, reader);
case ESM4::REC_REFR: return readTypedRecord<ESM4::Reference>(params, reader);
case ESM4::REC_REGN: return readTypedRecord<ESM4::Region>(params, reader);
case ESM4::REC_RELA: break;
case ESM4::REC_REVB: break;
case ESM4::REC_RFCT: break;
case ESM4::REC_ROAD: return readTypedRecord<ESM4::Road>(params, reader);
case ESM4::REC_SBSP: return readTypedRecord<ESM4::SubSpace>(params, reader);
case ESM4::REC_SCEN: break;
case ESM4::REC_SCOL: return readTypedRecord<ESM4::StaticCollection>(params, reader);
case ESM4::REC_SCPT: return readTypedRecord<ESM4::Script>(params, reader);
case ESM4::REC_SCRL: return readTypedRecord<ESM4::Scroll>(params, reader);
case ESM4::REC_SGST: return readTypedRecord<ESM4::SigilStone>(params, reader);
case ESM4::REC_SHOU: break;
case ESM4::REC_SLGM: return readTypedRecord<ESM4::SoulGem>(params, reader);
case ESM4::REC_SMBN: break;
case ESM4::REC_SMEN: break;
case ESM4::REC_SMQN: break;
case ESM4::REC_SNCT: break;
case ESM4::REC_SNDR: return readTypedRecord<ESM4::SoundReference>(params, reader);
case ESM4::REC_SOPM: break;
case ESM4::REC_SOUN: return readTypedRecord<ESM4::Sound>(params, reader);
case ESM4::REC_SPEL: break;
case ESM4::REC_SPGD: break;
case ESM4::REC_STAT: return readTypedRecord<ESM4::Static>(params, reader);
case ESM4::REC_TACT: return readTypedRecord<ESM4::TalkingActivator>(params, reader);
case ESM4::REC_TERM: return readTypedRecord<ESM4::Terminal>(params, reader);
case ESM4::REC_TES4: return readTypedRecord<ESM4::Header>(params, reader);
case ESM4::REC_TREE: return readTypedRecord<ESM4::Tree>(params, reader);
case ESM4::REC_TXST: return readTypedRecord<ESM4::TextureSet>(params, reader);
case ESM4::REC_VTYP: break;
case ESM4::REC_WATR: break;
case ESM4::REC_WEAP: return readTypedRecord<ESM4::Weapon>(params, reader);
case ESM4::REC_WOOP: break;
case ESM4::REC_WRLD: return readTypedRecord<ESM4::World>(params, reader);
case ESM4::REC_WTHR: break;
}
if (!params.mQuite)
std::cout << "\n Unsupported record: " << ESM::NAME(reader.hdr().record.typeId).toStringView() << '\n';
reader.skipRecordData();
}
bool readItem(const Params& params, ESM4::Reader& reader);
bool readGroup(const Params& params, ESM4::Reader& reader)
{
const ESM4::RecordHeader& header = reader.hdr();
if (!params.mQuite)
std::cout << "\nGroup: " << toString(static_cast<ESM4::GroupType>(header.group.type))
<< " " << ESM::NAME(header.group.typeId).toStringView() << '\n';
switch (static_cast<ESM4::GroupType>(header.group.type))
{
case ESM4::Grp_RecordType:
case ESM4::Grp_InteriorCell:
case ESM4::Grp_InteriorSubCell:
case ESM4::Grp_ExteriorCell:
case ESM4::Grp_ExteriorSubCell:
reader.enterGroup();
return readItem(params, reader);
case ESM4::Grp_WorldChild:
case ESM4::Grp_CellChild:
case ESM4::Grp_TopicChild:
case ESM4::Grp_CellPersistentChild:
case ESM4::Grp_CellTemporaryChild:
case ESM4::Grp_CellVisibleDistChild:
reader.adjustGRUPFormId();
reader.enterGroup();
if (!reader.hasMoreRecs())
return false;
return readItem(params, reader);
}
reader.skipGroup();
return true;
}
bool readItem(const Params& params, ESM4::Reader& reader)
{
if (!reader.getRecordHeader() || !reader.hasMoreRecs())
return false;
const ESM4::RecordHeader& header = reader.hdr();
if (header.record.typeId == ESM4::REC_GRUP)
return readGroup(params, reader);
readRecord(params, reader);
return true;
}
}
int loadTes4(const Arguments& info, std::unique_ptr<std::ifstream>&& stream)
{
std::cout << "Loading TES4 file: " << info.filename << '\n';
try
{
const ToUTF8::StatelessUtf8Encoder encoder(ToUTF8::calculateEncoding(info.encoding));
ESM4::Reader reader(std::move(stream), info.filename);
reader.setEncoder(&encoder);
const Params params(info);
if (!params.mQuite)
{
std::cout << "Author: " << reader.getAuthor() << '\n'
<< "Description: " << reader.getDesc() << '\n'
<< "File format version: " << reader.esmVersion() << '\n';
if (const std::vector<ESM::MasterData>& masterData = reader.getGameFiles(); !masterData.empty())
{
std::cout << "Masters:" << '\n';
for (const auto& master : masterData)
std::cout << " " << master.name << ", " << master.size << " bytes\n";
}
}
while (reader.hasMoreRecs())
{
reader.exitGroupCheck();
if (!readItem(params, reader))
break;
}
}
catch (const std::exception& e)
{
std::cout << "\nERROR:\n\n " << e.what() << std::endl;
return -1;
}
return 0;
}
}

@ -0,0 +1,15 @@
#ifndef OPENMW_ESMTOOL_TES4_H
#define OPENMW_ESMTOOL_TES4_H
#include <fstream>
#include <iosfwd>
#include <memory>
namespace EsmTool
{
struct Arguments;
int loadTes4(const Arguments& info, std::unique_ptr<std::ifstream>&& stream);
}
#endif

@ -80,7 +80,7 @@ add_component_dir (to_utf8
to_utf8
)
add_component_dir(esm attr common defs esmcommon reader records util luascripts)
add_component_dir(esm attr common defs esmcommon reader records util luascripts format)
add_component_dir (esm3
esmreader esmwriter loadacti loadalch loadappa loadarmo loadbody loadbook loadbsgn loadcell

@ -0,0 +1,40 @@
#include "format.hpp"
#include <components/esm/esmcommon.hpp>
namespace ESM
{
namespace
{
bool isValidFormat(std::uint32_t value)
{
return value == static_cast<std::uint32_t>(Format::Tes3)
|| value == static_cast<std::uint32_t>(Format::Tes4);
}
Format toFormat(std::uint32_t value)
{
if (!isValidFormat(value))
throw std::runtime_error("Invalid format: " + std::to_string(value));
return static_cast<Format>(value);
}
}
Format readFormat(std::istream& stream)
{
std::uint32_t format = 0;
stream.read(reinterpret_cast<char*>(&format), sizeof(format));
if (stream.gcount() != sizeof(format))
throw std::runtime_error("Not enough bytes to read file header");
return toFormat(format);
}
Format parseFormat(std::string_view value)
{
if (value.size() != sizeof(std::uint32_t))
throw std::logic_error("Invalid format value: " + std::string(value));
std::uint32_t format;
std::memcpy(&format, value.data(), sizeof(std::uint32_t));
return toFormat(format);
}
}

@ -0,0 +1,23 @@
#ifndef COMPONENT_ESM_FORMAT_H
#define COMPONENT_ESM_FORMAT_H
#include "defs.hpp"
#include <cstdint>
#include <istream>
#include <string_view>
namespace ESM
{
enum class Format : std::uint32_t
{
Tes3 = fourCC("TES3"),
Tes4 = fourCC("TES4"),
};
Format readFormat(std::istream& stream);
Format parseFormat(std::string_view value);
}
#endif

@ -76,7 +76,7 @@ namespace ESM4
REC_DOBJ = fourCC("DOBJ"), // Default Object Manager
REC_DOOR = fourCC("DOOR"), // Door
REC_DUAL = fourCC("DUAL"), // Dual Cast Data (possibly unused)
//REC_ECZN = fourCC("ECZN"), // Encounter Zone
REC_ECZN = fourCC("ECZN"), // Encounter Zone
REC_EFSH = fourCC("EFSH"), // Effect Shader
REC_ENCH = fourCC("ENCH"), // Enchantment
REC_EQUP = fourCC("EQUP"), // Equip Slot (flag-type values)
@ -93,7 +93,7 @@ namespace ESM4
REC_GRAS = fourCC("GRAS"), // Grass
REC_GRUP = fourCC("GRUP"), // Form Group
REC_HAIR = fourCC("HAIR"), // Hair
//REC_HAZD = fourCC("HAZD"), // Hazard
REC_HAZD = fourCC("HAZD"), // Hazard
REC_HDPT = fourCC("HDPT"), // Head Part
REC_IDLE = fourCC("IDLE"), // Idle Animation
REC_IDLM = fourCC("IDLM"), // Idle Marker

@ -0,0 +1,84 @@
#ifndef COMPONENTS_ESM4_RECORDS_H
#define COMPONENTS_ESM4_RECORDS_H
#include <components/esm4/loadachr.hpp>
#include <components/esm4/loadacre.hpp>
#include <components/esm4/loadacti.hpp>
#include <components/esm4/loadalch.hpp>
#include <components/esm4/loadaloc.hpp>
#include <components/esm4/loadammo.hpp>
#include <components/esm4/loadanio.hpp>
#include <components/esm4/loadappa.hpp>
#include <components/esm4/loadarma.hpp>
#include <components/esm4/loadarmo.hpp>
#include <components/esm4/loadaspc.hpp>
#include <components/esm4/loadbook.hpp>
#include <components/esm4/loadbptd.hpp>
#include <components/esm4/loadcell.hpp>
#include <components/esm4/loadclas.hpp>
#include <components/esm4/loadclfm.hpp>
#include <components/esm4/loadclot.hpp>
#include <components/esm4/loadcont.hpp>
#include <components/esm4/loadcrea.hpp>
#include <components/esm4/loaddial.hpp>
#include <components/esm4/loaddobj.hpp>
#include <components/esm4/loaddoor.hpp>
#include <components/esm4/loadeyes.hpp>
#include <components/esm4/loadflor.hpp>
#include <components/esm4/loadflst.hpp>
#include <components/esm4/loadfurn.hpp>
#include <components/esm4/loadglob.hpp>
#include <components/esm4/loadgras.hpp>
#include <components/esm4/loadgrup.hpp>
#include <components/esm4/loadhair.hpp>
#include <components/esm4/loadhdpt.hpp>
#include <components/esm4/loadidle.hpp>
#include <components/esm4/loadidlm.hpp>
#include <components/esm4/loadimod.hpp>
#include <components/esm4/loadinfo.hpp>
#include <components/esm4/loadingr.hpp>
#include <components/esm4/loadkeym.hpp>
#include <components/esm4/loadland.hpp>
#include <components/esm4/loadlgtm.hpp>
#include <components/esm4/loadligh.hpp>
#include <components/esm4/loadltex.hpp>
#include <components/esm4/loadlvlc.hpp>
#include <components/esm4/loadlvli.hpp>
#include <components/esm4/loadlvln.hpp>
#include <components/esm4/loadmato.hpp>
#include <components/esm4/loadmisc.hpp>
#include <components/esm4/loadmset.hpp>
#include <components/esm4/loadmstt.hpp>
#include <components/esm4/loadmusc.hpp>
#include <components/esm4/loadnavi.hpp>
#include <components/esm4/loadnavm.hpp>
#include <components/esm4/loadnote.hpp>
#include <components/esm4/loadnpc.hpp>
#include <components/esm4/loadotft.hpp>
#include <components/esm4/loadpack.hpp>
#include <components/esm4/loadpgrd.hpp>
#include <components/esm4/loadpgre.hpp>
#include <components/esm4/loadpwat.hpp>
#include <components/esm4/loadqust.hpp>
#include <components/esm4/loadrace.hpp>
#include <components/esm4/loadrefr.hpp>
#include <components/esm4/loadregn.hpp>
#include <components/esm4/loadroad.hpp>
#include <components/esm4/loadsbsp.hpp>
#include <components/esm4/loadscol.hpp>
#include <components/esm4/loadscpt.hpp>
#include <components/esm4/loadscrl.hpp>
#include <components/esm4/loadsgst.hpp>
#include <components/esm4/loadslgm.hpp>
#include <components/esm4/loadsndr.hpp>
#include <components/esm4/loadsoun.hpp>
#include <components/esm4/loadstat.hpp>
#include <components/esm4/loadtact.hpp>
#include <components/esm4/loadterm.hpp>
#include <components/esm4/loadtes4.hpp>
#include <components/esm4/loadtree.hpp>
#include <components/esm4/loadtxst.hpp>
#include <components/esm4/loadweap.hpp>
#include <components/esm4/loadwrld.hpp>
#endif
Loading…
Cancel
Save