mirror of
https://github.com/OpenMW/openmw.git
synced 2025-03-03 02:09:41 +00:00
Support TES4 in esmtool dump
This commit is contained in:
parent
4b28d51d5e
commit
d2510284ec
10 changed files with 606 additions and 48 deletions
|
@ -4,6 +4,9 @@ set(ESMTOOL
|
|||
labels.cpp
|
||||
record.hpp
|
||||
record.cpp
|
||||
arguments.hpp
|
||||
tes4.hpp
|
||||
tes4.cpp
|
||||
)
|
||||
source_group(apps\\esmtool FILES ${ESMTOOL})
|
||||
|
||||
|
|
28
apps/esmtool/arguments.hpp
Normal file
28
apps/esmtool/arguments.hpp
Normal file
|
@ -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"
|
||||
|
||||
#define ESMTOOL_VERSION 1.2
|
||||
namespace
|
||||
{
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
329
apps/esmtool/tes4.cpp
Normal file
329
apps/esmtool/tes4.cpp
Normal file
|
@ -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;
|
||||
}
|
||||
}
|
15
apps/esmtool/tes4.hpp
Normal file
15
apps/esmtool/tes4.hpp
Normal file
|
@ -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
|
||||
|
|
40
components/esm/format.cpp
Normal file
40
components/esm/format.cpp
Normal file
|
@ -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);
|
||||
}
|
||||
}
|
23
components/esm/format.hpp
Normal file
23
components/esm/format.hpp
Normal file
|
@ -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
|
||||
|
|
84
components/esm4/records.hpp
Normal file
84
components/esm4/records.hpp
Normal file
|
@ -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…
Reference in a new issue