Support TES4 in esmtool dump

pull/3226/head
elsid 3 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 labels.cpp
record.hpp record.hpp
record.cpp record.cpp
arguments.hpp
tes4.hpp
tes4.cpp
) )
source_group(apps\\esmtool FILES ${ESMTOOL}) 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 <fstream>
#include <cmath> #include <cmath>
#include <memory> #include <memory>
#include <optional>
#include <iomanip>
#include <boost/program_options.hpp> #include <boost/program_options.hpp>
#include <components/esm3/esmreader.hpp> #include <components/esm3/esmreader.hpp>
#include <components/esm3/esmwriter.hpp> #include <components/esm3/esmwriter.hpp>
#include <components/esm/records.hpp> #include <components/esm/records.hpp>
#include <components/esm/format.hpp>
#include <components/files/openfile.hpp>
#include "record.hpp" #include "record.hpp"
#include "labels.hpp" #include "labels.hpp"
#include "arguments.hpp"
#include "tes4.hpp"
namespace
{
using namespace EsmTool;
#define ESMTOOL_VERSION 1.2 constexpr unsigned majorVersion = 1;
constexpr unsigned minorVersion = 3;
// Create a local alias for brevity // Create a local alias for brevity
namespace bpo = boost::program_options; 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) 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"); 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() desc.add_options()
("help,h", "print help message.") ("help,h", "print help message.")
("version,v", "print version information and quit.") ("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 // The intention is that this option would interact better
// with other modes including clone, dump, and raw. // with other modes including clone, dump, and raw.
("type,t", bpo::value< std::vector<std::string> >(), ("type,t", bpo::value< std::vector<std::string> >(),
@ -122,7 +120,7 @@ bool parseOptions (int argc, char** argv, Arguments &info)
} }
if (variables.count ("version")) if (variables.count ("version"))
{ {
std::cout << "ESMTool version " << ESMTOOL_VERSION << std::endl; std::cout << "ESMTool version " << majorVersion << '.' << minorVersion << std::endl;
return false; return false;
} }
if (!variables.count("mode")) 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) if (variables["input-file"].as< std::vector<std::string> >().size() > 1)
info.outname = variables["input-file"].as< std::vector<std::string> >()[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.quiet_given = variables.count ("quiet") != 0;
info.loadcells_given = variables.count ("loadcells") != 0; info.loadcells_given = variables.count ("loadcells") != 0;
info.plain_given = variables.count("plain") != 0; info.plain_given = variables.count("plain") != 0;
@ -181,13 +181,14 @@ bool parseOptions (int argc, char** argv, Arguments &info)
return true; return true;
} }
void printRaw(ESM::ESMReader &esm);
void loadCell(const Arguments& info, ESM::Cell &cell, ESM::ESMReader &esm, ESMData* data); void loadCell(const Arguments& info, ESM::Cell &cell, ESM::ESMReader &esm, ESMData* data);
int load(const Arguments& info, ESMData* data); int load(const Arguments& info, ESMData* data);
int clone(const Arguments& info); int clone(const Arguments& info);
int comp(const Arguments& info); int comp(const Arguments& info);
}
int main(int argc, char**argv) int main(int argc, char**argv)
{ {
try try
@ -217,6 +218,9 @@ int main(int argc, char**argv)
return 0; return 0;
} }
namespace
{
void loadCell(const Arguments& info, ESM::Cell &cell, ESM::ESMReader &esm, ESMData* data) void loadCell(const Arguments& info, ESM::Cell &cell, ESM::ESMReader &esm, ESMData* data)
{ {
bool quiet = (info.quiet_given || info.mode == "clone"); 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()) while(esm.hasMoreRecs())
{ {
ESM::NAME n = esm.getRecName(); 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; ESM::ESMReader esm;
ToUTF8::Utf8Encoder encoder (ToUTF8::calculateEncoding(info.encoding)); ToUTF8::Utf8Encoder encoder (ToUTF8::calculateEncoding(info.encoding));
esm.setEncoder(&encoder); esm.setEncoder(&encoder);
std::string filename = info.filename;
std::cout << "Loading file: " << filename << '\n';
std::unordered_set<uint32_t> skipped; std::unordered_set<uint32_t> skipped;
try { try
if(info.raw_given && info.mode == "dump")
{ {
std::cout << "RAW file listing:\n";
esm.openRaw(filename);
printRaw(esm);
return 0;
}
bool quiet = (info.quiet_given || info.mode == "clone"); bool quiet = (info.quiet_given || info.mode == "clone");
bool loadCells = (info.loadcells_given || info.mode == "clone"); bool loadCells = (info.loadcells_given || info.mode == "clone");
bool save = (info.mode == "clone"); bool save = (info.mode == "clone");
esm.open(filename); esm.open(std::move(stream), info.filename);
if (data != nullptr) if (data != nullptr)
{ {
@ -422,7 +417,49 @@ int load(const Arguments& info, ESMData* data)
return 0; 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) int clone(const Arguments& info)
{ {
@ -526,9 +563,6 @@ int comp(const Arguments& info)
Arguments fileOne; Arguments fileOne;
Arguments fileTwo; Arguments fileTwo;
fileOne.raw_given = false;
fileTwo.raw_given = false;
fileOne.mode = "clone"; fileOne.mode = "clone";
fileTwo.mode = "clone"; fileTwo.mode = "clone";
@ -560,3 +594,5 @@ int comp(const Arguments& info)
return 0; 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 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 add_component_dir (esm3
esmreader esmwriter loadacti loadalch loadappa loadarmo loadbody loadbook loadbsgn loadcell 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_DOBJ = fourCC("DOBJ"), // Default Object Manager
REC_DOOR = fourCC("DOOR"), // Door REC_DOOR = fourCC("DOOR"), // Door
REC_DUAL = fourCC("DUAL"), // Dual Cast Data (possibly unused) 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_EFSH = fourCC("EFSH"), // Effect Shader
REC_ENCH = fourCC("ENCH"), // Enchantment REC_ENCH = fourCC("ENCH"), // Enchantment
REC_EQUP = fourCC("EQUP"), // Equip Slot (flag-type values) REC_EQUP = fourCC("EQUP"), // Equip Slot (flag-type values)
@ -93,7 +93,7 @@ namespace ESM4
REC_GRAS = fourCC("GRAS"), // Grass REC_GRAS = fourCC("GRAS"), // Grass
REC_GRUP = fourCC("GRUP"), // Form Group REC_GRUP = fourCC("GRUP"), // Form Group
REC_HAIR = fourCC("HAIR"), // Hair REC_HAIR = fourCC("HAIR"), // Hair
//REC_HAZD = fourCC("HAZD"), // Hazard REC_HAZD = fourCC("HAZD"), // Hazard
REC_HDPT = fourCC("HDPT"), // Head Part REC_HDPT = fourCC("HDPT"), // Head Part
REC_IDLE = fourCC("IDLE"), // Idle Animation REC_IDLE = fourCC("IDLE"), // Idle Animation
REC_IDLM = fourCC("IDLM"), // Idle Marker 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