From ba602929ef5573942d73721596e07a6a19d0d57c Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Fri, 6 Apr 2012 21:04:30 +0200 Subject: [PATCH 01/14] Adding basic save functions to all record types. --- components/CMakeLists.txt | 2 +- components/esm/defs.hpp | 13 +++++ components/esm/esm_common.hpp | 102 +++++++++++++++++++++++++++++++++ components/esm/esm_reader.hpp | 96 +------------------------------ components/esm/esm_writer.cpp | 28 +++++++++ components/esm/esm_writer.hpp | 71 +++++++++++++++++++++++ components/esm/loadacti.cpp | 9 +++ components/esm/loadacti.hpp | 2 + components/esm/loadalch.cpp | 12 ++++ components/esm/loadalch.hpp | 2 + components/esm/loadappa.cpp | 9 +++ components/esm/loadappa.hpp | 2 + components/esm/loadarmo.cpp | 27 +++++++++ components/esm/loadarmo.hpp | 3 + components/esm/loadbody.cpp | 6 ++ components/esm/loadbody.hpp | 2 + components/esm/loadbook.cpp | 15 +++++ components/esm/loadbook.hpp | 2 + components/esm/loadbsgn.cpp | 10 ++++ components/esm/loadbsgn.hpp | 2 + components/esm/loadcell.cpp | 67 ++++++++++++++++++++++ components/esm/loadcell.hpp | 4 ++ components/esm/loadclas.cpp | 7 +++ components/esm/loadclas.hpp | 2 + components/esm/loadclot.cpp | 17 ++++++ components/esm/loadclot.hpp | 2 + components/esm/loadcont.cpp | 22 +++++++ components/esm/loadcont.hpp | 3 + components/esm/loadcrea.cpp | 16 ++++++ components/esm/loadcrea.hpp | 2 + components/esm/loadcrec.hpp | 9 +++ components/esm/loaddial.cpp | 11 ++++ components/esm/loaddial.hpp | 2 + components/esm/loaddoor.cpp | 12 ++++ components/esm/loaddoor.hpp | 2 + components/esm/loadench.cpp | 5 ++ components/esm/loadench.hpp | 2 + components/esm/loadfact.cpp | 17 ++++++ components/esm/loadfact.hpp | 2 + components/esm/loadglob.cpp | 13 +++++ components/esm/loadglob.hpp | 2 + components/esm/loadgmst.cpp | 10 ++++ components/esm/loadgmst.hpp | 2 + components/esm/loadinfo.cpp | 39 +++++++++++++ components/esm/loadinfo.hpp | 2 + components/esm/loadingr.cpp | 10 ++++ components/esm/loadingr.hpp | 2 + components/esm/loadland.cpp | 26 +++++++++ components/esm/loadland.hpp | 4 ++ components/esm/loadlevlist.cpp | 12 ++++ components/esm/loadlevlist.hpp | 2 + components/esm/loadligh.cpp | 13 +++++ components/esm/loadligh.hpp | 2 + components/esm/loadlocks.cpp | 24 ++++++++ components/esm/loadlocks.hpp | 10 ++++ components/esm/loadltex.cpp | 5 ++ components/esm/loadltex.hpp | 2 + components/esm/loadmgef.cpp | 19 ++++++ components/esm/loadmgef.hpp | 2 + components/esm/loadmisc.cpp | 8 +++ components/esm/loadmisc.hpp | 2 + components/esm/loadnpc.cpp | 30 ++++++++++ components/esm/loadnpc.hpp | 3 + components/esm/loadnpcc.hpp | 4 ++ components/esm/loadpgrd.cpp | 23 ++++++++ components/esm/loadpgrd.hpp | 2 + components/esm/loadrace.cpp | 7 +++ components/esm/loadrace.hpp | 2 + components/esm/loadregn.cpp | 14 +++++ components/esm/loadregn.hpp | 2 + components/esm/loadscpt.cpp | 16 ++++++ components/esm/loadscpt.hpp | 2 + components/esm/loadskil.cpp | 6 ++ components/esm/loadskil.hpp | 2 + components/esm/loadsndg.cpp | 6 ++ components/esm/loadsndg.hpp | 2 + components/esm/loadsoun.cpp | 5 ++ components/esm/loadsoun.hpp | 2 + components/esm/loadspel.cpp | 6 ++ components/esm/loadspel.hpp | 2 + components/esm/loadsscr.cpp | 5 ++ components/esm/loadsscr.hpp | 2 + components/esm/loadstat.cpp | 4 ++ components/esm/loadstat.hpp | 2 + components/esm/loadweap.cpp | 9 +++ components/esm/loadweap.hpp | 2 + 86 files changed, 894 insertions(+), 96 deletions(-) create mode 100644 components/esm/esm_common.hpp create mode 100644 components/esm/esm_writer.cpp create mode 100644 components/esm/esm_writer.hpp diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index b48c50640c..83ebcefe17 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -35,7 +35,7 @@ add_component_dir (esm_store ) add_component_dir (esm - attr defs esm_reader loadacti loadalch loadappa loadarmo loadbody loadbook loadbsgn loadcell + attr defs esm_reader esm_writer loadacti loadalch loadappa loadarmo loadbody loadbook loadbsgn loadcell loadclas loadclot loadcont loadcrea loadcrec loaddial loaddoor loadench loadfact loadglob loadgmst loadinfo loadingr loadland loadlevlist loadligh loadlocks loadltex loadmgef loadmisc loadnpcc loadnpc loadpgrd loadrace loadregn loadscpt loadskil loadsndg loadsoun loadspel loadsscr loadstat diff --git a/components/esm/defs.hpp b/components/esm/defs.hpp index 917c1031fe..a332479069 100644 --- a/components/esm/defs.hpp +++ b/components/esm/defs.hpp @@ -2,6 +2,7 @@ #define _ESM_DEFS_H #include "esm_reader.hpp" +#include "esm_writer.hpp" namespace ESM { @@ -47,6 +48,11 @@ struct SpellList while (esm.isNextSub("NPCS")) list.push_back(esm.getHString()); } + void save(ESMWriter &esm) + { + for (std::vector::iterator it = list.begin(); it != list.end(); ++it) + esm.writeHNString("NPCS", *it); + } }; /** Defines a spell effect. Shared between SPEL (Spells), ALCH @@ -92,6 +98,13 @@ struct EffectList list.push_back(s); } } + void save(ESMWriter &esm) + { + for (std::vector::iterator it = list.begin(); it != list.end(); ++it) + { + esm.writeHNT("ENAM", *it, 24); + } + } }; } diff --git a/components/esm/esm_common.hpp b/components/esm/esm_common.hpp new file mode 100644 index 0000000000..abe0250dfc --- /dev/null +++ b/components/esm/esm_common.hpp @@ -0,0 +1,102 @@ +#ifndef _ESM_COMMON_H +#define _ESM_COMMON_H + +#include + +namespace ESM +{ +enum Version + { + VER_12 = 0x3f99999a, + VER_13 = 0x3fa66666 + }; + +enum FileType + { + FT_ESP = 0, // Plugin + FT_ESM = 1, // Master + FT_ESS = 32 // Savegame + }; + +// Used to mark special files. The original ESM files are given +// special treatment in a few places, most noticably in loading and +// filtering out "dirtly" GMST entries correctly. +enum SpecialFile + { + SF_Other, + SF_Morrowind, + SF_Tribunal, + SF_Bloodmoon + }; + +/* A structure used for holding fixed-length strings. In the case of + LEN=4, it can be more efficient to match the string as a 32 bit + number, therefore the struct is implemented as a union with an int. + */ +template +union NAME_T +{ + char name[LEN]; + int32_t val; + + bool operator==(const char *str) + { + for(int i=0; i NAME; +typedef NAME_T<32> NAME32; +typedef NAME_T<64> NAME64; +typedef NAME_T<256> NAME256; + +#pragma pack(push) +#pragma pack(1) +/// File header data for all ES files +struct HEDRstruct +{ + /* File format version. This is actually a float, the supported + versions are 1.2 and 1.3. These correspond to: + 1.2 = 0x3f99999a and 1.3 = 0x3fa66666 + */ + int version; + int type; // 0=esp, 1=esm, 32=ess + NAME32 author; // Author's name + NAME256 desc; // File description + int records; // Number of records? Not used. +}; + +// Defines another files (esm or esp) that this file depends upon. +struct MasterData +{ + std::string name; + uint64_t size; +}; + +// Data that is only present in save game files +struct SaveData +{ + float pos[6]; // Player position and rotation + NAME64 cell; // Cell name + float unk2; // Unknown value - possibly game time? + NAME32 player; // Player name +}; +#pragma pack(pop) +} + +#endif diff --git a/components/esm/esm_reader.hpp b/components/esm/esm_reader.hpp index 0420f37cd6..6e5592cf7b 100644 --- a/components/esm/esm_reader.hpp +++ b/components/esm/esm_reader.hpp @@ -16,103 +16,9 @@ #include #include +#include "esm_common.hpp" namespace ESM { - -enum Version - { - VER_12 = 0x3f99999a, - VER_13 = 0x3fa66666 - }; - -enum FileType - { - FT_ESP = 0, // Plugin - FT_ESM = 1, // Master - FT_ESS = 32 // Savegame - }; - -// Used to mark special files. The original ESM files are given -// special treatment in a few places, most noticably in loading and -// filtering out "dirtly" GMST entries correctly. -enum SpecialFile - { - SF_Other, - SF_Morrowind, - SF_Tribunal, - SF_Bloodmoon - }; - -/* A structure used for holding fixed-length strings. In the case of - LEN=4, it can be more efficient to match the string as a 32 bit - number, therefore the struct is implemented as a union with an int. - */ -template -union NAME_T -{ - char name[LEN]; - int32_t val; - - bool operator==(const char *str) - { - for(int i=0; i NAME; -typedef NAME_T<32> NAME32; -typedef NAME_T<64> NAME64; -typedef NAME_T<256> NAME256; - -#pragma pack(push) -#pragma pack(1) -/// File header data for all ES files -struct HEDRstruct -{ - /* File format version. This is actually a float, the supported - versions are 1.2 and 1.3. These correspond to: - 1.2 = 0x3f99999a and 1.3 = 0x3fa66666 - */ - int version; - int type; // 0=esp, 1=esm, 32=ess - NAME32 author; // Author's name - NAME256 desc; // File description - int records; // Number of records? Not used. -}; - -// Defines another files (esm or esp) that this file depends upon. -struct MasterData -{ - std::string name; - uint64_t size; -}; - -// Data that is only present in save game files -struct SaveData -{ - float pos[6]; // Player position and rotation - NAME64 cell; // Cell name - float unk2; // Unknown value - possibly game time? - NAME32 player; // Player name -}; -#pragma pack(pop) - - /* This struct defines a file 'context' which can be saved and later restored by an ESMReader instance. It will save the position within a file, and when restored will let you read from that position as diff --git a/components/esm/esm_writer.cpp b/components/esm/esm_writer.cpp new file mode 100644 index 0000000000..da040c664d --- /dev/null +++ b/components/esm/esm_writer.cpp @@ -0,0 +1,28 @@ +#include "esm_writer.hpp" + +namespace ESM +{ + +void ESMWriter::writeHNString(const std::string& name, const std::string& data) +{ + writeName(name); + writeHString(data); +} + +void ESMWriter::writeHString(const std::string& data) +{ + writeT(data.size()-1); + write(data.c_str(), data.size()-1); +} + +void ESMWriter::writeName(const std::string& name) +{ + write(name.c_str(), name.size()-1); +} + +void ESMWriter::write(const char* data, int size) +{ + m_stream.write(data, size); +} + +} diff --git a/components/esm/esm_writer.hpp b/components/esm/esm_writer.hpp new file mode 100644 index 0000000000..5adf32049a --- /dev/null +++ b/components/esm/esm_writer.hpp @@ -0,0 +1,71 @@ +#ifndef _ESM_WRITER_H +#define _ESM_WRITER_H + +#include +#include + +#include "esm_common.hpp" + +namespace ESM { + +class ESMWriter +{ +public: + void writeHNString(const std::string& name, const std::string& data); + void writeHNOString(const std::string& name, const std::string& data) + { + if (!data.empty()) + writeHNString(name, data); + } + + template + void writeHNT(const std::string& name, const T& data) + { + writeName(name); + writeT(data); + } + + template + void writeHNT(const std::string& name, const T& data, int size) + { + assert(sizeof(T) == size); + writeHNT(name, data); + } + + template + void writeHT(const T& data) + { + writeT((unsigned int)sizeof(T)); + writeT(data); + } + + template + void writeHT(const T& data, int size) + { + assert(sizeof(T) == size); + writeHT(data); + } + + template + void writeT(const T& data) + { + write((char*)&data, sizeof(T)); + } + + template + void writeT(const T& data, int size) + { + assert(sizeof(T) == size); + writeT(data); + } + + void writeHString(const std::string& data); + void writeName(const std::string& data); + void write(const char* data, int size); + +private: + std::ostream m_stream; +}; + +} +#endif diff --git a/components/esm/loadacti.cpp b/components/esm/loadacti.cpp index 40c9b635c3..a5e59a0068 100644 --- a/components/esm/loadacti.cpp +++ b/components/esm/loadacti.cpp @@ -8,4 +8,13 @@ void Activator::load(ESMReader &esm) name = esm.getHNString("FNAM"); script = esm.getHNOString("SCRI"); } +void Activator::save(ESMWriter &esm) +{ + esm.writeHNString("MODL", model); + esm.writeHNString("FNAM", name); + if (!script.empty()) + { + esm.writeHNString("SCRI", script); + } +} } diff --git a/components/esm/loadacti.hpp b/components/esm/loadacti.hpp index 783559e11b..3f968bc7c8 100644 --- a/components/esm/loadacti.hpp +++ b/components/esm/loadacti.hpp @@ -2,6 +2,7 @@ #define _ESM_ACTI_H #include "esm_reader.hpp" +#include "esm_writer.hpp" namespace ESM { @@ -11,6 +12,7 @@ struct Activator std::string name, script, model; void load(ESMReader &esm); + void save(ESMWriter &esm); }; } #endif diff --git a/components/esm/loadalch.cpp b/components/esm/loadalch.cpp index d3bc36a775..7db9ef9ac9 100644 --- a/components/esm/loadalch.cpp +++ b/components/esm/loadalch.cpp @@ -11,4 +11,16 @@ void Potion::load(ESMReader &esm) esm.getHNT(data, "ALDT", 12); effects.load(esm); } +void Potion::save(ESMWriter &esm) +{ + esm.writeHNString("MODL", model); + if (!icon.empty()) + esm.writeHNString("TEXT", icon); + if (!script.empty()) + esm.writeHNString("SCRI", script); + if (!name.empty()) + esm.writeHNString("FNAM", name); + esm.writeHNT("ALDT", data, 12); + effects.save(esm); +} } diff --git a/components/esm/loadalch.hpp b/components/esm/loadalch.hpp index c21e5dea00..b447fe50c4 100644 --- a/components/esm/loadalch.hpp +++ b/components/esm/loadalch.hpp @@ -2,6 +2,7 @@ #define _ESM_ALCH_H #include "esm_reader.hpp" +#include "esm_writer.hpp" #include "defs.hpp" namespace ESM @@ -25,6 +26,7 @@ struct Potion EffectList effects; void load(ESMReader &esm); + void save(ESMWriter &esm); }; } #endif diff --git a/components/esm/loadappa.cpp b/components/esm/loadappa.cpp index c76ad53507..17cc22087e 100644 --- a/components/esm/loadappa.cpp +++ b/components/esm/loadappa.cpp @@ -10,4 +10,13 @@ void Apparatus::load(ESMReader &esm) script = esm.getHNOString("SCRI"); icon = esm.getHNString("ITEX"); } +void Apparatus::save(ESMWriter &esm) +{ + esm.writeHNString("MODL", model); + esm.writeHNString("FNAM", name); + esm.writeHNT("AADT", data, 16); + if (!script.empty()) + esm.writeHNString("SCRI", script); + esm.writeHNString("ITEX", icon); +} } diff --git a/components/esm/loadappa.hpp b/components/esm/loadappa.hpp index 2caca32b3d..ff105a3079 100644 --- a/components/esm/loadappa.hpp +++ b/components/esm/loadappa.hpp @@ -2,6 +2,7 @@ #define _ESM_APPA_H #include "esm_reader.hpp" +#include "esm_writer.hpp" namespace ESM { @@ -32,6 +33,7 @@ struct Apparatus std::string model, icon, script, name; void load(ESMReader &esm); + void save(ESMWriter &esm); }; } #endif diff --git a/components/esm/loadarmo.cpp b/components/esm/loadarmo.cpp index ddc25e176f..14cb056bf5 100644 --- a/components/esm/loadarmo.cpp +++ b/components/esm/loadarmo.cpp @@ -11,6 +11,19 @@ void PartReferenceList::load(ESMReader &esm) esm.getHT(pr.part); // The INDX byte pr.male = esm.getHNOString("BNAM"); pr.female = esm.getHNOString("CNAM"); + parts.push_back(pr); + } +} + +void PartReferenceList::save(ESMWriter &esm) +{ + for (std::vector::iterator it = parts.begin(); it != parts.end(); ++it) + { + esm.writeHT(it->part); + if (!it->male.empty()) + esm.writeHNString("BNAM", it->male); + if (!it->female.empty()) + esm.writeHNString("CNAM", it->female); } } @@ -25,4 +38,18 @@ void Armor::load(ESMReader &esm) enchant = esm.getHNOString("ENAM"); } +void Armor::save(ESMWriter &esm) +{ + esm.writeHNString("MODL", model); + esm.writeHNString("FNAM", name); + if (!script.empty()) + esm.writeHNString("SCRI", script); + esm.writeHNT("AODT", data, 24); + if (!icon.empty()) + esm.writeHNString("ITEX", icon); + parts.save(esm); + if (!enchant.empty()) + esm.writeHNString("ENAM", enchant); +} + } diff --git a/components/esm/loadarmo.hpp b/components/esm/loadarmo.hpp index 16b6b1d3a0..5026696c24 100644 --- a/components/esm/loadarmo.hpp +++ b/components/esm/loadarmo.hpp @@ -2,6 +2,7 @@ #define _ESM_ARMO_H #include "esm_reader.hpp" +#include "esm_writer.hpp" namespace ESM { @@ -50,6 +51,7 @@ struct PartReferenceList std::vector parts; void load(ESMReader &esm); + void save(ESMWriter &esm); }; struct Armor @@ -82,6 +84,7 @@ struct Armor std::string name, model, icon, script, enchant; void load(ESMReader &esm); + void save(ESMWriter &esm); }; } #endif diff --git a/components/esm/loadbody.cpp b/components/esm/loadbody.cpp index 1c72b0fe0a..72d56eac35 100644 --- a/components/esm/loadbody.cpp +++ b/components/esm/loadbody.cpp @@ -9,5 +9,11 @@ void BodyPart::load(ESMReader &esm) name = esm.getHNString("FNAM"); esm.getHNT(data, "BYDT", 4); } +void BodyPart::save(ESMWriter &esm) +{ + esm.writeHNString("MODL", model); + esm.writeHNString("FNAM", name); + esm.writeHNT("BYDT", data, 4); +} } diff --git a/components/esm/loadbody.hpp b/components/esm/loadbody.hpp index de3db40fcd..46cb1d899d 100644 --- a/components/esm/loadbody.hpp +++ b/components/esm/loadbody.hpp @@ -2,6 +2,7 @@ #define _ESM_BODY_H #include "esm_reader.hpp" +#include "esm_writer.hpp" namespace ESM { @@ -52,6 +53,7 @@ struct BodyPart std::string model, name; void load(ESMReader &esm); + void save(ESMWriter &esm); }; } #endif diff --git a/components/esm/loadbook.cpp b/components/esm/loadbook.cpp index ffa958e144..829b7d297c 100644 --- a/components/esm/loadbook.cpp +++ b/components/esm/loadbook.cpp @@ -13,5 +13,20 @@ void Book::load(ESMReader &esm) text = esm.getHNOString("TEXT"); enchant = esm.getHNOString("ENAM"); } +void Book::save(ESMWriter &esm) +{ + esm.writeHNString("MODL", model); + if (!name.empty()) + esm.writeHNString("FNAM", name); + esm.writeHNT("BKDT", data, 20); + if (!script.empty()) + esm.writeHNString("SCRI", script); + if (!icon.empty()) + esm.writeHNString("ITEX", icon); + if (!text.empty()) + esm.writeHNString("TEXT", text); + if (!enchant.empty()) + esm.writeHNString("ENAM", enchant); +} } diff --git a/components/esm/loadbook.hpp b/components/esm/loadbook.hpp index 3a4ab441e8..a46135cc0d 100644 --- a/components/esm/loadbook.hpp +++ b/components/esm/loadbook.hpp @@ -2,6 +2,7 @@ #define _ESM_BOOK_H #include "esm_reader.hpp" +#include "esm_writer.hpp" namespace ESM { @@ -22,6 +23,7 @@ struct Book std::string name, model, icon, script, enchant, text; void load(ESMReader &esm); + void save(ESMWriter &esm); }; } #endif diff --git a/components/esm/loadbsgn.cpp b/components/esm/loadbsgn.cpp index 976cb7d207..9488f355f4 100644 --- a/components/esm/loadbsgn.cpp +++ b/components/esm/loadbsgn.cpp @@ -11,5 +11,15 @@ void BirthSign::load(ESMReader &esm) powers.load(esm); } +void BirthSign::save(ESMWriter &esm) +{ + esm.writeHNString("FNAM", name); + if (!texture.empty()) + esm.writeHNString("TNAM", texture); + if (!description.empty()) + esm.writeHNString("DESC", description); + + powers.save(esm); +} } diff --git a/components/esm/loadbsgn.hpp b/components/esm/loadbsgn.hpp index 53964b02c6..d00664bff8 100644 --- a/components/esm/loadbsgn.hpp +++ b/components/esm/loadbsgn.hpp @@ -3,6 +3,7 @@ #include "defs.hpp" #include "esm_reader.hpp" +#include "esm_writer.hpp" namespace ESM { @@ -15,6 +16,7 @@ struct BirthSign SpellList powers; void load(ESMReader &esm); + void save(ESMWriter &esm); }; } #endif diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index 158cc08673..8b3d09183d 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -6,6 +6,49 @@ namespace ESM { +void CellRef::save(ESMWriter &esm) +{ + esm.writeHNT("FRMR", refnum); + esm.writeHNString("NAME", refID); + + if (scale != 1.0) + esm.writeHNT("XSCL", scale); + + esm.writeHNOString("ANAM", owner); + esm.writeHNOString("BNAM", glob); + esm.writeHNOString("SXOL", soul); + + esm.writeHNOString("CNAM", faction); + if (factIndex != -1) + esm.writeHNT("INDX", factIndex); + + if (charge != -1.0) + esm.writeHNT("XCHG", charge); + + if (intv != 0) + esm.writeHNT("INTV", intv); + if (nam9 != 0) + esm.writeHNT("NAM9", nam9); + + if (teleport) + { + esm.writeHNT("DODT", doorDest); + esm.writeHNOString("DNAM", destCell); + } + + if (lockLevel != 0) + esm.writeHNT("FLTV", lockLevel); + esm.writeHNOString("KNAM", key); + esm.writeHNOString("TNAM", trap); + + if (unam != 0) + esm.writeHNT("UNAM", unam); + if (fltv != 0) + esm.writeHNT("FLTV", fltv); + + esm.writeHNT("DATA", pos, 24); +} + void Cell::load(ESMReader &esm) { // Ignore this for now, it might mean we should delete the entire @@ -50,6 +93,30 @@ void Cell::load(ESMReader &esm) esm.skipRecord(); } +void Cell::save(ESMWriter &esm) +{ + esm.writeHNT("DATA", data, 12); + if (data.flags & Interior) + { + if (water != 0) + esm.writeHNT("WHGT", water); + if (data.flags & QuasiEx) + { + if (!region.empty()) + esm.writeHNString("RGNN", region); + } + else + esm.writeHNT("AMBI", ambi, 16); + } + else + { + if (!region.empty()) + esm.writeHNString("RGNN", region); + if (mapColor != 0) + esm.writeHNT("NAM5", mapColor); + } +} + void Cell::restore(ESMReader &esm) const { esm.restoreContext(context); diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index 8070f9c038..8d461369c8 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -2,6 +2,7 @@ #define _ESM_CELL_H #include "esm_reader.hpp" +#include "esm_writer.hpp" #include "defs.hpp" namespace ESM { @@ -71,6 +72,8 @@ public: // Position and rotation of this object within the cell Position pos; + + void save(ESMWriter &esm); }; /* Cells hold data about objects, creatures, statics (rocks, walls, @@ -118,6 +121,7 @@ struct Cell int mapColor; void load(ESMReader &esm); + void save(ESMWriter &esm); bool isExterior() const { diff --git a/components/esm/loadclas.cpp b/components/esm/loadclas.cpp index b15852cc29..05cbfe7093 100644 --- a/components/esm/loadclas.cpp +++ b/components/esm/loadclas.cpp @@ -25,5 +25,12 @@ void Class::load(ESMReader &esm) description = esm.getHNOString("DESC"); } +void Class::save(ESMWriter &esm) +{ + esm.writeHNString("FNAM", name); + esm.writeHNT("CLDT", data, 60); + if (!description.empty()) + esm.writeHNString("DESC", description); +} } diff --git a/components/esm/loadclas.hpp b/components/esm/loadclas.hpp index 08412c8384..a89481a7ac 100644 --- a/components/esm/loadclas.hpp +++ b/components/esm/loadclas.hpp @@ -2,6 +2,7 @@ #define _ESM_CLAS_H #include "esm_reader.hpp" +#include "esm_writer.hpp" namespace ESM { @@ -61,6 +62,7 @@ struct Class CLDTstruct data; void load(ESMReader &esm); + void save(ESMWriter &esm); }; } #endif diff --git a/components/esm/loadclot.cpp b/components/esm/loadclot.cpp index 1d6c9d4a1e..b1c6783484 100644 --- a/components/esm/loadclot.cpp +++ b/components/esm/loadclot.cpp @@ -16,5 +16,22 @@ void Clothing::load(ESMReader &esm) enchant = esm.getHNOString("ENAM"); } +void Clothing::save(ESMWriter &esm) +{ + esm.writeHNString("MODL", model); + if (!name.empty()) + esm.writeHNString("FNAM", name); + esm.writeHNT("CTDT", data, 12); + + if (!script.empty()) + esm.writeHNString("SCRI", script); + if (!icon.empty()) + esm.writeHNString("ITEX", icon); + + parts.save(esm); + + if (!enchant.empty()) + esm.writeHNString("ENAM", enchant); +} } diff --git a/components/esm/loadclot.hpp b/components/esm/loadclot.hpp index 8fa06e7e41..77ef3786a8 100644 --- a/components/esm/loadclot.hpp +++ b/components/esm/loadclot.hpp @@ -2,6 +2,7 @@ #define _ESM_CLOT_H #include "esm_reader.hpp" +#include "esm_writer.hpp" #include "loadarmo.hpp" namespace ESM @@ -41,6 +42,7 @@ struct Clothing std::string name, model, icon, enchant, script; void load(ESMReader &esm); + void save(ESMWriter &esm); }; } #endif diff --git a/components/esm/loadcont.cpp b/components/esm/loadcont.cpp index 14699ccc5b..ba90e52ce7 100644 --- a/components/esm/loadcont.cpp +++ b/components/esm/loadcont.cpp @@ -13,6 +13,14 @@ void InventoryList::load(ESMReader &esm) } } +void InventoryList::save(ESMWriter &esm) +{ + for (std::vector::iterator it = list.begin(); it != list.end(); ++it) + { + esm.writeHNT("NPCO", *it, 36); + } +} + void Container::load(ESMReader &esm) { model = esm.getHNString("MODL"); @@ -30,4 +38,18 @@ void Container::load(ESMReader &esm) inventory.load(esm); } +void Container::save(ESMWriter &esm) +{ + esm.writeHNString("MODL", model); + if (!name.empty()) + esm.writeHNString("FNAM", name); + esm.writeHNT("CNDT", weight, 4); + esm.writeHNT("FLAG", flags, 4); + + if (!script.empty()) + esm.writeHNString("SCRI", script); + + inventory.save(esm); +} + } diff --git a/components/esm/loadcont.hpp b/components/esm/loadcont.hpp index 4614c4230c..bf6994f9af 100644 --- a/components/esm/loadcont.hpp +++ b/components/esm/loadcont.hpp @@ -2,6 +2,7 @@ #define _ESM_CONT_H #include "esm_reader.hpp" +#include "esm_writer.hpp" namespace ESM { @@ -21,6 +22,7 @@ struct InventoryList std::vector list; void load(ESMReader &esm); + void save(ESMWriter &esm); }; struct Container @@ -39,6 +41,7 @@ struct Container InventoryList inventory; void load(ESMReader &esm); + void save(ESMWriter &esm); }; } #endif diff --git a/components/esm/loadcrea.cpp b/components/esm/loadcrea.cpp index 651d9a3181..0cab2761e3 100644 --- a/components/esm/loadcrea.cpp +++ b/components/esm/loadcrea.cpp @@ -37,4 +37,20 @@ void Creature::load(ESMReader &esm, const std::string& id) esm.skipRecord(); } +void Creature::save(ESMWriter &esm) +{ + esm.writeHNString("MODL", model); + if (!original.empty()) + esm.writeHNString("CNAM", original); + if (!name.empty()) + esm.writeHNString("FNAM", name); + if (!script.empty()) + esm.writeHNString("SCRI", script); + esm.writeHNT("NPDT", data, 96); + esm.writeHNT("FLAG", flags); + if (scale != 1.0) + esm.writeHNT("XSCL", scale); + inventory.save(esm); +} + } diff --git a/components/esm/loadcrea.hpp b/components/esm/loadcrea.hpp index 3c334ebbd4..2f5f4061d9 100644 --- a/components/esm/loadcrea.hpp +++ b/components/esm/loadcrea.hpp @@ -2,6 +2,7 @@ #define _ESM_CREA_H #include "esm_reader.hpp" +#include "esm_writer.hpp" #include "loadcont.hpp" namespace ESM @@ -64,6 +65,7 @@ struct Creature std::string mId; void load(ESMReader &esm, const std::string& id); + void save(ESMWriter &esm); }; } #endif diff --git a/components/esm/loadcrec.hpp b/components/esm/loadcrec.hpp index 4d38d4a23b..056f572ae4 100644 --- a/components/esm/loadcrec.hpp +++ b/components/esm/loadcrec.hpp @@ -2,6 +2,7 @@ #define _ESM_CREC_H #include "esm_reader.hpp" +#include "esm_writer.hpp" namespace ESM { @@ -15,6 +16,10 @@ struct LoadCREC { esm.skipRecord(); } + + void save(ESMWriter &esm) + { + } }; /// Changes an item list / container @@ -24,6 +29,10 @@ struct LoadCNTC { esm.skipRecord(); } + + void save(ESMWriter &esm) + { + } }; } #endif diff --git a/components/esm/loaddial.cpp b/components/esm/loaddial.cpp index d2283d3514..bdee275868 100644 --- a/components/esm/loaddial.cpp +++ b/components/esm/loaddial.cpp @@ -22,4 +22,15 @@ void Dialogue::load(ESMReader &esm) esm.fail("Unknown sub record size"); } +void Dialogue::save(ESMWriter &esm) +{ + if (type != Deleted) + esm.writeHNT("DATA", type); + else + { + esm.writeHNT("DATA", (int)1); + esm.writeHNT("DELE", (int)1); + } +} + } diff --git a/components/esm/loaddial.hpp b/components/esm/loaddial.hpp index 1f18a49d0a..a19b0c7ad5 100644 --- a/components/esm/loaddial.hpp +++ b/components/esm/loaddial.hpp @@ -4,6 +4,7 @@ #include #include "esm_reader.hpp" +#include "esm_writer.hpp" #include "loadinfo.hpp" namespace ESM @@ -30,6 +31,7 @@ struct Dialogue std::vector mInfo; void load(ESMReader &esm); + void save(ESMWriter &esm); }; } #endif diff --git a/components/esm/loaddoor.cpp b/components/esm/loaddoor.cpp index d3cc69bd45..513eac7537 100644 --- a/components/esm/loaddoor.cpp +++ b/components/esm/loaddoor.cpp @@ -11,5 +11,17 @@ void Door::load(ESMReader &esm) openSound = esm.getHNOString("SNAM"); closeSound = esm.getHNOString("ANAM"); } +void Door::save(ESMWriter &esm) +{ + esm.writeHNString("MODL", model); + if (!name.empty()) + esm.writeHNString("FNAM", name); + if (!script.empty()) + esm.writeHNString("SCRI", script); + if (!openSound.empty()) + esm.writeHNString("SNAM", openSound); + if (!closeSound.empty()) + esm.writeHNString("ANAM", closeSound); +} } diff --git a/components/esm/loaddoor.hpp b/components/esm/loaddoor.hpp index 2c0db40649..1234ac7f91 100644 --- a/components/esm/loaddoor.hpp +++ b/components/esm/loaddoor.hpp @@ -2,6 +2,7 @@ #define _ESM_DOOR_H #include "esm_reader.hpp" +#include "esm_writer.hpp" namespace ESM { @@ -11,6 +12,7 @@ struct Door std::string name, model, script, openSound, closeSound; void load(ESMReader &esm); + void save(ESMWriter &esm); }; } #endif diff --git a/components/esm/loadench.cpp b/components/esm/loadench.cpp index b2787492dd..6157463cfd 100644 --- a/components/esm/loadench.cpp +++ b/components/esm/loadench.cpp @@ -8,5 +8,10 @@ void Enchantment::load(ESMReader &esm) esm.getHNT(data, "ENDT", 16); effects.load(esm); } +void Enchantment::save(ESMWriter &esm) +{ + esm.writeHNT("ENDT", data, 16); + effects.save(esm); +} } diff --git a/components/esm/loadench.hpp b/components/esm/loadench.hpp index 449589e257..6091669832 100644 --- a/components/esm/loadench.hpp +++ b/components/esm/loadench.hpp @@ -2,6 +2,7 @@ #define _ESM_ENCH_H #include "esm_reader.hpp" +#include "esm_writer.hpp" #include "defs.hpp" namespace ESM @@ -34,6 +35,7 @@ struct Enchantment EffectList effects; void load(ESMReader &esm); + void save(ESMWriter &esm); }; } #endif diff --git a/components/esm/loadfact.cpp b/components/esm/loadfact.cpp index 346ad2a2ef..fdbedcbd01 100644 --- a/components/esm/loadfact.cpp +++ b/components/esm/loadfact.cpp @@ -27,5 +27,22 @@ void Faction::load(ESMReader &esm) reactions.push_back(r); } } +void Faction::save(ESMWriter &esm) +{ + esm.writeHNString("FNAM", name); + + for (int i = 0; !ranks[i].empty(); i++) + { + esm.writeHNString("RNAM", ranks[i]); + } + + esm.writeHNT("FADT", data, 240); + + for (std::vector::iterator it = reactions.begin(); it != reactions.end(); ++it) + { + esm.writeHNString("ANAM", it->faction); + esm.writeHNT("INTV", it->reaction); + } +} } diff --git a/components/esm/loadfact.hpp b/components/esm/loadfact.hpp index 85874aa78d..686554da32 100644 --- a/components/esm/loadfact.hpp +++ b/components/esm/loadfact.hpp @@ -2,6 +2,7 @@ #define _ESM_FACT_H #include "esm_reader.hpp" +#include "esm_writer.hpp" namespace ESM { @@ -53,6 +54,7 @@ struct Faction std::string ranks[10]; void load(ESMReader &esm); + void save(ESMWriter &esm); }; } #endif diff --git a/components/esm/loadglob.cpp b/components/esm/loadglob.cpp index c946b3fa07..cf43de957c 100644 --- a/components/esm/loadglob.cpp +++ b/components/esm/loadglob.cpp @@ -21,4 +21,17 @@ void Global::load(ESMReader &esm) esm.getHNT(value, "FLTV"); } +void Global::save(ESMWriter &esm) +{ + switch(type) + { + case VT_Short: esm.writeHNString("FNAM", "s"); break; + case VT_Int: esm.writeHNString("FNAM", "l"); break; + case VT_Float: esm.writeHNString("FNAM", "f"); break; + default: return; + } + + esm.writeHNT("FLTV", value); +} + } diff --git a/components/esm/loadglob.hpp b/components/esm/loadglob.hpp index 5028679dd3..669475fe71 100644 --- a/components/esm/loadglob.hpp +++ b/components/esm/loadglob.hpp @@ -2,6 +2,7 @@ #define _ESM_GLOB_H #include "esm_reader.hpp" +#include "esm_writer.hpp" #include "defs.hpp" namespace ESM @@ -17,6 +18,7 @@ struct Global VarType type; void load(ESMReader &esm); + void save(ESMWriter &esm); }; } #endif diff --git a/components/esm/loadgmst.cpp b/components/esm/loadgmst.cpp index 677642e319..21c2d1fb18 100644 --- a/components/esm/loadgmst.cpp +++ b/components/esm/loadgmst.cpp @@ -168,5 +168,15 @@ void GameSetting::load(ESMReader &esm) && isDirtyBloodmoon())) dirty = true; } +void GameSetting::save(ESMWriter &esm) +{ + switch(type) + { + case VT_String: esm.writeHNString("STRV", str); break; + case VT_Int: esm.writeHNT("INTV", i); break; + case VT_Float: esm.writeHNT("FLTV", f); break; + default: break; + } +} } diff --git a/components/esm/loadgmst.hpp b/components/esm/loadgmst.hpp index 01fbc30676..dc0400a4ed 100644 --- a/components/esm/loadgmst.hpp +++ b/components/esm/loadgmst.hpp @@ -2,6 +2,7 @@ #define _ESM_GMST_H #include "esm_reader.hpp" +#include "esm_writer.hpp" #include "defs.hpp" namespace ESM @@ -83,6 +84,7 @@ struct GameSetting bool isDirtyBloodmoon(); void load(ESMReader &esm); + void save(ESMWriter &esm); }; } #endif diff --git a/components/esm/loadinfo.cpp b/components/esm/loadinfo.cpp index 0f08b3c8a2..c240aba87e 100644 --- a/components/esm/loadinfo.cpp +++ b/components/esm/loadinfo.cpp @@ -130,4 +130,43 @@ void DialInfo::load(ESMReader &esm) esm.skipRecord(); } +void DialInfo::save(ESMWriter &esm) +{ + esm.writeHNString("INAM", id); + esm.writeHNString("PNAM", prev); + esm.writeHNString("NNAM", next); + esm.writeHNT("DATA", data, 12); + esm.writeHNOString("ONAM", actor); + esm.writeHNOString("RNAM", race); + esm.writeHNOString("CNAM", clas); + esm.writeHNOString("FNAM", npcFaction); + esm.writeHNOString("ANAM", cell); + esm.writeHNOString("DNAM", pcFaction); + esm.writeHNOString("SNAM", sound); + esm.writeHNOString("NAME", response); + + for (std::vector::iterator it = selects.begin(); it != selects.end(); ++it) + { + esm.writeHNString("SCVR", it->selectRule); + switch(it->type) + { + case VT_Int: esm.writeHNT("INTV", it->i); break; + case VT_Float: esm.writeHNT("FLTV", it->f); break; + default: break; + } + } + + if (!resultScript.empty()) + esm.writeHNString("BNAM", resultScript); + + switch(questStatus) + { + case QS_Name: esm.writeHNT("QSTN",'\1'); break; + case QS_Finished: esm.writeHNT("QSTF", '\1'); break; + case QS_Restart: esm.writeHNT("QSTR", '\1'); break; + case QS_Deleted: esm.writeHNT("DELE", '\1'); break; + default: break; + } +} + } diff --git a/components/esm/loadinfo.hpp b/components/esm/loadinfo.hpp index c47af341e3..6f2d5ab25c 100644 --- a/components/esm/loadinfo.hpp +++ b/components/esm/loadinfo.hpp @@ -2,6 +2,7 @@ #define _ESM_INFO_H #include "esm_reader.hpp" +#include "esm_writer.hpp" #include "defs.hpp" namespace ESM @@ -98,6 +99,7 @@ struct DialInfo }; void load(ESMReader &esm); + void save(ESMWriter &esm); }; /* diff --git a/components/esm/loadingr.cpp b/components/esm/loadingr.cpp index 471f717800..b71f6f13db 100644 --- a/components/esm/loadingr.cpp +++ b/components/esm/loadingr.cpp @@ -11,5 +11,15 @@ void Ingredient::load(ESMReader &esm) script = esm.getHNOString("SCRI"); icon = esm.getHNOString("ITEX"); } +void Ingredient::save(ESMWriter &esm) +{ + esm.writeHNString("MODL", model); + esm.writeHNString("FNAM", name); + esm.writeHNT("IRDT", data, 56); + if (!script.empty()) + esm.writeHNString("SCRI", script); + if (!icon.empty()) + esm.writeHNString("ITEX", script); +} } diff --git a/components/esm/loadingr.hpp b/components/esm/loadingr.hpp index af9599ed06..040118bbfd 100644 --- a/components/esm/loadingr.hpp +++ b/components/esm/loadingr.hpp @@ -2,6 +2,7 @@ #define _ESM_INGR_H #include "esm_reader.hpp" +#include "esm_writer.hpp" namespace ESM { @@ -25,6 +26,7 @@ struct Ingredient std::string name, model, icon, script; void load(ESMReader &esm); + void save(ESMWriter &esm); }; } #endif diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp index 96afdf8316..4d3a4a0edf 100644 --- a/components/esm/loadland.cpp +++ b/components/esm/loadland.cpp @@ -3,6 +3,17 @@ namespace ESM { +void Land::LandData::save(ESMWriter &esm) +{ + // TODO: Make this actually work. + + //esm.writeHNT("VNML", normals, sizeof(VNML)); + esm.writeHNT("VHGT", heights, sizeof(VHGT)); + esm.writeHNT("WNAM", 0, 81); + esm.writeHNT("VCLR", colours, 3*LAND_NUM_VERTS); + esm.writeHNT("VTEX", textures, 512); +} + Land::Land() : flags(0) , X(0) @@ -71,6 +82,21 @@ void Land::load(ESMReader &esm) landData = NULL; } +void Land::save(ESMWriter &esm) +{ + esm.writeHString("INTV"); + esm.writeT(X); + esm.writeT(Y); + + esm.writeHNT("DATA", flags); + + if (hasData && !dataLoaded) + loadData(); // I think it might be a good idea to have + // the data loaded before trying to save it + if (dataLoaded) + landData->save(esm); +} + void Land::loadData() { if (dataLoaded) diff --git a/components/esm/loadland.hpp b/components/esm/loadland.hpp index ebc314a280..ba506b63b9 100644 --- a/components/esm/loadland.hpp +++ b/components/esm/loadland.hpp @@ -2,6 +2,7 @@ #define _ESM_LAND_H #include "esm_reader.hpp" +#include "esm_writer.hpp" namespace ESM { @@ -65,11 +66,14 @@ struct Land bool usingColours; char colours[3 * LAND_NUM_VERTS]; + + void save(ESMWriter &esm); }; LandData *landData; void load(ESMReader &esm); + void save(ESMWriter &esm); /** * Actually loads data diff --git a/components/esm/loadlevlist.cpp b/components/esm/loadlevlist.cpp index d1bff7972d..811964775b 100644 --- a/components/esm/loadlevlist.cpp +++ b/components/esm/loadlevlist.cpp @@ -30,5 +30,17 @@ void LeveledListBase::load(ESMReader &esm) esm.getHNT(li.level, "INTV"); } } +void LeveledListBase::save(ESMWriter &esm) +{ + esm.writeHNT("DATA", flags); + esm.writeHNT("NNAM", chanceNone); + esm.writeHNT("INDX", list.size()); + + for (std::vector::iterator it = list.begin(); it != list.end(); ++it) + { + esm.writeHNString("INAM", it->id); + esm.writeHNT("INTV", it->level); + } +} } diff --git a/components/esm/loadlevlist.hpp b/components/esm/loadlevlist.hpp index 4affce5394..ff20ce9d16 100644 --- a/components/esm/loadlevlist.hpp +++ b/components/esm/loadlevlist.hpp @@ -2,6 +2,7 @@ #define _ESM_LEVLISTS_H #include "esm_reader.hpp" +#include "esm_writer.hpp" namespace ESM { @@ -43,6 +44,7 @@ struct LeveledListBase std::vector list; void load(ESMReader &esm); + void save(ESMWriter &esm); }; struct CreatureLevList: LeveledListBase diff --git a/components/esm/loadligh.cpp b/components/esm/loadligh.cpp index 721a818f7b..b7530eb6c0 100644 --- a/components/esm/loadligh.cpp +++ b/components/esm/loadligh.cpp @@ -13,5 +13,18 @@ void Light::load(ESMReader &esm) script = esm.getHNOString("SCRI"); sound = esm.getHNOString("SNAM"); } +void Light::save(ESMWriter &esm) +{ + esm.writeHNString("MODL", model); + if (!name.empty()) + esm.writeHNString("FNAM", name); + if (!icon.empty()) + esm.writeHNString("ITEX", icon); + esm.writeHNT("LHDT", data, 24); + if (!script.empty()) + esm.writeHNString("SCRI", script); + if (!sound.empty()) + esm.writeHNString("SNAM", sound); +} } diff --git a/components/esm/loadligh.hpp b/components/esm/loadligh.hpp index 178258a053..aecd8b99b6 100644 --- a/components/esm/loadligh.hpp +++ b/components/esm/loadligh.hpp @@ -2,6 +2,7 @@ #define _ESM_LIGH_H #include "esm_reader.hpp" +#include "esm_writer.hpp" namespace ESM { @@ -41,6 +42,7 @@ struct Light std::string sound, script, model, icon, name; void load(ESMReader &esm); + void save(ESMWriter &esm); }; } #endif diff --git a/components/esm/loadlocks.cpp b/components/esm/loadlocks.cpp index 79e882d94d..b9f1d35cae 100644 --- a/components/esm/loadlocks.cpp +++ b/components/esm/loadlocks.cpp @@ -17,14 +17,38 @@ void Tool::load(ESMReader &esm) if (n == "RIDT") { + type = Type_Repair; // Swap t.data.quality and t.data.uses for repair items (sigh) float tmp = *((float*) &data.uses); data.uses = *((int*) &data.quality); data.quality = tmp; } + else if (n == "LKDT") + type = Type_Pick; + else if (n == "PBDT") + type = Type_Probe; script = esm.getHNOString("SCRI"); icon = esm.getHNOString("ITEX"); } +void Tool::save(ESMWriter &esm) +{ + esm.writeHNString("MODL", model); + esm.writeHNString("FNAM", name); + + switch(type) + { + case Type_Repair: esm.writeHString("RIDT"); break; + case Type_Pick: esm.writeHString("LKDT"); break; + case Type_Probe: esm.writeHString("PBDT"); break; + } + + esm.writeT(data, 16); + if (!script.empty()) + esm.writeHNString("SCRI", script); + if (!icon.empty()) + esm.writeHNString("ITEX", icon); +} + } diff --git a/components/esm/loadlocks.hpp b/components/esm/loadlocks.hpp index a1e537a4c6..1c2a709f14 100644 --- a/components/esm/loadlocks.hpp +++ b/components/esm/loadlocks.hpp @@ -2,6 +2,7 @@ #define _ESM_LOCKS_H #include "esm_reader.hpp" +#include "esm_writer.hpp" namespace ESM { @@ -13,6 +14,13 @@ namespace ESM struct Tool { + enum Type + { + Type_Pick, + Type_Probe, + Type_Repair + }; + struct Data { float weight; @@ -25,9 +33,11 @@ struct Tool }; // Size = 16 Data data; + Type type; std::string name, model, icon, script; void load(ESMReader &esm); + void save(ESMWriter &esm); }; struct Probe: Tool diff --git a/components/esm/loadltex.cpp b/components/esm/loadltex.cpp index 08b1cf6dc0..b4820d9ec3 100644 --- a/components/esm/loadltex.cpp +++ b/components/esm/loadltex.cpp @@ -8,5 +8,10 @@ void LandTexture::load(ESMReader &esm) esm.getHNT(index, "INTV"); texture = esm.getHNString("DATA"); } +void LandTexture::save(ESMWriter &esm) +{ + esm.writeHNT("INTV", index); + esm.writeHNString("DATA", texture); +} } diff --git a/components/esm/loadltex.hpp b/components/esm/loadltex.hpp index fa4cac10a3..d171c8e11b 100644 --- a/components/esm/loadltex.hpp +++ b/components/esm/loadltex.hpp @@ -2,6 +2,7 @@ #define _ESM_LTEX_H #include "esm_reader.hpp" +#include "esm_writer.hpp" namespace ESM { @@ -28,6 +29,7 @@ struct LandTexture int index; void load(ESMReader &esm); + void save(ESMWriter &esm); }; } #endif diff --git a/components/esm/loadmgef.cpp b/components/esm/loadmgef.cpp index 2eda67b61c..8de37f065e 100644 --- a/components/esm/loadmgef.cpp +++ b/components/esm/loadmgef.cpp @@ -23,5 +23,24 @@ void MagicEffect::load(ESMReader &esm) description = esm.getHNOString("DESC"); } +void MagicEffect::save(ESMWriter &esm) +{ + esm.writeHNT("INDX", index); + esm.writeHNT("MEDT", data, 36); + + esm.writeHNOString("ITEX", icon); + esm.writeHNOString("PTEX", particle); + esm.writeHNOString("BSND", boltSound); + esm.writeHNOString("CSND", castSound); + esm.writeHNOString("HSND", hitSound); + esm.writeHNOString("ASND", areaSound); + + esm.writeHNOString("CVFX", casting); + esm.writeHNOString("BVFX", bolt); + esm.writeHNOString("HVFX", hit); + esm.writeHNOString("AVFX", area); + + esm.writeHNOString("DESC", description); +} } diff --git a/components/esm/loadmgef.hpp b/components/esm/loadmgef.hpp index b0b330aeb4..ed0b03d0bd 100644 --- a/components/esm/loadmgef.hpp +++ b/components/esm/loadmgef.hpp @@ -2,6 +2,7 @@ #define _ESM_MGEF_H #include "esm_reader.hpp" +#include "esm_writer.hpp" namespace ESM { @@ -46,6 +47,7 @@ struct MagicEffect int index; void load(ESMReader &esm); + void save(ESMWriter &esm); }; } #endif diff --git a/components/esm/loadmisc.cpp b/components/esm/loadmisc.cpp index 0206661c43..cf5cf92ae1 100644 --- a/components/esm/loadmisc.cpp +++ b/components/esm/loadmisc.cpp @@ -11,5 +11,13 @@ void Miscellaneous::load(ESMReader &esm) script = esm.getHNOString("SCRI"); icon = esm.getHNOString("ITEX"); } +void Miscellaneous::save(ESMWriter &esm) +{ + esm.writeHNString("MODL", model); + esm.writeHNOString("FNAM", name); + esm.writeHNT("MCDT", data, 12); + esm.writeHNOString("SCRI", script); + esm.writeHNOString("ITEX", icon); +} } diff --git a/components/esm/loadmisc.hpp b/components/esm/loadmisc.hpp index 7e151f7970..9aaa3c1be6 100644 --- a/components/esm/loadmisc.hpp +++ b/components/esm/loadmisc.hpp @@ -2,6 +2,7 @@ #define _ESM_MISC_H #include "esm_reader.hpp" +#include "esm_writer.hpp" namespace ESM { @@ -26,6 +27,7 @@ struct Miscellaneous std::string name, model, icon, script; void load(ESMReader &esm); + void save(ESMWriter &esm); }; } #endif diff --git a/components/esm/loadnpc.cpp b/components/esm/loadnpc.cpp index 5b0e90c846..6cb6b64c78 100644 --- a/components/esm/loadnpc.cpp +++ b/components/esm/loadnpc.cpp @@ -23,9 +23,15 @@ void NPC::load(ESMReader &esm, const std::string& id) esm.getSubNameIs("NPDT"); esm.getSubHeader(); if (esm.getSubSize() == 52) + { + npdtType = 52; esm.getExact(&npdt52, 52); + } else if (esm.getSubSize() == 12) + { + npdtType = 12; esm.getExact(&npdt12, 12); + } else esm.fail("NPC_NPDT must be 12 or 52 bytes long"); @@ -44,5 +50,29 @@ void NPC::load(ESMReader &esm, const std::string& id) esm.skipRecord(); } +void NPC::save(ESMWriter &esm) +{ + esm.writeHNOString("MODL", model); + esm.writeHNOString("FNAM", name); + esm.writeHNString("RNAM", race); + esm.writeHNString("CNAM", cls); + esm.writeHNString("ANAM", faction); + esm.writeHNString("BNAM", head); + esm.writeHNString("KNAM", hair); + esm.writeHNOString("SCRI", script); + + if (npdtType == 52) + esm.writeHNT("NPDT", npdt52, 52); + else if (npdtType == 12) + esm.writeHNT("NPDT", npdt12, 12); + + esm.writeHNT("FLAG", flags); + + inventory.save(esm); + spells.save(esm); + + if (hasAI) + esm.writeHNT("AIDT", AI); +} } diff --git a/components/esm/loadnpc.hpp b/components/esm/loadnpc.hpp index 62a99e763d..3e094a1971 100644 --- a/components/esm/loadnpc.hpp +++ b/components/esm/loadnpc.hpp @@ -2,6 +2,7 @@ #define _ESM_NPC_H #include "esm_reader.hpp" +#include "esm_writer.hpp" #include "loadcont.hpp" #include "defs.hpp" @@ -83,6 +84,7 @@ struct NPC #pragma pack(pop) + char npdtType; NPDTstruct52 npdt52; NPDTstruct12 npdt12; // Use this if npdt52.gold == -10 @@ -101,6 +103,7 @@ struct NPC // Implementation moved to load_impl.cpp void load(ESMReader &esm, const std::string& id); + void save(ESMWriter &esm); }; } #endif diff --git a/components/esm/loadnpcc.hpp b/components/esm/loadnpcc.hpp index 592d5b57fb..a65f6a6b34 100644 --- a/components/esm/loadnpcc.hpp +++ b/components/esm/loadnpcc.hpp @@ -2,6 +2,7 @@ #define _ESM_NPCC_H #include "esm_reader.hpp" +#include "esm_writer.hpp" namespace ESM { @@ -76,6 +77,9 @@ struct LoadNPCC { esm.skipRecord(); } + void save(ESMWriter &esm) + { + } }; } #endif diff --git a/components/esm/loadpgrd.cpp b/components/esm/loadpgrd.cpp index dc63ce335e..572378dad8 100644 --- a/components/esm/loadpgrd.cpp +++ b/components/esm/loadpgrd.cpp @@ -67,5 +67,28 @@ void Pathgrid::load(ESMReader &esm) } } } +void Pathgrid::save(ESMWriter &esm) +{ + esm.writeHNT("DATA", data, 12); + esm.writeHNString("NAME", cell); + + if (!points.empty()) + { + esm.writeHString("PGRP"); + for (PointList::iterator it = points.begin(); it != points.end(); ++it) + { + esm.writeT(*it); + } + } + + if (!edges.empty()) + { + esm.writeHString("PGRC"); + for (std::vector::iterator it = edges.begin(); it != edges.end(); ++it) + { + esm.writeT(it->v1); + } + } +} } diff --git a/components/esm/loadpgrd.hpp b/components/esm/loadpgrd.hpp index 6e2c6e134f..ec339240f8 100644 --- a/components/esm/loadpgrd.hpp +++ b/components/esm/loadpgrd.hpp @@ -2,6 +2,7 @@ #define _ESM_PGRD_H #include "esm_reader.hpp" +#include "esm_writer.hpp" namespace ESM { @@ -42,6 +43,7 @@ struct Pathgrid EdgeList edges; void load(ESMReader &esm); + void save(ESMWriter &esm); }; } #endif diff --git a/components/esm/loadrace.cpp b/components/esm/loadrace.cpp index ce64f5f725..04752add1e 100644 --- a/components/esm/loadrace.cpp +++ b/components/esm/loadrace.cpp @@ -10,5 +10,12 @@ void Race::load(ESMReader &esm) powers.load(esm); description = esm.getHNOString("DESC"); } +void Race::save(ESMWriter &esm) +{ + esm.writeHNString("FNAM", name); + esm.writeHNT("RADT", data, 140); + powers.save(esm); + esm.writeHNOString("DESC", description); +} } diff --git a/components/esm/loadrace.hpp b/components/esm/loadrace.hpp index d4506dbef2..15fa439842 100644 --- a/components/esm/loadrace.hpp +++ b/components/esm/loadrace.hpp @@ -2,6 +2,7 @@ #define _ESM_RACE_H #include "esm_reader.hpp" +#include "esm_writer.hpp" #include "defs.hpp" namespace ESM @@ -58,6 +59,7 @@ struct Race SpellList powers; void load(ESMReader &esm); + void save(ESMWriter &esm); }; } #endif diff --git a/components/esm/loadregn.cpp b/components/esm/loadregn.cpp index f31c9a827a..d67922b4d9 100644 --- a/components/esm/loadregn.cpp +++ b/components/esm/loadregn.cpp @@ -25,5 +25,19 @@ void Region::load(ESMReader &esm) soundList.push_back(sr); } } +void Region::save(ESMWriter &esm) +{ + esm.writeHNString("FNAM", name); + + esm.writeHNT("WEAT", data); + + esm.writeHNOString("BNAM", sleepList); + + esm.writeHNT("CNAM", mapColor); + for (std::vector::iterator it = soundList.begin(); it != soundList.end(); ++it) + { + esm.writeHNT("SNAM", *it); + } +} } diff --git a/components/esm/loadregn.hpp b/components/esm/loadregn.hpp index 1748b3d282..81b8bc51da 100644 --- a/components/esm/loadregn.hpp +++ b/components/esm/loadregn.hpp @@ -2,6 +2,7 @@ #define _ESM_REGN_H #include "esm_reader.hpp" +#include "esm_writer.hpp" namespace ESM { @@ -41,6 +42,7 @@ struct Region std::vector soundList; void load(ESMReader &esm); + void save(ESMWriter &esm); }; } #endif diff --git a/components/esm/loadscpt.cpp b/components/esm/loadscpt.cpp index 9c0176725c..86d1d8e294 100644 --- a/components/esm/loadscpt.cpp +++ b/components/esm/loadscpt.cpp @@ -38,5 +38,21 @@ void Script::load(ESMReader &esm) // Script text scriptText = esm.getHNOString("SCTX"); } +void Script::save(ESMWriter &esm) +{ + esm.writeHNT("SCHD", data, 52); + + if (!varNames.empty()) + { + esm.writeHString("SCVR"); + for (std::vector::iterator it = varNames.begin(); it != varNames.end(); ++it) + { + esm.writeT(it->c_str(), it->size()); + } + } + + esm.writeHNT("SCDT", &scriptData[0], scriptData.size()); + esm.writeHNOString("SCDT", scriptText); +} } diff --git a/components/esm/loadscpt.hpp b/components/esm/loadscpt.hpp index 3ce3d9636b..55cfb053ad 100644 --- a/components/esm/loadscpt.hpp +++ b/components/esm/loadscpt.hpp @@ -2,6 +2,7 @@ #define _ESM_SCPT_H #include "esm_reader.hpp" +#include "esm_writer.hpp" namespace ESM { @@ -50,6 +51,7 @@ public: std::string scriptText; // Uncompiled script void load(ESMReader &esm); + void save(ESMWriter &esm); }; } #endif diff --git a/components/esm/loadskil.cpp b/components/esm/loadskil.cpp index aa7103efcb..adce2f361c 100644 --- a/components/esm/loadskil.cpp +++ b/components/esm/loadskil.cpp @@ -67,4 +67,10 @@ void Skill::load(ESMReader &esm) esm.getHNT(data, "SKDT", 24); description = esm.getHNOString("DESC"); } +void Skill::save(ESMWriter &esm) +{ + esm.writeHNT("INDX", index); + esm.writeHNT("SKDT", data, 24); + esm.writeHNOString("DESC", description); +} } diff --git a/components/esm/loadskil.hpp b/components/esm/loadskil.hpp index 836f702051..8cc90b0634 100644 --- a/components/esm/loadskil.hpp +++ b/components/esm/loadskil.hpp @@ -4,6 +4,7 @@ #include #include "esm_reader.hpp" +#include "esm_writer.hpp" #include "defs.hpp" namespace ESM { @@ -67,6 +68,7 @@ struct Skill static const boost::array skillIds; void load(ESMReader &esm); + void save(ESMWriter &esm); }; } #endif diff --git a/components/esm/loadsndg.cpp b/components/esm/loadsndg.cpp index b7b5681320..10f010f48e 100644 --- a/components/esm/loadsndg.cpp +++ b/components/esm/loadsndg.cpp @@ -10,5 +10,11 @@ void SoundGenerator::load(ESMReader &esm) creature = esm.getHNOString("CNAM"); sound = esm.getHNOString("SNAM"); } +void SoundGenerator::save(ESMWriter &esm) +{ + esm.writeHNT("DATA", type, 4); + esm.writeHNOString("CNAM", creature); + esm.writeHNOString("SNAM", sound); +} } diff --git a/components/esm/loadsndg.hpp b/components/esm/loadsndg.hpp index 2953369c4c..e9e20c2126 100644 --- a/components/esm/loadsndg.hpp +++ b/components/esm/loadsndg.hpp @@ -2,6 +2,7 @@ #define _ESM_SNDG_H #include "esm_reader.hpp" +#include "esm_writer.hpp" namespace ESM { @@ -30,6 +31,7 @@ struct SoundGenerator std::string creature, sound; void load(ESMReader &esm); + void save(ESMWriter &esm); }; } #endif diff --git a/components/esm/loadsoun.cpp b/components/esm/loadsoun.cpp index cd47f0f17c..a160f3d1ca 100644 --- a/components/esm/loadsoun.cpp +++ b/components/esm/loadsoun.cpp @@ -14,5 +14,10 @@ void Sound::load(ESMReader &esm) << endl; */ } +void Sound::save(ESMWriter &esm) +{ + esm.writeHNString("FNAM", sound); + esm.writeHNT("DATA", data, 3); +} } diff --git a/components/esm/loadsoun.hpp b/components/esm/loadsoun.hpp index 775a664be0..9f0bdf5099 100644 --- a/components/esm/loadsoun.hpp +++ b/components/esm/loadsoun.hpp @@ -2,6 +2,7 @@ #define _ESM_SOUN_H #include "esm_reader.hpp" +#include "esm_writer.hpp" namespace ESM { @@ -17,6 +18,7 @@ struct Sound std::string sound; void load(ESMReader &esm); + void save(ESMWriter &esm); }; } #endif diff --git a/components/esm/loadspel.cpp b/components/esm/loadspel.cpp index c3c928ce67..a87dfb620d 100644 --- a/components/esm/loadspel.cpp +++ b/components/esm/loadspel.cpp @@ -9,5 +9,11 @@ void Spell::load(ESMReader &esm) esm.getHNT(data, "SPDT", 12); effects.load(esm); } +void Spell::save(ESMWriter &esm) +{ + esm.writeHNOString("FNAM", name); + esm.writeHNT("SPDT", data, 12); + effects.save(esm); +} } diff --git a/components/esm/loadspel.hpp b/components/esm/loadspel.hpp index c97d037cd8..971bf23a4d 100644 --- a/components/esm/loadspel.hpp +++ b/components/esm/loadspel.hpp @@ -2,6 +2,7 @@ #define _ESM_SPEL_H #include "esm_reader.hpp" +#include "esm_writer.hpp" #include "defs.hpp" namespace ESM @@ -38,6 +39,7 @@ struct Spell EffectList effects; void load(ESMReader &esm); + void save(ESMWriter &esm); }; } #endif diff --git a/components/esm/loadsscr.cpp b/components/esm/loadsscr.cpp index f4e79271ca..f1099e67b9 100644 --- a/components/esm/loadsscr.cpp +++ b/components/esm/loadsscr.cpp @@ -9,5 +9,10 @@ void StartScript::load(ESMReader &esm) esm.skipHSub(); script = esm.getHNString("NAME"); } +void StartScript::save(ESMWriter &esm) +{ + esm.writeHNString("DATA", "NIET"); + esm.writeHNString("NAME", script); +} } diff --git a/components/esm/loadsscr.hpp b/components/esm/loadsscr.hpp index d18bde101b..2cc7eccf9f 100644 --- a/components/esm/loadsscr.hpp +++ b/components/esm/loadsscr.hpp @@ -2,6 +2,7 @@ #define _ESM_SSCR_H #include "esm_reader.hpp" +#include "esm_writer.hpp" namespace ESM { @@ -20,6 +21,7 @@ struct StartScript // Load a record and add it to the list void load(ESMReader &esm); + void save(ESMWriter &esm); }; } diff --git a/components/esm/loadstat.cpp b/components/esm/loadstat.cpp index 654bf290ae..2252e9b030 100644 --- a/components/esm/loadstat.cpp +++ b/components/esm/loadstat.cpp @@ -7,5 +7,9 @@ void Static::load(ESMReader &esm) { model = esm.getHNString("MODL"); } +void Static::save(ESMWriter &esm) +{ + esm.writeHNString("MODL", model); +} } diff --git a/components/esm/loadstat.hpp b/components/esm/loadstat.hpp index 4f3121d186..a5b82c46dc 100644 --- a/components/esm/loadstat.hpp +++ b/components/esm/loadstat.hpp @@ -2,6 +2,7 @@ #define _ESM_STAT_H #include "esm_reader.hpp" +#include "esm_writer.hpp" namespace ESM { @@ -22,6 +23,7 @@ struct Static std::string model; void load(ESMReader &esm); + void save(ESMWriter &esm); }; } #endif diff --git a/components/esm/loadweap.cpp b/components/esm/loadweap.cpp index 1910631bcc..6cc7fa02db 100644 --- a/components/esm/loadweap.cpp +++ b/components/esm/loadweap.cpp @@ -12,5 +12,14 @@ void Weapon::load(ESMReader &esm) icon = esm.getHNOString("ITEX"); enchant = esm.getHNOString("ENAM"); } +void Weapon::save(ESMWriter &esm) +{ + esm.writeHNString("MODL", model); + esm.writeHNOString("FNAM", name); + esm.writeHNT("WPDT", data, 32); + esm.writeHNOString("SCRI", script); + esm.writeHNOString("ITEX", icon); + esm.writeHNOString("ENAM", enchant); +} } diff --git a/components/esm/loadweap.hpp b/components/esm/loadweap.hpp index 8bd3b147cf..8e7947bf33 100644 --- a/components/esm/loadweap.hpp +++ b/components/esm/loadweap.hpp @@ -2,6 +2,7 @@ #define _ESM_WEAP_H #include "esm_reader.hpp" +#include "esm_writer.hpp" namespace ESM { @@ -56,6 +57,7 @@ struct Weapon std::string name, model, icon, enchant, script; void load(ESMReader &esm); + void save(ESMWriter &esm); }; } #endif From 7c1e417f9a4514b1e35cce760ccb58e7d8d2f128 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Fri, 6 Apr 2012 21:14:52 +0200 Subject: [PATCH 02/14] Niceify-ing it (Yes, that's a word) --- components/esm/loadacti.cpp | 5 +---- components/esm/loadalch.cpp | 9 +++------ components/esm/loadappa.cpp | 3 +-- components/esm/loadarmo.cpp | 15 +++++---------- components/esm/loadbook.cpp | 15 +++++---------- components/esm/loadbsgn.cpp | 6 ++---- components/esm/loadcell.cpp | 9 +++------ components/esm/loadclas.cpp | 3 +-- components/esm/loadclot.cpp | 12 ++++-------- components/esm/loadcont.cpp | 6 ++---- components/esm/loadcrea.cpp | 9 +++------ components/esm/loaddoor.cpp | 12 ++++-------- components/esm/loadinfo.cpp | 3 +-- components/esm/loadingr.cpp | 6 ++---- components/esm/loadligh.cpp | 12 ++++-------- components/esm/loadlocks.cpp | 6 ++---- 16 files changed, 43 insertions(+), 88 deletions(-) diff --git a/components/esm/loadacti.cpp b/components/esm/loadacti.cpp index a5e59a0068..b62a461586 100644 --- a/components/esm/loadacti.cpp +++ b/components/esm/loadacti.cpp @@ -12,9 +12,6 @@ void Activator::save(ESMWriter &esm) { esm.writeHNString("MODL", model); esm.writeHNString("FNAM", name); - if (!script.empty()) - { - esm.writeHNString("SCRI", script); - } + esm.writeHNOString("SCRI", script); } } diff --git a/components/esm/loadalch.cpp b/components/esm/loadalch.cpp index 7db9ef9ac9..e5d3d8e271 100644 --- a/components/esm/loadalch.cpp +++ b/components/esm/loadalch.cpp @@ -14,12 +14,9 @@ void Potion::load(ESMReader &esm) void Potion::save(ESMWriter &esm) { esm.writeHNString("MODL", model); - if (!icon.empty()) - esm.writeHNString("TEXT", icon); - if (!script.empty()) - esm.writeHNString("SCRI", script); - if (!name.empty()) - esm.writeHNString("FNAM", name); + esm.writeHNOString("TEXT", icon); + esm.writeHNOString("SCRI", script); + esm.writeHNOString("FNAM", name); esm.writeHNT("ALDT", data, 12); effects.save(esm); } diff --git a/components/esm/loadappa.cpp b/components/esm/loadappa.cpp index 17cc22087e..6eb164ec25 100644 --- a/components/esm/loadappa.cpp +++ b/components/esm/loadappa.cpp @@ -15,8 +15,7 @@ void Apparatus::save(ESMWriter &esm) esm.writeHNString("MODL", model); esm.writeHNString("FNAM", name); esm.writeHNT("AADT", data, 16); - if (!script.empty()) - esm.writeHNString("SCRI", script); + esm.writeHNOString("SCRI", script); esm.writeHNString("ITEX", icon); } } diff --git a/components/esm/loadarmo.cpp b/components/esm/loadarmo.cpp index 14cb056bf5..aecfc7e922 100644 --- a/components/esm/loadarmo.cpp +++ b/components/esm/loadarmo.cpp @@ -20,10 +20,8 @@ void PartReferenceList::save(ESMWriter &esm) for (std::vector::iterator it = parts.begin(); it != parts.end(); ++it) { esm.writeHT(it->part); - if (!it->male.empty()) - esm.writeHNString("BNAM", it->male); - if (!it->female.empty()) - esm.writeHNString("CNAM", it->female); + esm.writeHNOString("BNAM", it->male); + esm.writeHNOString("CNAM", it->female); } } @@ -42,14 +40,11 @@ void Armor::save(ESMWriter &esm) { esm.writeHNString("MODL", model); esm.writeHNString("FNAM", name); - if (!script.empty()) - esm.writeHNString("SCRI", script); + esm.writeHNOString("SCRI", script); esm.writeHNT("AODT", data, 24); - if (!icon.empty()) - esm.writeHNString("ITEX", icon); + esm.writeHNOString("ITEX", icon); parts.save(esm); - if (!enchant.empty()) - esm.writeHNString("ENAM", enchant); + esm.writeHNOString("ENAM", enchant); } } diff --git a/components/esm/loadbook.cpp b/components/esm/loadbook.cpp index 829b7d297c..ed21d71e14 100644 --- a/components/esm/loadbook.cpp +++ b/components/esm/loadbook.cpp @@ -16,17 +16,12 @@ void Book::load(ESMReader &esm) void Book::save(ESMWriter &esm) { esm.writeHNString("MODL", model); - if (!name.empty()) - esm.writeHNString("FNAM", name); + esm.writeHNOString("FNAM", name); esm.writeHNT("BKDT", data, 20); - if (!script.empty()) - esm.writeHNString("SCRI", script); - if (!icon.empty()) - esm.writeHNString("ITEX", icon); - if (!text.empty()) - esm.writeHNString("TEXT", text); - if (!enchant.empty()) - esm.writeHNString("ENAM", enchant); + esm.writeHNOString("SCRI", script); + esm.writeHNOString("ITEX", icon); + esm.writeHNOString("TEXT", text); + esm.writeHNOString("ENAM", enchant); } } diff --git a/components/esm/loadbsgn.cpp b/components/esm/loadbsgn.cpp index 9488f355f4..de76e1949a 100644 --- a/components/esm/loadbsgn.cpp +++ b/components/esm/loadbsgn.cpp @@ -14,10 +14,8 @@ void BirthSign::load(ESMReader &esm) void BirthSign::save(ESMWriter &esm) { esm.writeHNString("FNAM", name); - if (!texture.empty()) - esm.writeHNString("TNAM", texture); - if (!description.empty()) - esm.writeHNString("DESC", description); + esm.writeHNOString("TNAM", texture); + esm.writeHNOString("DESC", description); powers.save(esm); } diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index 8b3d09183d..f6db5c70cc 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -100,18 +100,15 @@ void Cell::save(ESMWriter &esm) { if (water != 0) esm.writeHNT("WHGT", water); + if (data.flags & QuasiEx) - { - if (!region.empty()) - esm.writeHNString("RGNN", region); - } + esm.writeHNOString("RGNN", region); else esm.writeHNT("AMBI", ambi, 16); } else { - if (!region.empty()) - esm.writeHNString("RGNN", region); + esm.writeHNOString("RGNN", region); if (mapColor != 0) esm.writeHNT("NAM5", mapColor); } diff --git a/components/esm/loadclas.cpp b/components/esm/loadclas.cpp index 05cbfe7093..e13442dcf4 100644 --- a/components/esm/loadclas.cpp +++ b/components/esm/loadclas.cpp @@ -29,8 +29,7 @@ void Class::save(ESMWriter &esm) { esm.writeHNString("FNAM", name); esm.writeHNT("CLDT", data, 60); - if (!description.empty()) - esm.writeHNString("DESC", description); + esm.writeHNOString("DESC", description); } } diff --git a/components/esm/loadclot.cpp b/components/esm/loadclot.cpp index b1c6783484..cd884d2065 100644 --- a/components/esm/loadclot.cpp +++ b/components/esm/loadclot.cpp @@ -19,19 +19,15 @@ void Clothing::load(ESMReader &esm) void Clothing::save(ESMWriter &esm) { esm.writeHNString("MODL", model); - if (!name.empty()) - esm.writeHNString("FNAM", name); + esm.writeHNOString("FNAM", name); esm.writeHNT("CTDT", data, 12); - if (!script.empty()) - esm.writeHNString("SCRI", script); - if (!icon.empty()) - esm.writeHNString("ITEX", icon); + esm.writeHNOString("SCRI", script); + esm.writeHNOString("ITEX", icon); parts.save(esm); - if (!enchant.empty()) - esm.writeHNString("ENAM", enchant); + esm.writeHNOString("ENAM", enchant); } } diff --git a/components/esm/loadcont.cpp b/components/esm/loadcont.cpp index ba90e52ce7..176c4ec050 100644 --- a/components/esm/loadcont.cpp +++ b/components/esm/loadcont.cpp @@ -41,13 +41,11 @@ void Container::load(ESMReader &esm) void Container::save(ESMWriter &esm) { esm.writeHNString("MODL", model); - if (!name.empty()) - esm.writeHNString("FNAM", name); + esm.writeHNOString("FNAM", name); esm.writeHNT("CNDT", weight, 4); esm.writeHNT("FLAG", flags, 4); - if (!script.empty()) - esm.writeHNString("SCRI", script); + esm.writeHNOString("SCRI", script); inventory.save(esm); } diff --git a/components/esm/loadcrea.cpp b/components/esm/loadcrea.cpp index 0cab2761e3..f5ffb694f5 100644 --- a/components/esm/loadcrea.cpp +++ b/components/esm/loadcrea.cpp @@ -40,12 +40,9 @@ void Creature::load(ESMReader &esm, const std::string& id) void Creature::save(ESMWriter &esm) { esm.writeHNString("MODL", model); - if (!original.empty()) - esm.writeHNString("CNAM", original); - if (!name.empty()) - esm.writeHNString("FNAM", name); - if (!script.empty()) - esm.writeHNString("SCRI", script); + esm.writeHNOString("CNAM", original); + esm.writeHNOString("FNAM", name); + esm.writeHNOString("SCRI", script); esm.writeHNT("NPDT", data, 96); esm.writeHNT("FLAG", flags); if (scale != 1.0) diff --git a/components/esm/loaddoor.cpp b/components/esm/loaddoor.cpp index 513eac7537..45af407e17 100644 --- a/components/esm/loaddoor.cpp +++ b/components/esm/loaddoor.cpp @@ -14,14 +14,10 @@ void Door::load(ESMReader &esm) void Door::save(ESMWriter &esm) { esm.writeHNString("MODL", model); - if (!name.empty()) - esm.writeHNString("FNAM", name); - if (!script.empty()) - esm.writeHNString("SCRI", script); - if (!openSound.empty()) - esm.writeHNString("SNAM", openSound); - if (!closeSound.empty()) - esm.writeHNString("ANAM", closeSound); + esm.writeHNOString("FNAM", name); + esm.writeHNOString("SCRI", script); + esm.writeHNOString("SNAM", openSound); + esm.writeHNOString("ANAM", closeSound); } } diff --git a/components/esm/loadinfo.cpp b/components/esm/loadinfo.cpp index c240aba87e..63b3fe3a2a 100644 --- a/components/esm/loadinfo.cpp +++ b/components/esm/loadinfo.cpp @@ -156,8 +156,7 @@ void DialInfo::save(ESMWriter &esm) } } - if (!resultScript.empty()) - esm.writeHNString("BNAM", resultScript); + esm.writeHNOString("BNAM", resultScript); switch(questStatus) { diff --git a/components/esm/loadingr.cpp b/components/esm/loadingr.cpp index b71f6f13db..b8b8aea06e 100644 --- a/components/esm/loadingr.cpp +++ b/components/esm/loadingr.cpp @@ -16,10 +16,8 @@ void Ingredient::save(ESMWriter &esm) esm.writeHNString("MODL", model); esm.writeHNString("FNAM", name); esm.writeHNT("IRDT", data, 56); - if (!script.empty()) - esm.writeHNString("SCRI", script); - if (!icon.empty()) - esm.writeHNString("ITEX", script); + esm.writeHNOString("SCRI", script); + esm.writeHNOString("ITEX", script); } } diff --git a/components/esm/loadligh.cpp b/components/esm/loadligh.cpp index b7530eb6c0..2b1d37461f 100644 --- a/components/esm/loadligh.cpp +++ b/components/esm/loadligh.cpp @@ -16,15 +16,11 @@ void Light::load(ESMReader &esm) void Light::save(ESMWriter &esm) { esm.writeHNString("MODL", model); - if (!name.empty()) - esm.writeHNString("FNAM", name); - if (!icon.empty()) - esm.writeHNString("ITEX", icon); + esm.writeHNOString("FNAM", name); + esm.writeHNOString("ITEX", icon); esm.writeHNT("LHDT", data, 24); - if (!script.empty()) - esm.writeHNString("SCRI", script); - if (!sound.empty()) - esm.writeHNString("SNAM", sound); + esm.writeHNOString("SCRI", script); + esm.writeHNOString("SNAM", sound); } } diff --git a/components/esm/loadlocks.cpp b/components/esm/loadlocks.cpp index b9f1d35cae..ff01aac37b 100644 --- a/components/esm/loadlocks.cpp +++ b/components/esm/loadlocks.cpp @@ -44,10 +44,8 @@ void Tool::save(ESMWriter &esm) } esm.writeT(data, 16); - if (!script.empty()) - esm.writeHNString("SCRI", script); - if (!icon.empty()) - esm.writeHNString("ITEX", icon); + esm.writeHNOString("SCRI", script); + esm.writeHNOString("ITEX", icon); } From b81ac363fc520b09f1109a0c328bff8b53649601 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Fri, 6 Apr 2012 21:28:58 +0200 Subject: [PATCH 03/14] Write names with a small sanity check --- components/esm/esm_writer.cpp | 1 + components/esm/loadland.cpp | 2 +- components/esm/loadlocks.cpp | 6 +++--- components/esm/loadpgrd.cpp | 4 ++-- components/esm/loadscpt.cpp | 2 +- 5 files changed, 8 insertions(+), 7 deletions(-) diff --git a/components/esm/esm_writer.cpp b/components/esm/esm_writer.cpp index da040c664d..b4690807c6 100644 --- a/components/esm/esm_writer.cpp +++ b/components/esm/esm_writer.cpp @@ -17,6 +17,7 @@ void ESMWriter::writeHString(const std::string& data) void ESMWriter::writeName(const std::string& name) { + assert((name.size() == 4 && name.c_str()[3] != '\0') || (name.size() == 5 && name.c_str()[4] == '\0')); write(name.c_str(), name.size()-1); } diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp index 4d3a4a0edf..9aa02e4781 100644 --- a/components/esm/loadland.cpp +++ b/components/esm/loadland.cpp @@ -84,7 +84,7 @@ void Land::load(ESMReader &esm) void Land::save(ESMWriter &esm) { - esm.writeHString("INTV"); + esm.writeName("INTV"); esm.writeT(X); esm.writeT(Y); diff --git a/components/esm/loadlocks.cpp b/components/esm/loadlocks.cpp index ff01aac37b..f49de1bc8f 100644 --- a/components/esm/loadlocks.cpp +++ b/components/esm/loadlocks.cpp @@ -38,9 +38,9 @@ void Tool::save(ESMWriter &esm) switch(type) { - case Type_Repair: esm.writeHString("RIDT"); break; - case Type_Pick: esm.writeHString("LKDT"); break; - case Type_Probe: esm.writeHString("PBDT"); break; + case Type_Repair: esm.writeName("RIDT"); break; + case Type_Pick: esm.writeName("LKDT"); break; + case Type_Probe: esm.writeName("PBDT"); break; } esm.writeT(data, 16); diff --git a/components/esm/loadpgrd.cpp b/components/esm/loadpgrd.cpp index 572378dad8..41dd341748 100644 --- a/components/esm/loadpgrd.cpp +++ b/components/esm/loadpgrd.cpp @@ -74,7 +74,7 @@ void Pathgrid::save(ESMWriter &esm) if (!points.empty()) { - esm.writeHString("PGRP"); + esm.writeName("PGRP"); for (PointList::iterator it = points.begin(); it != points.end(); ++it) { esm.writeT(*it); @@ -83,7 +83,7 @@ void Pathgrid::save(ESMWriter &esm) if (!edges.empty()) { - esm.writeHString("PGRC"); + esm.writeName("PGRC"); for (std::vector::iterator it = edges.begin(); it != edges.end(); ++it) { esm.writeT(it->v1); diff --git a/components/esm/loadscpt.cpp b/components/esm/loadscpt.cpp index 86d1d8e294..291259bc08 100644 --- a/components/esm/loadscpt.cpp +++ b/components/esm/loadscpt.cpp @@ -44,7 +44,7 @@ void Script::save(ESMWriter &esm) if (!varNames.empty()) { - esm.writeHString("SCVR"); + esm.writeName("SCVR"); for (std::vector::iterator it = varNames.begin(); it != varNames.end(); ++it) { esm.writeT(it->c_str(), it->size()); From 47013799ea43d6262f63588506d823633a213ba3 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Fri, 6 Apr 2012 22:25:33 +0200 Subject: [PATCH 04/14] Fleshing out the esm writer a bit --- components/esm/esm_writer.cpp | 38 ++++++++++++++++++++++++++++++++++- components/esm/esm_writer.hpp | 13 ++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/components/esm/esm_writer.cpp b/components/esm/esm_writer.cpp index b4690807c6..1875ae330d 100644 --- a/components/esm/esm_writer.cpp +++ b/components/esm/esm_writer.cpp @@ -3,6 +3,42 @@ namespace ESM { +void ESMWriter::setVersion(Version ver) +{ + m_header.version = ver; +} + +void ESMWriter::setType(FileType type) +{ + m_header.type = type; +} + +void ESMWriter::setAuthor(const std::string& auth) +{ + strcpy(auth.c_str(), m_header.author, 32); +} + +void ESMWriter::setDescription(const std::string& desc) +{ + strcpy(desc.c_str(), m_header.desc, 256); +} + +void ESMWriter::save(const std::string& file) +{ + std::ostream os(file, "wb"); + save(os); +} + +void ESMWriter::save(std::ostream& file) +{ + // TODO: Saving +} + +void ESMWriter::close() +{ + // TODO: Saving +} + void ESMWriter::writeHNString(const std::string& name, const std::string& data) { writeName(name); @@ -17,7 +53,7 @@ void ESMWriter::writeHString(const std::string& data) void ESMWriter::writeName(const std::string& name) { - assert((name.size() == 4 && name.c_str()[3] != '\0') || (name.size() == 5 && name.c_str()[4] == '\0')); + assert((name.size() == 4 && name[3] != '\0') || (name.size() == 5 && name[4] == '\0')); write(name.c_str(), name.size()-1); } diff --git a/components/esm/esm_writer.hpp b/components/esm/esm_writer.hpp index 5adf32049a..21cb42de9a 100644 --- a/components/esm/esm_writer.hpp +++ b/components/esm/esm_writer.hpp @@ -11,6 +11,16 @@ namespace ESM { class ESMWriter { public: + void setVersion(Version ver); + void setType(FileType type); + + void setAuthor(const std::string& author); + void setDescription(const std::string& desc); + + void save(const std::string& file); + void save(std::ostream& file); + void close(); + void writeHNString(const std::string& name, const std::string& data); void writeHNOString(const std::string& name, const std::string& data) { @@ -65,6 +75,9 @@ public: private: std::ostream m_stream; + + HEDRstruct m_header; + SaveData m_saveData; }; } From 0fd48c42295c7c8d1bfc0ecb2be85eaa2d270209 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Sun, 8 Apr 2012 11:51:52 +0200 Subject: [PATCH 05/14] Extended the esmtool a bit and prepared all records for saving. --- apps/esmtool/esmtool.cpp | 899 +++++++++++++++++++++--------- components/esm/esm_writer.cpp | 46 +- components/esm/esm_writer.hpp | 14 +- components/esm/loadacti.hpp | 5 +- components/esm/loadalch.hpp | 5 +- components/esm/loadappa.hpp | 5 +- components/esm/loadarmo.hpp | 5 +- components/esm/loadbody.hpp | 5 +- components/esm/loadbook.hpp | 5 +- components/esm/loadbsgn.hpp | 5 +- components/esm/loadcell.hpp | 5 +- components/esm/loadclas.hpp | 5 +- components/esm/loadclot.hpp | 5 +- components/esm/loadcont.hpp | 5 +- components/esm/loadcrea.cpp | 5 +- components/esm/loadcrea.hpp | 8 +- components/esm/loadcrec.hpp | 17 +- components/esm/loaddial.hpp | 5 +- components/esm/loaddoor.hpp | 5 +- components/esm/loadench.hpp | 5 +- components/esm/loadfact.hpp | 5 +- components/esm/loadglob.hpp | 5 +- components/esm/loadgmst.hpp | 5 +- components/esm/loadinfo.hpp | 5 +- components/esm/loadingr.hpp | 5 +- components/esm/loadland.hpp | 5 +- components/esm/loadlevlist.hpp | 11 +- components/esm/loadligh.hpp | 5 +- components/esm/loadlocks.hpp | 17 +- components/esm/loadltex.hpp | 5 +- components/esm/loadmgef.hpp | 5 +- components/esm/loadmisc.hpp | 5 +- components/esm/loadnpc.cpp | 5 +- components/esm/loadnpc.hpp | 8 +- components/esm/loadnpcc.hpp | 5 +- components/esm/loadpgrd.hpp | 5 +- components/esm/loadrace.hpp | 5 +- components/esm/loadregn.hpp | 5 +- components/esm/loadscpt.hpp | 5 +- components/esm/loadskil.hpp | 5 +- components/esm/loadsndg.hpp | 5 +- components/esm/loadsoun.hpp | 5 +- components/esm/loadspel.hpp | 5 +- components/esm/loadsscr.hpp | 5 +- components/esm/loadstat.hpp | 5 +- components/esm/loadweap.hpp | 5 +- components/esm/record.hpp | 70 +++ components/esm/records.hpp | 54 +- components/esm_store/reclists.hpp | 3 +- 49 files changed, 950 insertions(+), 387 deletions(-) create mode 100644 components/esm/record.hpp diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp index f417d5c608..ea9a388a52 100644 --- a/apps/esmtool/esmtool.cpp +++ b/apps/esmtool/esmtool.cpp @@ -1,8 +1,10 @@ #include +#include #include #include +#include #include #define ESMTOOL_VERSION 1.1 @@ -16,19 +18,33 @@ namespace bpo = boost::program_options; void printRaw(ESMReader &esm); void loadCell(Cell &cell, ESMReader &esm, bool quiet); +struct ESMData +{ + std::string author; + std::string description; + ESMReader::MasterList masters; + + std::list records; +}; + // Based on the legacy struct struct Arguments { unsigned int raw_given; unsigned int quiet_given; unsigned int loadcells_given; + + std::string mode; std::string encoding; std::string filename; + std::string outname; + + ESMData data; }; 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] file \nAllowed options"); + bpo::options_description desc("Inspect and extract from Morrowind ES files (ESM, ESP, ESS)\nSyntax: esmtool [options] mode infile [outfile]\nAllowed options"); desc.add_options() ("help,h", "print help message.") @@ -38,11 +54,11 @@ bool parseOptions (int argc, char** argv, Arguments &info) ("loadcells,C", "Browse through contents of all cells.") ( "encoding,e", bpo::value(&(info.encoding))-> - default_value("win1252"), - "Character encoding used in ESMTool:\n" - "\n\twin1250 - Central and Eastern European such as Polish, Czech, Slovak, Hungarian, Slovene, Bosnian, Croatian, Serbian (Latin script), Romanian and Albanian languages\n" - "\n\twin1251 - Cyrillic alphabet such as Russian, Bulgarian, Serbian Cyrillic and other languages\n" - "\n\twin1252 - Western European (Latin) alphabet, used by default") + default_value("win1252"), + "Character encoding used in ESMTool:\n" + "\n\twin1250 - Central and Eastern European such as Polish, Czech, Slovak, Hungarian, Slovene, Bosnian, Croatian, Serbian (Latin script), Romanian and Albanian languages\n" + "\n\twin1251 - Cyrillic alphabet such as Russian, Bulgarian, Serbian Cyrillic and other languages\n" + "\n\twin1252 - Western European (Latin) alphabet, used by default") ; std::string finalText = "\nIf no option is given, the default action is to parse all records in the archive\nand display diagnostic information."; @@ -51,11 +67,12 @@ bool parseOptions (int argc, char** argv, Arguments &info) bpo::options_description hidden("Hidden Options"); hidden.add_options() + ( "mode,m", bpo::value(), "esmtool mode") ( "input-file,i", bpo::value< vector >(), "input file") ; bpo::positional_options_description p; - p.add("input-file", -1); + p.add("mode", 1).add("input-file", 2); // there might be a better way to do this bpo::options_description all; @@ -77,6 +94,12 @@ bool parseOptions (int argc, char** argv, Arguments &info) std::cout << "ESMTool version " << ESMTOOL_VERSION << std::endl; return false; } + if (!variables.count("mode")) + { + std::cout << "No mode specified!" << std::endl << std::endl + << desc << finalText << std::endl; + return false; + } if ( !variables.count("input-file") ) { @@ -86,14 +109,18 @@ bool parseOptions (int argc, char** argv, Arguments &info) } // handling gracefully the user adding multiple files - if (variables["input-file"].as< vector >().size() > 1) - { - std::cout << "\nERROR: more than one ES file specified\n\n"; - std::cout << desc << finalText << std::endl; - return false; - } +/* if (variables["input-file"].as< vector >().size() > 1) + { + std::cout << "\nERROR: more than one ES file specified\n\n"; + std::cout << desc << finalText << std::endl; + return false; + }*/ + + info.mode = variables["mode"].as(); info.filename = variables["input-file"].as< vector >()[0]; + if (variables["input-file"].as< vector >().size() > 1) + info.outname = variables["input-file"].as< vector >()[1]; info.raw_given = variables.count ("raw"); info.quiet_given = variables.count ("quiet"); @@ -122,288 +149,612 @@ bool parseOptions (int argc, char** argv, Arguments &info) return true; } +int load(Arguments& info); +int clone(Arguments& info); int main(int argc, char**argv) { - Arguments info; - if(!parseOptions (argc, argv, info)) - return 1; + Arguments info; + if(!parseOptions (argc, argv, info)) + return 1; - ESMReader esm; - esm.setEncoding(info.encoding); - - string filename = info.filename; - cout << "\nFile: " << filename << endl; - - try { - - if(info.raw_given) + if (info.mode == "dump") + return load(info); + else if (info.mode == "clone") + return clone(info); + else { - cout << "RAW file listing:\n"; - - esm.openRaw(filename); - - printRaw(esm); - - return 0; + cout << "Invalid or no mode specified, dying horribly. Have a nice day." << endl; + return 1; } - bool quiet = info.quiet_given; - bool loadCells = info.loadcells_given; - - esm.open(filename); - - cout << "Author: " << esm.getAuthor() << endl; - cout << "Description: " << esm.getDesc() << endl; - cout << "File format version: " << esm.getFVer() << endl; - cout << "Special flag: " << esm.getSpecial() << endl; - cout << "Masters:\n"; - ESMReader::MasterList m = esm.getMasters(); - for(unsigned int i=0;i skipped; + + try { + + if(info.raw_given) + { + cout << "RAW file listing:\n"; + + esm.openRaw(filename); + + printRaw(esm); + + return 0; + } + + bool quiet = (info.quiet_given || info.mode == "clone"); + bool loadCells = (info.loadcells_given || info.mode == "clone"); + bool save = (info.mode == "clone"); + + esm.open(filename); + + info.data.author = esm.getAuthor(); + info.data.description = esm.getDesc(); + info.data.masters = esm.getMasters(); + + cout << "Author: " << esm.getAuthor() << endl; + cout << "Description: " << esm.getDesc() << endl; + cout << "File format version: " << esm.getFVer() << endl; + cout << "Special flag: " << esm.getSpecial() << endl; + cout << "Masters:\n"; + ESMReader::MasterList m = esm.getMasters(); + for(unsigned int i=0;i::iterator it = info.data.records.begin(); it != info.data.records.end();) + { + delete *it; + info.data.records.erase(it++); + } + return 1; + } + + return 0; +} + +#include + +int clone(Arguments& info) +{ + if (info.outname.empty()) + { + cout << "You need to specify an output name" << endl; + return 1; + } + + if (load(info) != 0) + { + cout << "Failed to load, aborting." << endl; + return 1; + } + + cout << "Loaded " << info.data.records.size() << " records:" << endl; + + std::map records; + + for (std::list::iterator it = info.data.records.begin(); it != info.data.records.end();) + { + Record* rec = *it; + NAME n; + n.val = rec->getName(); + records[n.toString()]++; + + delete rec; + info.data.records.erase(it++); + } + + for (std::map::iterator it = records.begin(); it != records.end(); ++it) + { + std::string n = it->first; + cout << n << ": " << it->second << " records." << endl; + } + + return 0; +} diff --git a/components/esm/esm_writer.cpp b/components/esm/esm_writer.cpp index 1875ae330d..57517b0f53 100644 --- a/components/esm/esm_writer.cpp +++ b/components/esm/esm_writer.cpp @@ -1,4 +1,6 @@ #include "esm_writer.hpp" +#include +#include namespace ESM { @@ -15,22 +17,31 @@ void ESMWriter::setType(FileType type) void ESMWriter::setAuthor(const std::string& auth) { - strcpy(auth.c_str(), m_header.author, 32); + strncpy((char*)&m_header.author, auth.c_str(), 32); } void ESMWriter::setDescription(const std::string& desc) { - strcpy(desc.c_str(), m_header.desc, 256); + strncpy((char*)&m_header.desc, desc.c_str(), 256); } void ESMWriter::save(const std::string& file) { - std::ostream os(file, "wb"); - save(os); + std::ofstream fs(file.c_str(), std::ios_base::out | std::ios_base::trunc); + save(fs); + fs.close(); } void ESMWriter::save(std::ostream& file) { + m_stream = &file; + + startRecord("TES3"); + writeT(0); + writeT(0); + + endRecord(); + // TODO: Saving } @@ -39,6 +50,28 @@ void ESMWriter::close() // TODO: Saving } +void ESMWriter::startRecord(const std::string& name) +{ + writeName(name); + RecordData rec; + rec.position = m_stream->tellp(); + rec.size = 0; + m_records.push_back(rec); + writeT(0); +} + +void ESMWriter::endRecord() +{ + std::streampos cur = m_stream->tellp(); + RecordData rec = m_records.back(); + m_records.pop_back(); + + m_stream->seekp(rec.position); + m_stream->write((char*)&rec.size, sizeof(int)); + + m_stream->seekp(cur); +} + void ESMWriter::writeHNString(const std::string& name, const std::string& data) { writeName(name); @@ -59,7 +92,10 @@ void ESMWriter::writeName(const std::string& name) void ESMWriter::write(const char* data, int size) { - m_stream.write(data, size); + if (!m_records.empty()) + m_records.back().size += size; + + m_stream->write(data, size); } } diff --git a/components/esm/esm_writer.hpp b/components/esm/esm_writer.hpp index 21cb42de9a..3999e987d2 100644 --- a/components/esm/esm_writer.hpp +++ b/components/esm/esm_writer.hpp @@ -2,6 +2,7 @@ #define _ESM_WRITER_H #include +#include #include #include "esm_common.hpp" @@ -10,6 +11,12 @@ namespace ESM { class ESMWriter { + struct RecordData + { + std::streampos position; + int size; + }; + public: void setVersion(Version ver); void setType(FileType type); @@ -68,13 +75,16 @@ public: assert(sizeof(T) == size); writeT(data); } - + + void startRecord(const std::string& name); + void endRecord(); void writeHString(const std::string& data); void writeName(const std::string& data); void write(const char* data, int size); private: - std::ostream m_stream; + std::vector m_records; + std::ostream* m_stream; HEDRstruct m_header; SaveData m_saveData; diff --git a/components/esm/loadacti.hpp b/components/esm/loadacti.hpp index 3f968bc7c8..083c8fc677 100644 --- a/components/esm/loadacti.hpp +++ b/components/esm/loadacti.hpp @@ -1,18 +1,21 @@ #ifndef _ESM_ACTI_H #define _ESM_ACTI_H +#include "record.hpp" #include "esm_reader.hpp" #include "esm_writer.hpp" namespace ESM { -struct Activator +struct Activator : public Record { std::string name, script, model; void load(ESMReader &esm); void save(ESMWriter &esm); + + int getName() { return REC_ACTI; } }; } #endif diff --git a/components/esm/loadalch.hpp b/components/esm/loadalch.hpp index b447fe50c4..5adc44ee23 100644 --- a/components/esm/loadalch.hpp +++ b/components/esm/loadalch.hpp @@ -1,6 +1,7 @@ #ifndef _ESM_ALCH_H #define _ESM_ALCH_H +#include "record.hpp" #include "esm_reader.hpp" #include "esm_writer.hpp" #include "defs.hpp" @@ -12,7 +13,7 @@ namespace ESM * Alchemy item (potions) */ -struct Potion +struct Potion : public Record { struct ALDTstruct { @@ -27,6 +28,8 @@ struct Potion void load(ESMReader &esm); void save(ESMWriter &esm); + + int getName() { return REC_ALCH; } }; } #endif diff --git a/components/esm/loadappa.hpp b/components/esm/loadappa.hpp index ff105a3079..8321778dba 100644 --- a/components/esm/loadappa.hpp +++ b/components/esm/loadappa.hpp @@ -1,6 +1,7 @@ #ifndef _ESM_APPA_H #define _ESM_APPA_H +#include "record.hpp" #include "esm_reader.hpp" #include "esm_writer.hpp" @@ -11,7 +12,7 @@ namespace ESM * Alchemist apparatus */ -struct Apparatus +struct Apparatus : public Record { enum AppaType { @@ -34,6 +35,8 @@ struct Apparatus void load(ESMReader &esm); void save(ESMWriter &esm); + + int getName() { return REC_APPA; } }; } #endif diff --git a/components/esm/loadarmo.hpp b/components/esm/loadarmo.hpp index 5026696c24..1b2cb8653e 100644 --- a/components/esm/loadarmo.hpp +++ b/components/esm/loadarmo.hpp @@ -1,6 +1,7 @@ #ifndef _ESM_ARMO_H #define _ESM_ARMO_H +#include "record.hpp" #include "esm_reader.hpp" #include "esm_writer.hpp" @@ -54,7 +55,7 @@ struct PartReferenceList void save(ESMWriter &esm); }; -struct Armor +struct Armor : public Record { enum Type { @@ -85,6 +86,8 @@ struct Armor void load(ESMReader &esm); void save(ESMWriter &esm); + + int getName() { return REC_ARMO; } }; } #endif diff --git a/components/esm/loadbody.hpp b/components/esm/loadbody.hpp index 46cb1d899d..90605e39d4 100644 --- a/components/esm/loadbody.hpp +++ b/components/esm/loadbody.hpp @@ -1,13 +1,14 @@ #ifndef _ESM_BODY_H #define _ESM_BODY_H +#include "record.hpp" #include "esm_reader.hpp" #include "esm_writer.hpp" namespace ESM { -struct BodyPart +struct BodyPart : public Record { enum MeshPart { @@ -54,6 +55,8 @@ struct BodyPart void load(ESMReader &esm); void save(ESMWriter &esm); + + int getName() { return REC_BODY; } }; } #endif diff --git a/components/esm/loadbook.hpp b/components/esm/loadbook.hpp index a46135cc0d..a5a891a587 100644 --- a/components/esm/loadbook.hpp +++ b/components/esm/loadbook.hpp @@ -1,6 +1,7 @@ #ifndef _ESM_BOOK_H #define _ESM_BOOK_H +#include "record.hpp" #include "esm_reader.hpp" #include "esm_writer.hpp" @@ -11,7 +12,7 @@ namespace ESM * Books, magic scrolls, notes and so on */ -struct Book +struct Book : public Record { struct BKDTstruct { @@ -24,6 +25,8 @@ struct Book void load(ESMReader &esm); void save(ESMWriter &esm); + + int getName() { return REC_BOOK; } }; } #endif diff --git a/components/esm/loadbsgn.hpp b/components/esm/loadbsgn.hpp index d00664bff8..b094b2e498 100644 --- a/components/esm/loadbsgn.hpp +++ b/components/esm/loadbsgn.hpp @@ -1,6 +1,7 @@ #ifndef _ESM_BSGN_H #define _ESM_BSGN_H +#include "record.hpp" #include "defs.hpp" #include "esm_reader.hpp" #include "esm_writer.hpp" @@ -8,7 +9,7 @@ namespace ESM { -struct BirthSign +struct BirthSign : public Record { std::string name, description, texture; @@ -17,6 +18,8 @@ struct BirthSign void load(ESMReader &esm); void save(ESMWriter &esm); + + int getName() { return REC_BSGN; } }; } #endif diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index 8d461369c8..f03c541b7e 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -1,6 +1,7 @@ #ifndef _ESM_CELL_H #define _ESM_CELL_H +#include "record.hpp" #include "esm_reader.hpp" #include "esm_writer.hpp" #include "defs.hpp" @@ -84,7 +85,7 @@ public: (using ESMReader::getContext()) and jumping back into place whenever we need to load a given cell. */ -struct Cell +struct Cell : public Record { enum Flags { @@ -123,6 +124,8 @@ struct Cell void load(ESMReader &esm); void save(ESMWriter &esm); + int getName() { return REC_CELL; } + bool isExterior() const { return !(data.flags & Interior); diff --git a/components/esm/loadclas.hpp b/components/esm/loadclas.hpp index a89481a7ac..084f1edb1c 100644 --- a/components/esm/loadclas.hpp +++ b/components/esm/loadclas.hpp @@ -1,6 +1,7 @@ #ifndef _ESM_CLAS_H #define _ESM_CLAS_H +#include "record.hpp" #include "esm_reader.hpp" #include "esm_writer.hpp" @@ -13,7 +14,7 @@ namespace ESM // These flags tells us which items should be auto-calculated for this // class -struct Class +struct Class : public Record { enum AutoCalc { @@ -63,6 +64,8 @@ struct Class void load(ESMReader &esm); void save(ESMWriter &esm); + + int getName() { return REC_CLAS; } }; } #endif diff --git a/components/esm/loadclot.hpp b/components/esm/loadclot.hpp index 77ef3786a8..4d0ec06cd8 100644 --- a/components/esm/loadclot.hpp +++ b/components/esm/loadclot.hpp @@ -1,6 +1,7 @@ #ifndef _ESM_CLOT_H #define _ESM_CLOT_H +#include "record.hpp" #include "esm_reader.hpp" #include "esm_writer.hpp" #include "loadarmo.hpp" @@ -12,7 +13,7 @@ namespace ESM * Clothing */ -struct Clothing +struct Clothing : public Record { enum Type { @@ -43,6 +44,8 @@ struct Clothing void load(ESMReader &esm); void save(ESMWriter &esm); + + int getName() { return REC_CLOT; } }; } #endif diff --git a/components/esm/loadcont.hpp b/components/esm/loadcont.hpp index bf6994f9af..7d8952e388 100644 --- a/components/esm/loadcont.hpp +++ b/components/esm/loadcont.hpp @@ -1,6 +1,7 @@ #ifndef _ESM_CONT_H #define _ESM_CONT_H +#include "record.hpp" #include "esm_reader.hpp" #include "esm_writer.hpp" @@ -25,7 +26,7 @@ struct InventoryList void save(ESMWriter &esm); }; -struct Container +struct Container : public Record { enum Flags { @@ -42,6 +43,8 @@ struct Container void load(ESMReader &esm); void save(ESMWriter &esm); + + int getName() { return REC_CONT; } }; } #endif diff --git a/components/esm/loadcrea.cpp b/components/esm/loadcrea.cpp index f5ffb694f5..7b84a7f296 100644 --- a/components/esm/loadcrea.cpp +++ b/components/esm/loadcrea.cpp @@ -2,10 +2,13 @@ namespace ESM { -void Creature::load(ESMReader &esm, const std::string& id) +void Creature::setID(const std::string& id) { mId = id; +} +void Creature::load(ESMReader &esm) +{ model = esm.getHNString("MODL"); original = esm.getHNOString("CNAM"); name = esm.getHNOString("FNAM"); diff --git a/components/esm/loadcrea.hpp b/components/esm/loadcrea.hpp index 2f5f4061d9..3035003cf8 100644 --- a/components/esm/loadcrea.hpp +++ b/components/esm/loadcrea.hpp @@ -1,6 +1,7 @@ #ifndef _ESM_CREA_H #define _ESM_CREA_H +#include "record.hpp" #include "esm_reader.hpp" #include "esm_writer.hpp" #include "loadcont.hpp" @@ -13,7 +14,7 @@ namespace ESM * */ -struct Creature +struct Creature : public Record { // Default is 0x48? enum Flags @@ -64,8 +65,11 @@ struct Creature std::string mId; - void load(ESMReader &esm, const std::string& id); + void setID(const std::string& id); + void load(ESMReader &esm); void save(ESMWriter &esm); + + int getName() { return REC_CREA; } }; } #endif diff --git a/components/esm/loadcrec.hpp b/components/esm/loadcrec.hpp index 056f572ae4..0a575921a8 100644 --- a/components/esm/loadcrec.hpp +++ b/components/esm/loadcrec.hpp @@ -1,6 +1,7 @@ #ifndef _ESM_CREC_H #define _ESM_CREC_H +#include "record.hpp" #include "esm_reader.hpp" #include "esm_writer.hpp" @@ -10,29 +11,33 @@ namespace ESM { */ /// Changes a creature -struct LoadCREC +struct LoadCREC : public Record { - void load(ESMReader &esm) + void load(ESMReader &esm) { esm.skipRecord(); } - void save(ESMWriter &esm) + void save(ESMWriter &esm) { } + + int getName() { return REC_CREC; } }; /// Changes an item list / container -struct LoadCNTC +struct LoadCNTC : public Record { - void load(ESMReader &esm) + void load(ESMReader &esm) { esm.skipRecord(); } - void save(ESMWriter &esm) + void save(ESMWriter &esm) { } + + int getName() { return REC_CNTC; } }; } #endif diff --git a/components/esm/loaddial.hpp b/components/esm/loaddial.hpp index a19b0c7ad5..92818598e8 100644 --- a/components/esm/loaddial.hpp +++ b/components/esm/loaddial.hpp @@ -3,6 +3,7 @@ #include +#include "record.hpp" #include "esm_reader.hpp" #include "esm_writer.hpp" #include "loadinfo.hpp" @@ -15,7 +16,7 @@ namespace ESM * the INFO records following the DIAL. */ -struct Dialogue +struct Dialogue : public Record { enum Type { @@ -32,6 +33,8 @@ struct Dialogue void load(ESMReader &esm); void save(ESMWriter &esm); + + int getName() { return REC_DIAL; } }; } #endif diff --git a/components/esm/loaddoor.hpp b/components/esm/loaddoor.hpp index 1234ac7f91..e8b3be970b 100644 --- a/components/esm/loaddoor.hpp +++ b/components/esm/loaddoor.hpp @@ -1,18 +1,21 @@ #ifndef _ESM_DOOR_H #define _ESM_DOOR_H +#include "record.hpp" #include "esm_reader.hpp" #include "esm_writer.hpp" namespace ESM { -struct Door +struct Door : public Record { std::string name, model, script, openSound, closeSound; void load(ESMReader &esm); void save(ESMWriter &esm); + + int getName() { return REC_DOOR; } }; } #endif diff --git a/components/esm/loadench.hpp b/components/esm/loadench.hpp index 6091669832..1cb417c9f4 100644 --- a/components/esm/loadench.hpp +++ b/components/esm/loadench.hpp @@ -1,6 +1,7 @@ #ifndef _ESM_ENCH_H #define _ESM_ENCH_H +#include "record.hpp" #include "esm_reader.hpp" #include "esm_writer.hpp" #include "defs.hpp" @@ -12,7 +13,7 @@ namespace ESM * Enchantments */ -struct Enchantment +struct Enchantment : public Record { enum Type { @@ -36,6 +37,8 @@ struct Enchantment void load(ESMReader &esm); void save(ESMWriter &esm); + + int getName() { return REC_ENCH; } }; } #endif diff --git a/components/esm/loadfact.hpp b/components/esm/loadfact.hpp index 686554da32..f62c92e19a 100644 --- a/components/esm/loadfact.hpp +++ b/components/esm/loadfact.hpp @@ -1,6 +1,7 @@ #ifndef _ESM_FACT_H #define _ESM_FACT_H +#include "record.hpp" #include "esm_reader.hpp" #include "esm_writer.hpp" @@ -24,7 +25,7 @@ struct RankData int factReaction; // Reaction from faction members }; -struct Faction +struct Faction : public Record { std::string id, name; @@ -55,6 +56,8 @@ struct Faction void load(ESMReader &esm); void save(ESMWriter &esm); + + int getName() { return REC_FACT; } }; } #endif diff --git a/components/esm/loadglob.hpp b/components/esm/loadglob.hpp index 669475fe71..8a6991490c 100644 --- a/components/esm/loadglob.hpp +++ b/components/esm/loadglob.hpp @@ -1,6 +1,7 @@ #ifndef _ESM_GLOB_H #define _ESM_GLOB_H +#include "record.hpp" #include "esm_reader.hpp" #include "esm_writer.hpp" #include "defs.hpp" @@ -12,13 +13,15 @@ namespace ESM * Global script variables */ -struct Global +struct Global : public Record { unsigned value; VarType type; void load(ESMReader &esm); void save(ESMWriter &esm); + + int getName() { return REC_GLOB; } }; } #endif diff --git a/components/esm/loadgmst.hpp b/components/esm/loadgmst.hpp index dc0400a4ed..0854ea2aa0 100644 --- a/components/esm/loadgmst.hpp +++ b/components/esm/loadgmst.hpp @@ -1,6 +1,7 @@ #ifndef _ESM_GMST_H #define _ESM_GMST_H +#include "record.hpp" #include "esm_reader.hpp" #include "esm_writer.hpp" #include "defs.hpp" @@ -13,7 +14,7 @@ namespace ESM * */ -struct GameSetting +struct GameSetting : public Record { std::string id; @@ -85,6 +86,8 @@ struct GameSetting void load(ESMReader &esm); void save(ESMWriter &esm); + + int getName() { return REC_GMST; } }; } #endif diff --git a/components/esm/loadinfo.hpp b/components/esm/loadinfo.hpp index 6f2d5ab25c..36c31a422f 100644 --- a/components/esm/loadinfo.hpp +++ b/components/esm/loadinfo.hpp @@ -1,6 +1,7 @@ #ifndef _ESM_INFO_H #define _ESM_INFO_H +#include "record.hpp" #include "esm_reader.hpp" #include "esm_writer.hpp" #include "defs.hpp" @@ -15,7 +16,7 @@ namespace ESM * and form a linked list of dialogue items. */ -struct DialInfo +struct DialInfo : public Record { enum Gender { @@ -100,6 +101,8 @@ struct DialInfo void load(ESMReader &esm); void save(ESMWriter &esm); + + int getName() { return REC_INFO; } }; /* diff --git a/components/esm/loadingr.hpp b/components/esm/loadingr.hpp index 040118bbfd..8536d5b02e 100644 --- a/components/esm/loadingr.hpp +++ b/components/esm/loadingr.hpp @@ -1,6 +1,7 @@ #ifndef _ESM_INGR_H #define _ESM_INGR_H +#include "record.hpp" #include "esm_reader.hpp" #include "esm_writer.hpp" @@ -11,7 +12,7 @@ namespace ESM * Alchemy ingredient */ -struct Ingredient +struct Ingredient : public Record { struct IRDTstruct { @@ -27,6 +28,8 @@ struct Ingredient void load(ESMReader &esm); void save(ESMWriter &esm); + + int getName() { return REC_INGR; } }; } #endif diff --git a/components/esm/loadland.hpp b/components/esm/loadland.hpp index ba506b63b9..6a14891f19 100644 --- a/components/esm/loadland.hpp +++ b/components/esm/loadland.hpp @@ -1,6 +1,7 @@ #ifndef _ESM_LAND_H #define _ESM_LAND_H +#include "record.hpp" #include "esm_reader.hpp" #include "esm_writer.hpp" @@ -10,7 +11,7 @@ namespace ESM * Landscape data. */ -struct Land +struct Land : public Record { Land(); ~Land(); @@ -75,6 +76,8 @@ struct Land void load(ESMReader &esm); void save(ESMWriter &esm); + int getName() { return REC_LAND; } + /** * Actually loads data */ diff --git a/components/esm/loadlevlist.hpp b/components/esm/loadlevlist.hpp index ff20ce9d16..c8591d7d2b 100644 --- a/components/esm/loadlevlist.hpp +++ b/components/esm/loadlevlist.hpp @@ -1,6 +1,7 @@ #ifndef _ESM_LEVLISTS_H #define _ESM_LEVLISTS_H +#include "record.hpp" #include "esm_reader.hpp" #include "esm_writer.hpp" @@ -15,7 +16,7 @@ namespace ESM * several files. */ -struct LeveledListBase +struct LeveledListBase : public Record { enum Flags { @@ -45,6 +46,14 @@ struct LeveledListBase void load(ESMReader &esm); void save(ESMWriter &esm); + + int getName() + { + if (recName[0] == 'C') + return REC_LEVC; + + return REC_LEVI; + } }; struct CreatureLevList: LeveledListBase diff --git a/components/esm/loadligh.hpp b/components/esm/loadligh.hpp index aecd8b99b6..75a78ae5fb 100644 --- a/components/esm/loadligh.hpp +++ b/components/esm/loadligh.hpp @@ -1,6 +1,7 @@ #ifndef _ESM_LIGH_H #define _ESM_LIGH_H +#include "record.hpp" #include "esm_reader.hpp" #include "esm_writer.hpp" @@ -12,7 +13,7 @@ namespace ESM * and torches. */ -struct Light +struct Light : public Record { enum Flags { @@ -43,6 +44,8 @@ struct Light void load(ESMReader &esm); void save(ESMWriter &esm); + + int getName() { return REC_LIGH; } }; } #endif diff --git a/components/esm/loadlocks.hpp b/components/esm/loadlocks.hpp index 1c2a709f14..c92a56ea78 100644 --- a/components/esm/loadlocks.hpp +++ b/components/esm/loadlocks.hpp @@ -1,6 +1,7 @@ #ifndef _ESM_LOCKS_H #define _ESM_LOCKS_H +#include "record.hpp" #include "esm_reader.hpp" #include "esm_writer.hpp" @@ -12,7 +13,7 @@ namespace ESM * items (REPA). These have nearly identical data structures. */ -struct Tool +struct Tool : public Record { enum Type { @@ -38,16 +39,26 @@ struct Tool void load(ESMReader &esm); void save(ESMWriter &esm); + + int getName() + { + if (type == Type_Probe) + return REC_PROB; + else if (type == Type_Repair) + return REC_REPA; + else + return REC_LOCK; + } }; struct Probe: Tool { - + Probe() { type = Type_Probe; } }; struct Repair: Tool { - + Repair() { type = Type_Repair; } }; } diff --git a/components/esm/loadltex.hpp b/components/esm/loadltex.hpp index d171c8e11b..994e12024d 100644 --- a/components/esm/loadltex.hpp +++ b/components/esm/loadltex.hpp @@ -1,6 +1,7 @@ #ifndef _ESM_LTEX_H #define _ESM_LTEX_H +#include "record.hpp" #include "esm_reader.hpp" #include "esm_writer.hpp" @@ -23,13 +24,15 @@ namespace ESM * texture, and see if it affects the game. */ -struct LandTexture +struct LandTexture : public Record { std::string id, texture; int index; void load(ESMReader &esm); void save(ESMWriter &esm); + + int getName() { return REC_LTEX; } }; } #endif diff --git a/components/esm/loadmgef.hpp b/components/esm/loadmgef.hpp index ed0b03d0bd..1c95be2bc6 100644 --- a/components/esm/loadmgef.hpp +++ b/components/esm/loadmgef.hpp @@ -1,13 +1,14 @@ #ifndef _ESM_MGEF_H #define _ESM_MGEF_H +#include "record.hpp" #include "esm_reader.hpp" #include "esm_writer.hpp" namespace ESM { -struct MagicEffect +struct MagicEffect : public Record { enum Flags { @@ -48,6 +49,8 @@ struct MagicEffect void load(ESMReader &esm); void save(ESMWriter &esm); + + int getName() { return REC_MGEF; } }; } #endif diff --git a/components/esm/loadmisc.hpp b/components/esm/loadmisc.hpp index 9aaa3c1be6..3d6cdb526f 100644 --- a/components/esm/loadmisc.hpp +++ b/components/esm/loadmisc.hpp @@ -1,6 +1,7 @@ #ifndef _ESM_MISC_H #define _ESM_MISC_H +#include "record.hpp" #include "esm_reader.hpp" #include "esm_writer.hpp" @@ -12,7 +13,7 @@ namespace ESM * carried, bought and sold. It also includes keys. */ -struct Miscellaneous +struct Miscellaneous : public Record { struct MCDTstruct { @@ -28,6 +29,8 @@ struct Miscellaneous void load(ESMReader &esm); void save(ESMWriter &esm); + + int getName() { return REC_MISC; } }; } #endif diff --git a/components/esm/loadnpc.cpp b/components/esm/loadnpc.cpp index 6cb6b64c78..34b5e69ed1 100644 --- a/components/esm/loadnpc.cpp +++ b/components/esm/loadnpc.cpp @@ -3,10 +3,13 @@ namespace ESM { -void NPC::load(ESMReader &esm, const std::string& id) +void NPC::setID(const std::string& id) { mId = id; +} +void NPC::load(ESMReader &esm) +{ npdt52.gold = -10; model = esm.getHNOString("MODL"); diff --git a/components/esm/loadnpc.hpp b/components/esm/loadnpc.hpp index 3e094a1971..3f8a60304c 100644 --- a/components/esm/loadnpc.hpp +++ b/components/esm/loadnpc.hpp @@ -1,6 +1,7 @@ #ifndef _ESM_NPC_H #define _ESM_NPC_H +#include "record.hpp" #include "esm_reader.hpp" #include "esm_writer.hpp" #include "loadcont.hpp" @@ -12,7 +13,7 @@ namespace ESM { * NPC definition */ -struct NPC +struct NPC : public Record { // Services enum Services @@ -102,8 +103,11 @@ struct NPC std::string mId; // Implementation moved to load_impl.cpp - void load(ESMReader &esm, const std::string& id); + void setID(const std::string& id); + void load(ESMReader &esm); void save(ESMWriter &esm); + + int getName() { return REC_NPC_; } }; } #endif diff --git a/components/esm/loadnpcc.hpp b/components/esm/loadnpcc.hpp index a65f6a6b34..46d1bf9d29 100644 --- a/components/esm/loadnpcc.hpp +++ b/components/esm/loadnpcc.hpp @@ -1,6 +1,7 @@ #ifndef _ESM_NPCC_H #define _ESM_NPCC_H +#include "record.hpp" #include "esm_reader.hpp" #include "esm_writer.hpp" @@ -71,7 +72,7 @@ namespace ESM { * will be harder than reading it. */ -struct LoadNPCC +struct LoadNPCC : public Record { void load(ESMReader &esm) { @@ -80,6 +81,8 @@ struct LoadNPCC void save(ESMWriter &esm) { } + + int getName() { return REC_NPCC; } }; } #endif diff --git a/components/esm/loadpgrd.hpp b/components/esm/loadpgrd.hpp index ec339240f8..db423204c8 100644 --- a/components/esm/loadpgrd.hpp +++ b/components/esm/loadpgrd.hpp @@ -1,6 +1,7 @@ #ifndef _ESM_PGRD_H #define _ESM_PGRD_H +#include "record.hpp" #include "esm_reader.hpp" #include "esm_writer.hpp" @@ -10,7 +11,7 @@ namespace ESM /* * Path grid. */ -struct Pathgrid +struct Pathgrid : public Record { struct DATAstruct { @@ -44,6 +45,8 @@ struct Pathgrid void load(ESMReader &esm); void save(ESMWriter &esm); + + int getName() { return REC_PGRD; } }; } #endif diff --git a/components/esm/loadrace.hpp b/components/esm/loadrace.hpp index 15fa439842..5c0593786b 100644 --- a/components/esm/loadrace.hpp +++ b/components/esm/loadrace.hpp @@ -1,6 +1,7 @@ #ifndef _ESM_RACE_H #define _ESM_RACE_H +#include "record.hpp" #include "esm_reader.hpp" #include "esm_writer.hpp" #include "defs.hpp" @@ -12,7 +13,7 @@ namespace ESM * Race definition */ -struct Race +struct Race : public Record { struct SkillBonus { @@ -60,6 +61,8 @@ struct Race void load(ESMReader &esm); void save(ESMWriter &esm); + + int getName() { return REC_RACE; } }; } #endif diff --git a/components/esm/loadregn.hpp b/components/esm/loadregn.hpp index 81b8bc51da..90444b5ad4 100644 --- a/components/esm/loadregn.hpp +++ b/components/esm/loadregn.hpp @@ -1,6 +1,7 @@ #ifndef _ESM_REGN_H #define _ESM_REGN_H +#include "record.hpp" #include "esm_reader.hpp" #include "esm_writer.hpp" @@ -11,7 +12,7 @@ namespace ESM * Region data */ -struct Region +struct Region : public Record { #pragma pack(push) #pragma pack(1) @@ -43,6 +44,8 @@ struct Region void load(ESMReader &esm); void save(ESMWriter &esm); + + int getName() { return REC_REGN; } }; } #endif diff --git a/components/esm/loadscpt.hpp b/components/esm/loadscpt.hpp index 55cfb053ad..bf6082704f 100644 --- a/components/esm/loadscpt.hpp +++ b/components/esm/loadscpt.hpp @@ -1,6 +1,7 @@ #ifndef _ESM_SCPT_H #define _ESM_SCPT_H +#include "record.hpp" #include "esm_reader.hpp" #include "esm_writer.hpp" @@ -11,7 +12,7 @@ namespace ESM * Script definitions */ -class Script +class Script : public Record { public: struct SCHDstruct @@ -52,6 +53,8 @@ public: void load(ESMReader &esm); void save(ESMWriter &esm); + + int getName() { return REC_SCPT; } }; } #endif diff --git a/components/esm/loadskil.hpp b/components/esm/loadskil.hpp index 8cc90b0634..68ada6020b 100644 --- a/components/esm/loadskil.hpp +++ b/components/esm/loadskil.hpp @@ -3,6 +3,7 @@ #include +#include "record.hpp" #include "esm_reader.hpp" #include "esm_writer.hpp" #include "defs.hpp" @@ -14,7 +15,7 @@ namespace ESM { * */ -struct Skill +struct Skill : public Record { struct SKDTstruct { @@ -69,6 +70,8 @@ struct Skill void load(ESMReader &esm); void save(ESMWriter &esm); + + int getName() { return REC_SKIL; } }; } #endif diff --git a/components/esm/loadsndg.hpp b/components/esm/loadsndg.hpp index e9e20c2126..33b89726fc 100644 --- a/components/esm/loadsndg.hpp +++ b/components/esm/loadsndg.hpp @@ -1,6 +1,7 @@ #ifndef _ESM_SNDG_H #define _ESM_SNDG_H +#include "record.hpp" #include "esm_reader.hpp" #include "esm_writer.hpp" @@ -11,7 +12,7 @@ namespace ESM * Sound generator. This describes the sounds a creature make. */ -struct SoundGenerator +struct SoundGenerator : public Record { enum Type { @@ -32,6 +33,8 @@ struct SoundGenerator void load(ESMReader &esm); void save(ESMWriter &esm); + + int getName() { return REC_SNDG; } }; } #endif diff --git a/components/esm/loadsoun.hpp b/components/esm/loadsoun.hpp index 9f0bdf5099..05663ba222 100644 --- a/components/esm/loadsoun.hpp +++ b/components/esm/loadsoun.hpp @@ -1,6 +1,7 @@ #ifndef _ESM_SOUN_H #define _ESM_SOUN_H +#include "record.hpp" #include "esm_reader.hpp" #include "esm_writer.hpp" @@ -12,13 +13,15 @@ struct SOUNstruct unsigned char volume, minRange, maxRange; }; -struct Sound +struct Sound : public Record { SOUNstruct data; std::string sound; void load(ESMReader &esm); void save(ESMWriter &esm); + + int getName() { return REC_SOUN; } }; } #endif diff --git a/components/esm/loadspel.hpp b/components/esm/loadspel.hpp index 971bf23a4d..674f7e35d2 100644 --- a/components/esm/loadspel.hpp +++ b/components/esm/loadspel.hpp @@ -1,6 +1,7 @@ #ifndef _ESM_SPEL_H #define _ESM_SPEL_H +#include "record.hpp" #include "esm_reader.hpp" #include "esm_writer.hpp" #include "defs.hpp" @@ -8,7 +9,7 @@ namespace ESM { -struct Spell +struct Spell : public Record { enum SpellType { @@ -40,6 +41,8 @@ struct Spell void load(ESMReader &esm); void save(ESMWriter &esm); + + int getName() { return REC_SPEL; } }; } #endif diff --git a/components/esm/loadsscr.hpp b/components/esm/loadsscr.hpp index 2cc7eccf9f..2249b08ee5 100644 --- a/components/esm/loadsscr.hpp +++ b/components/esm/loadsscr.hpp @@ -1,6 +1,7 @@ #ifndef _ESM_SSCR_H #define _ESM_SSCR_H +#include "record.hpp" #include "esm_reader.hpp" #include "esm_writer.hpp" @@ -15,13 +16,15 @@ namespace ESM reference. */ -struct StartScript +struct StartScript : public Record { std::string script; // Load a record and add it to the list void load(ESMReader &esm); void save(ESMWriter &esm); + + int getName() { return REC_SSCR; } }; } diff --git a/components/esm/loadstat.hpp b/components/esm/loadstat.hpp index a5b82c46dc..3ebbd4813d 100644 --- a/components/esm/loadstat.hpp +++ b/components/esm/loadstat.hpp @@ -1,6 +1,7 @@ #ifndef _ESM_STAT_H #define _ESM_STAT_H +#include "record.hpp" #include "esm_reader.hpp" #include "esm_writer.hpp" @@ -18,12 +19,14 @@ namespace ESM { * you decode the CELL blocks, if you want to test this hypothesis. */ -struct Static +struct Static : public Record { std::string model; void load(ESMReader &esm); void save(ESMWriter &esm); + + int getName() { return REC_STAT; } }; } #endif diff --git a/components/esm/loadweap.hpp b/components/esm/loadweap.hpp index 8e7947bf33..4d464a7ee0 100644 --- a/components/esm/loadweap.hpp +++ b/components/esm/loadweap.hpp @@ -1,6 +1,7 @@ #ifndef _ESM_WEAP_H #define _ESM_WEAP_H +#include "record.hpp" #include "esm_reader.hpp" #include "esm_writer.hpp" @@ -11,7 +12,7 @@ namespace ESM * Weapon definition */ -struct Weapon +struct Weapon : public Record { enum Type { @@ -58,6 +59,8 @@ struct Weapon void load(ESMReader &esm); void save(ESMWriter &esm); + + int getName() { return REC_WEAP; } }; } #endif diff --git a/components/esm/record.hpp b/components/esm/record.hpp new file mode 100644 index 0000000000..666a6c15b9 --- /dev/null +++ b/components/esm/record.hpp @@ -0,0 +1,70 @@ +#ifndef _ESM_RECORD_H +#define _ESM_RECORD_H + +namespace ESM +{ + +enum RecNameInts +{ + REC_ACTI = 0x49544341, + REC_ALCH = 0x48434c41, + REC_APPA = 0x41505041, + REC_ARMO = 0x4f4d5241, + REC_BODY = 0x59444f42, + REC_BOOK = 0x4b4f4f42, + REC_BSGN = 0x4e475342, + REC_CELL = 0x4c4c4543, + REC_CLAS = 0x53414c43, + REC_CLOT = 0x544f4c43, + REC_CNTC = 0x43544e43, + REC_CONT = 0x544e4f43, + REC_CREA = 0x41455243, + REC_CREC = 0x43455243, + REC_DIAL = 0x4c414944, + REC_DOOR = 0x524f4f44, + REC_ENCH = 0x48434e45, + REC_FACT = 0x54434146, + REC_GLOB = 0x424f4c47, + REC_GMST = 0x54534d47, + REC_INFO = 0x4f464e49, + REC_INGR = 0x52474e49, + REC_LAND = 0x444e414c, + REC_LEVC = 0x4356454c, + REC_LEVI = 0x4956454c, + REC_LIGH = 0x4847494c, + REC_LOCK = 0x4b434f4c, + REC_LTEX = 0x5845544c, + REC_MGEF = 0x4645474d, + REC_MISC = 0x4353494d, + REC_NPC_ = 0x5f43504e, + REC_NPCC = 0x4343504e, + REC_PGRD = 0x44524750, + REC_PROB = 0x424f5250, + REC_RACE = 0x45434152, + REC_REGN = 0x4e474552, + REC_REPA = 0x41504552, + REC_SCPT = 0x54504353, + REC_SKIL = 0x4c494b53, + REC_SNDG = 0x47444e53, + REC_SOUN = 0x4e554f53, + REC_SPEL = 0x4c455053, + REC_SSCR = 0x52435353, + REC_STAT = 0x54415453, + REC_WEAP = 0x50414557 +}; + +class ESMReader; +class ESMWriter; + +class Record +{ +public: + virtual void load(ESMReader& esm) = 0; + virtual void save(ESMWriter& esm) = 0; + + virtual int getName() = 0; +}; + +} + +#endif diff --git a/components/esm/records.hpp b/components/esm/records.hpp index 704a11609a..e05f74f5df 100644 --- a/components/esm/records.hpp +++ b/components/esm/records.hpp @@ -1,6 +1,7 @@ #ifndef _ESM_RECORDS_H #define _ESM_RECORDS_H +#include "record.hpp" #include "loadacti.hpp" #include "loadalch.hpp" #include "loadappa.hpp" @@ -45,57 +46,4 @@ // Special records which are not loaded from ESM #include "attr.hpp" - -namespace ESM { - -// Integer versions of all the record names, used for faster lookup -enum RecNameInts - { - REC_ACTI = 0x49544341, - REC_ALCH = 0x48434c41, - REC_APPA = 0x41505041, - REC_ARMO = 0x4f4d5241, - REC_BODY = 0x59444f42, - REC_BOOK = 0x4b4f4f42, - REC_BSGN = 0x4e475342, - REC_CELL = 0x4c4c4543, - REC_CLAS = 0x53414c43, - REC_CLOT = 0x544f4c43, - REC_CNTC = 0x43544e43, - REC_CONT = 0x544e4f43, - REC_CREA = 0x41455243, - REC_CREC = 0x43455243, - REC_DIAL = 0x4c414944, - REC_DOOR = 0x524f4f44, - REC_ENCH = 0x48434e45, - REC_FACT = 0x54434146, - REC_GLOB = 0x424f4c47, - REC_GMST = 0x54534d47, - REC_INFO = 0x4f464e49, - REC_INGR = 0x52474e49, - REC_LAND = 0x444e414c, - REC_LEVC = 0x4356454c, - REC_LEVI = 0x4956454c, - REC_LIGH = 0x4847494c, - REC_LOCK = 0x4b434f4c, - REC_LTEX = 0x5845544c, - REC_MGEF = 0x4645474d, - REC_MISC = 0x4353494d, - REC_NPC_ = 0x5f43504e, - REC_NPCC = 0x4343504e, - REC_PGRD = 0x44524750, - REC_PROB = 0x424f5250, - REC_RACE = 0x45434152, - REC_REGN = 0x4e474552, - REC_REPA = 0x41504552, - REC_SCPT = 0x54504353, - REC_SKIL = 0x4c494b53, - REC_SNDG = 0x47444e53, - REC_SOUN = 0x4e554f53, - REC_SPEL = 0x4c455053, - REC_SSCR = 0x52435353, - REC_STAT = 0x54415453, - REC_WEAP = 0x50414557 - }; -} #endif diff --git a/components/esm_store/reclists.hpp b/components/esm_store/reclists.hpp index d7a4100aae..bc3b676a21 100644 --- a/components/esm_store/reclists.hpp +++ b/components/esm_store/reclists.hpp @@ -104,7 +104,8 @@ namespace ESMS void load(ESMReader &esm, const std::string &id) { std::string id2 = toLower (id); - list[id2].load(esm, id2); + list[id2].setID(id2); + list[id2].load(esm); } // Find the given object ID, or return NULL if not found. From fc8c75ab892aa51478c3bc7fce728707c3e0cb12 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Sun, 8 Apr 2012 17:04:52 +0200 Subject: [PATCH 06/14] Esmtool can now clone an esm file in such a way that it can read it back again afterwards. --- apps/esmtool/esmtool.cpp | 102 +++++++++++++++++++++++++++------ components/esm/esm_reader.hpp | 1 + components/esm/esm_writer.cpp | 99 +++++++++++++++++++++++++------- components/esm/esm_writer.hpp | 36 +++++++----- components/esm/loadarmo.cpp | 2 +- components/esm/loadfact.cpp | 2 +- components/esm/loadland.cpp | 5 +- components/esm/loadlevlist.cpp | 2 +- components/esm/loadlocks.cpp | 11 ++-- components/esm/loadpgrd.cpp | 6 +- components/esm/loadregn.cpp | 5 +- components/esm/loadscpt.cpp | 8 ++- components/esm/record.hpp | 8 +++ 13 files changed, 220 insertions(+), 67 deletions(-) diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp index ea9a388a52..97f1aa2a5b 100644 --- a/apps/esmtool/esmtool.cpp +++ b/apps/esmtool/esmtool.cpp @@ -22,6 +22,8 @@ struct ESMData { std::string author; std::string description; + int version; + int type; ESMReader::MasterList masters; std::list records; @@ -221,7 +223,7 @@ int load(Arguments& info) try { - if(info.raw_given) + if(info.raw_given && info.mode == "dump") { cout << "RAW file listing:\n"; @@ -233,7 +235,7 @@ int load(Arguments& info) } 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"); esm.open(filename); @@ -241,15 +243,23 @@ int load(Arguments& info) info.data.author = esm.getAuthor(); info.data.description = esm.getDesc(); info.data.masters = esm.getMasters(); + info.data.version = esm.getVer(); + info.data.type = esm.getType(); - cout << "Author: " << esm.getAuthor() << endl; - cout << "Description: " << esm.getDesc() << endl; - cout << "File format version: " << esm.getFVer() << endl; - cout << "Special flag: " << esm.getSpecial() << endl; - cout << "Masters:\n"; - ESMReader::MasterList m = esm.getMasters(); - for(unsigned int i=0;isetId(id); + if (save) info.data.records.push_back(rec); else @@ -720,6 +733,7 @@ int load(Arguments& info) } #include +#include int clone(Arguments& info) { @@ -735,26 +749,82 @@ int clone(Arguments& info) return 1; } - cout << "Loaded " << info.data.records.size() << " records:" << endl; + int recordCount = info.data.records.size(); + + int digitCount = 1; // For a nicer output + if (recordCount > 9) ++digitCount; + if (recordCount > 99) ++digitCount; + if (recordCount > 999) ++digitCount; + if (recordCount > 9999) ++digitCount; + if (recordCount > 99999) ++digitCount; + if (recordCount > 999999) ++digitCount; + + cout << "Loaded " << recordCount << " records:" << endl << endl; std::map records; - for (std::list::iterator it = info.data.records.begin(); it != info.data.records.end();) + for (std::list::iterator it = info.data.records.begin(); it != info.data.records.end(); ++it) { Record* rec = *it; NAME n; n.val = rec->getName(); records[n.toString()]++; - - delete rec; - info.data.records.erase(it++); } + int i = 0; for (std::map::iterator it = records.begin(); it != records.end(); ++it) { std::string n = it->first; - cout << n << ": " << it->second << " records." << endl; + float amount = it->second; + cout << setw(digitCount) << amount << " " << n << " "; + + if (++i % 3 == 0) + cout << endl; } + + if (i % 3 != 0) + cout << endl; + + cout << endl << "Saving records to: " << info.outname << "..." << endl; + + ESMWriter esm; + esm.setAuthor(info.data.author); + esm.setDescription(info.data.description); + esm.setVersion(info.data.version); + esm.setType(info.data.type); + + for (ESMReader::MasterList::iterator it = info.data.masters.begin(); it != info.data.masters.end(); ++it) + esm.addMaster(it->name, it->size); + + std::fstream save(info.outname.c_str(), std::fstream::out | std::fstream::binary); + esm.save(save); + + int saved = 0; + for (std::list::iterator it = info.data.records.begin(); it != info.data.records.end() && i > 0; ++it) + { + Record* rec = *it; + + NAME n; + n.val = rec->getName(); + + esm.startRecord(n.toString(), 0); + std::string id = rec->getId(); + esm.writeHNOString("NAME", id); + rec->save(esm); + esm.endRecord(n.toString()); + + saved++; + int perc = ((int)saved / (float)recordCount)*100; + if (perc % 10 == 0) + { + cerr << "\r" << perc << "%"; + } + } + + cout << "\rDone!" << endl; + + esm.close(); + save.close(); return 0; } diff --git a/components/esm/esm_reader.hpp b/components/esm/esm_reader.hpp index 6e5592cf7b..3e69aa5281 100644 --- a/components/esm/esm_reader.hpp +++ b/components/esm/esm_reader.hpp @@ -61,6 +61,7 @@ public: int getVer() { return mCtx.header.version; } float getFVer() { if(mCtx.header.version == VER_12) return 1.2; else return 1.3; } int getSpecial() { return mSpf; } + int getType() { return mCtx.header.type; } const std::string getAuthor() { return mCtx.header.author.toString(); } const std::string getDesc() { return mCtx.header.desc.toString(); } const SaveData &getSaveData() { return mSaveData; } diff --git a/components/esm/esm_writer.cpp b/components/esm/esm_writer.cpp index 57517b0f53..14e28f6ba9 100644 --- a/components/esm/esm_writer.cpp +++ b/components/esm/esm_writer.cpp @@ -2,15 +2,27 @@ #include #include +bool count = true; + namespace ESM { -void ESMWriter::setVersion(Version ver) +int ESMWriter::getVersion() +{ + return m_header.version; +} + +void ESMWriter::setVersion(int ver) { m_header.version = ver; } -void ESMWriter::setType(FileType type) +int ESMWriter::getType() +{ + return m_header.type; +} + +void ESMWriter::setType(int type) { m_header.type = type; } @@ -25,75 +37,118 @@ void ESMWriter::setDescription(const std::string& desc) strncpy((char*)&m_header.desc, desc.c_str(), 256); } +void ESMWriter::addMaster(const std::string& name, uint64_t size) +{ + MasterData d; + d.name = name; + d.size = size; + m_masters.push_back(d); +} + void ESMWriter::save(const std::string& file) { std::ofstream fs(file.c_str(), std::ios_base::out | std::ios_base::trunc); save(fs); - fs.close(); } void ESMWriter::save(std::ostream& file) { m_stream = &file; - startRecord("TES3"); - writeT(0); - writeT(0); + startRecord("TES3", 0); - endRecord(); + m_header.records = 0; + writeHNT("HEDR", m_header, 300); - // TODO: Saving + for (std::list::iterator it = m_masters.begin(); it != m_masters.end(); ++it) + { + writeHNString("MAST", it->name); + writeHNT("DATA", it->size); + } + + endRecord("TES3"); } void ESMWriter::close() { - // TODO: Saving + m_stream->flush(); + + if (!m_records.empty()) + throw "Unclosed record remaining"; } -void ESMWriter::startRecord(const std::string& name) +void ESMWriter::startRecord(const std::string& name, uint32_t flags) { writeName(name); RecordData rec; + rec.name = name; rec.position = m_stream->tellp(); rec.size = 0; + writeT(0); // Size goes here + writeT(0); // Unused header? + writeT(flags); m_records.push_back(rec); - writeT(0); + + assert(m_records.back().size == 0); } -void ESMWriter::endRecord() +void ESMWriter::startSubRecord(const std::string& name) +{ + writeName(name); + RecordData rec; + rec.name = name; + rec.position = m_stream->tellp(); + rec.size = 0; + writeT(0); // Size goes here + m_records.push_back(rec); + + assert(m_records.back().size == 0); +} + +void ESMWriter::endRecord(const std::string& name) { - std::streampos cur = m_stream->tellp(); RecordData rec = m_records.back(); + assert(rec.name == name); m_records.pop_back(); m_stream->seekp(rec.position); - m_stream->write((char*)&rec.size, sizeof(int)); - m_stream->seekp(cur); + count = false; + write((char*)&rec.size, sizeof(int)); + count = true; + + m_stream->seekp(0, std::ios::end); + } void ESMWriter::writeHNString(const std::string& name, const std::string& data) { - writeName(name); + startSubRecord(name); writeHString(data); + endRecord(name); } void ESMWriter::writeHString(const std::string& data) { - writeT(data.size()-1); - write(data.c_str(), data.size()-1); + if (data.size() == 0) + write("\0", 1); + else + write(data.c_str(), data.size()); } void ESMWriter::writeName(const std::string& name) { - assert((name.size() == 4 && name[3] != '\0') || (name.size() == 5 && name[4] == '\0')); - write(name.c_str(), name.size()-1); + assert((name.size() == 4 && name[3] != '\0')); + write(name.c_str(), name.size()); } void ESMWriter::write(const char* data, int size) { - if (!m_records.empty()) - m_records.back().size += size; + if (count && !m_records.empty()) + { + for (std::list::iterator it = m_records.begin(); it != m_records.end(); ++it) + it->size += size; + } m_stream->write(data, size); } diff --git a/components/esm/esm_writer.hpp b/components/esm/esm_writer.hpp index 3999e987d2..4439693c4d 100644 --- a/components/esm/esm_writer.hpp +++ b/components/esm/esm_writer.hpp @@ -2,7 +2,7 @@ #define _ESM_WRITER_H #include -#include +#include #include #include "esm_common.hpp" @@ -13,17 +13,22 @@ class ESMWriter { struct RecordData { + std::string name; std::streampos position; int size; }; public: - void setVersion(Version ver); - void setType(FileType type); - + int getVersion(); + void setVersion(int ver); + int getType(); + void setType(int type); +// void setEncoding(const std::string& encoding); // Write strings as UTF-8? void setAuthor(const std::string& author); void setDescription(const std::string& desc); + void addMaster(const std::string& name, uint64_t size); + void save(const std::string& file); void save(std::ostream& file); void close(); @@ -38,18 +43,20 @@ public: template void writeHNT(const std::string& name, const T& data) { - writeName(name); + startSubRecord(name); writeT(data); + endRecord(name); } template void writeHNT(const std::string& name, const T& data, int size) { - assert(sizeof(T) == size); - writeHNT(name, data); + startSubRecord(name); + writeT(data, size); + endRecord(name); } - template + /*template void writeHT(const T& data) { writeT((unsigned int)sizeof(T)); @@ -61,7 +68,7 @@ public: { assert(sizeof(T) == size); writeHT(data); - } + }*/ template void writeT(const T& data) @@ -72,18 +79,19 @@ public: template void writeT(const T& data, int size) { - assert(sizeof(T) == size); - writeT(data); + write((char*)&data, size); } - void startRecord(const std::string& name); - void endRecord(); + void startRecord(const std::string& name, uint32_t flags); + void startSubRecord(const std::string& name); + void endRecord(const std::string& name); void writeHString(const std::string& data); void writeName(const std::string& data); void write(const char* data, int size); private: - std::vector m_records; + std::list m_masters; + std::list m_records; std::ostream* m_stream; HEDRstruct m_header; diff --git a/components/esm/loadarmo.cpp b/components/esm/loadarmo.cpp index aecfc7e922..ca5865083f 100644 --- a/components/esm/loadarmo.cpp +++ b/components/esm/loadarmo.cpp @@ -19,7 +19,7 @@ void PartReferenceList::save(ESMWriter &esm) { for (std::vector::iterator it = parts.begin(); it != parts.end(); ++it) { - esm.writeHT(it->part); + esm.writeHNT("INDX", it->part); esm.writeHNOString("BNAM", it->male); esm.writeHNOString("CNAM", it->female); } diff --git a/components/esm/loadfact.cpp b/components/esm/loadfact.cpp index fdbedcbd01..2a927ad28c 100644 --- a/components/esm/loadfact.cpp +++ b/components/esm/loadfact.cpp @@ -31,7 +31,7 @@ void Faction::save(ESMWriter &esm) { esm.writeHNString("FNAM", name); - for (int i = 0; !ranks[i].empty(); i++) + for (int i = 0; i < 10; i++) { esm.writeHNString("RNAM", ranks[i]); } diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp index 9aa02e4781..222772041a 100644 --- a/components/esm/loadland.cpp +++ b/components/esm/loadland.cpp @@ -84,15 +84,18 @@ void Land::load(ESMReader &esm) void Land::save(ESMWriter &esm) { - esm.writeName("INTV"); + esm.startSubRecord("INTV"); esm.writeT(X); esm.writeT(Y); + esm.endRecord("INTV"); esm.writeHNT("DATA", flags); + /* TODO: Land! if (hasData && !dataLoaded) loadData(); // I think it might be a good idea to have // the data loaded before trying to save it + */ if (dataLoaded) landData->save(esm); } diff --git a/components/esm/loadlevlist.cpp b/components/esm/loadlevlist.cpp index 811964775b..f63a720256 100644 --- a/components/esm/loadlevlist.cpp +++ b/components/esm/loadlevlist.cpp @@ -38,7 +38,7 @@ void LeveledListBase::save(ESMWriter &esm) for (std::vector::iterator it = list.begin(); it != list.end(); ++it) { - esm.writeHNString("INAM", it->id); + esm.writeHNString(recName, it->id); esm.writeHNT("INTV", it->level); } } diff --git a/components/esm/loadlocks.cpp b/components/esm/loadlocks.cpp index f49de1bc8f..b3d53f4588 100644 --- a/components/esm/loadlocks.cpp +++ b/components/esm/loadlocks.cpp @@ -36,14 +36,15 @@ void Tool::save(ESMWriter &esm) esm.writeHNString("MODL", model); esm.writeHNString("FNAM", name); + std::string typeName; switch(type) { - case Type_Repair: esm.writeName("RIDT"); break; - case Type_Pick: esm.writeName("LKDT"); break; - case Type_Probe: esm.writeName("PBDT"); break; + case Type_Repair: typeName = "RIDT"; break; + case Type_Pick: typeName = "LKDT"; break; + case Type_Probe: typeName = "PBDT"; break; } - - esm.writeT(data, 16); + + esm.writeHNT(typeName, data, 16); esm.writeHNOString("SCRI", script); esm.writeHNOString("ITEX", icon); } diff --git a/components/esm/loadpgrd.cpp b/components/esm/loadpgrd.cpp index 41dd341748..ebdb6e8371 100644 --- a/components/esm/loadpgrd.cpp +++ b/components/esm/loadpgrd.cpp @@ -74,20 +74,22 @@ void Pathgrid::save(ESMWriter &esm) if (!points.empty()) { - esm.writeName("PGRP"); + esm.startSubRecord("PGRP"); for (PointList::iterator it = points.begin(); it != points.end(); ++it) { esm.writeT(*it); } + esm.endRecord("PGRP"); } if (!edges.empty()) { - esm.writeName("PGRC"); + esm.startSubRecord("PGRC"); for (std::vector::iterator it = edges.begin(); it != edges.end(); ++it) { esm.writeT(it->v1); } + esm.endRecord("PGRC"); } } diff --git a/components/esm/loadregn.cpp b/components/esm/loadregn.cpp index d67922b4d9..f9e4a151e7 100644 --- a/components/esm/loadregn.cpp +++ b/components/esm/loadregn.cpp @@ -29,7 +29,10 @@ void Region::save(ESMWriter &esm) { esm.writeHNString("FNAM", name); - esm.writeHNT("WEAT", data); + if (esm.getVersion() == VER_12) + esm.writeHNT("WEAT", data, sizeof(data) - 2); + else + esm.writeHNT("WEAT", data); esm.writeHNOString("BNAM", sleepList); diff --git a/components/esm/loadscpt.cpp b/components/esm/loadscpt.cpp index 291259bc08..ecb58cc31e 100644 --- a/components/esm/loadscpt.cpp +++ b/components/esm/loadscpt.cpp @@ -44,15 +44,17 @@ void Script::save(ESMWriter &esm) if (!varNames.empty()) { - esm.writeName("SCVR"); + esm.startSubRecord("SCVR"); for (std::vector::iterator it = varNames.begin(); it != varNames.end(); ++it) { esm.writeT(it->c_str(), it->size()); + esm.writeT('\0'); } + esm.endRecord("SCVR"); } - esm.writeHNT("SCDT", &scriptData[0], scriptData.size()); - esm.writeHNOString("SCDT", scriptText); + esm.writeHNString("SCDT", std::string(&scriptData[0], scriptData.size())); + esm.writeHNOString("SCTX", scriptText); } } diff --git a/components/esm/record.hpp b/components/esm/record.hpp index 666a6c15b9..d273b175ab 100644 --- a/components/esm/record.hpp +++ b/components/esm/record.hpp @@ -1,6 +1,8 @@ #ifndef _ESM_RECORD_H #define _ESM_RECORD_H +#include + namespace ESM { @@ -62,7 +64,13 @@ public: virtual void load(ESMReader& esm) = 0; virtual void save(ESMWriter& esm) = 0; + std::string getId() { return m_id; } + void setId(const std::string& in) { m_id = in; } + virtual int getName() = 0; + +protected: + std::string m_id; }; } From 23f81e63ddc64cc84424c7f0122ce3d5373edef5 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Sun, 8 Apr 2012 17:14:56 +0200 Subject: [PATCH 07/14] Nicer help text and error for not selecting a valid mode. --- apps/esmtool/esmtool.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp index 97f1aa2a5b..a8eeaee7fd 100644 --- a/apps/esmtool/esmtool.cpp +++ b/apps/esmtool/esmtool.cpp @@ -46,7 +46,7 @@ struct Arguments 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 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\nAllowed options"); desc.add_options() ("help,h", "print help message.") @@ -103,6 +103,14 @@ bool parseOptions (int argc, char** argv, Arguments &info) return false; } + info.mode = variables["mode"].as(); + if (!(info.mode == "dump" || info.mode == "clone")) + { + std::cout << std::endl << "ERROR: invalid mode \"" << info.mode << "\"" << std::endl << std::endl + << desc << finalText << std::endl; + return false; + } + if ( !variables.count("input-file") ) { std::cout << "\nERROR: missing ES file\n\n"; @@ -118,8 +126,6 @@ bool parseOptions (int argc, char** argv, Arguments &info) return false; }*/ - info.mode = variables["mode"].as(); - info.filename = variables["input-file"].as< vector >()[0]; if (variables["input-file"].as< vector >().size() > 1) info.outname = variables["input-file"].as< vector >()[1]; @@ -814,7 +820,7 @@ int clone(Arguments& info) esm.endRecord(n.toString()); saved++; - int perc = ((int)saved / (float)recordCount)*100; + int perc = (saved / (float)recordCount)*100; if (perc % 10 == 0) { cerr << "\r" << perc << "%"; From 1d48781567f756608f82192020176d16ab9d0ffd Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Sun, 8 Apr 2012 17:52:55 +0200 Subject: [PATCH 08/14] Forgot about the cell refs, oops --- apps/esmtool/esmtool.cpp | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp index a8eeaee7fd..dd9ed648c8 100644 --- a/apps/esmtool/esmtool.cpp +++ b/apps/esmtool/esmtool.cpp @@ -1,5 +1,6 @@ #include #include +#include #include @@ -15,9 +16,6 @@ using namespace ESM; // Create a local alias for brevity namespace bpo = boost::program_options; -void printRaw(ESMReader &esm); -void loadCell(Cell &cell, ESMReader &esm, bool quiet); - struct ESMData { std::string author; @@ -27,6 +25,7 @@ struct ESMData ESMReader::MasterList masters; std::list records; + std::map > cellRefs; }; // Based on the legacy struct @@ -157,6 +156,9 @@ bool parseOptions (int argc, char** argv, Arguments &info) return true; } +void printRaw(ESMReader &esm); +void loadCell(Cell &cell, ESMReader &esm, Arguments& info); + int load(Arguments& info); int clone(Arguments& info); @@ -179,8 +181,11 @@ int main(int argc, char**argv) return 0; } -void loadCell(Cell &cell, ESMReader &esm, bool quiet) +void loadCell(Cell &cell, ESMReader &esm, Arguments& info) { + bool quiet = (info.quiet_given || info.mode == "clone"); + bool save = (info.mode == "clone"); + // Skip back to the beginning of the reference list cell.restore(esm); @@ -189,6 +194,9 @@ void loadCell(Cell &cell, ESMReader &esm, bool quiet) if(!quiet) cout << " References:\n"; while(cell.getNextRef(esm, ref)) { + if (save) + info.data.cellRefs[&cell].push_back(ref); + if(quiet) continue; cout << " Refnum: " << ref.refnum << endl; @@ -241,7 +249,7 @@ int load(Arguments& info) } 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"); esm.open(filename); @@ -367,7 +375,7 @@ int load(Arguments& info) cout << " Region: " << b.region << endl; } if(loadCells) - loadCell(b, esm, quiet); + loadCell(b, esm, info); break; } case REC_CLAS: @@ -738,7 +746,6 @@ int load(Arguments& info) return 0; } -#include #include int clone(Arguments& info) @@ -817,6 +824,16 @@ int clone(Arguments& info) std::string id = rec->getId(); esm.writeHNOString("NAME", id); rec->save(esm); + + if (n.val == REC_CELL && !info.data.cellRefs[rec].empty()) + { + std::list& refs = info.data.cellRefs[rec]; + for (std::list::iterator it = refs.begin(); it != refs.end(); ++it) + { + it->save(esm); + } + } + esm.endRecord(n.toString()); saved++; From f0c32ba7d3baf5f4a3c4adb6bc791dc074c384f5 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Sun, 8 Apr 2012 18:01:54 +0200 Subject: [PATCH 09/14] Fixed saving cell ref data with wrong name --- components/esm/loadcell.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index f6db5c70cc..920fa8ad90 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -16,7 +16,7 @@ void CellRef::save(ESMWriter &esm) esm.writeHNOString("ANAM", owner); esm.writeHNOString("BNAM", glob); - esm.writeHNOString("SXOL", soul); + esm.writeHNOString("XSOL", soul); esm.writeHNOString("CNAM", faction); if (factIndex != -1) From 290d09de64768fbc052bc15d92191d620e852d0a Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Sun, 8 Apr 2012 18:32:40 +0200 Subject: [PATCH 10/14] Switching creature and npc to using the same id storage as the rest of the records --- apps/esmtool/esmtool.cpp | 1 - apps/openmw/mwclass/creature.cpp | 2 +- apps/openmw/mwclass/npc.cpp | 2 +- components/esm/loadcrea.cpp | 5 ----- components/esm/loadcrea.hpp | 3 --- components/esm/loadnpc.cpp | 5 ----- components/esm/loadnpc.hpp | 3 +-- components/esm/record.hpp | 2 +- components/esm_store/reclists.hpp | 2 +- 9 files changed, 5 insertions(+), 20 deletions(-) diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp index dd9ed648c8..06348e949c 100644 --- a/apps/esmtool/esmtool.cpp +++ b/apps/esmtool/esmtool.cpp @@ -410,7 +410,6 @@ int load(Arguments& info) { rec = new Creature(); Creature& b = *(Creature*)rec; - b.setID(id); b.load(esm); if(quiet) break; cout << " Name: " << b.name << endl; diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 7270fd22b9..8a5b149ff1 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -65,7 +65,7 @@ namespace MWClass ESMS::LiveCellRef *ref = ptr.get(); - return ref->base->mId; + return ref->base->getId(); } void Creature::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 83a94d27d1..04ac31f984 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -88,7 +88,7 @@ namespace MWClass ESMS::LiveCellRef *ref = ptr.get(); - return ref->base->mId; + return ref->base->getId(); } void Npc::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const diff --git a/components/esm/loadcrea.cpp b/components/esm/loadcrea.cpp index 7b84a7f296..259d37b4a1 100644 --- a/components/esm/loadcrea.cpp +++ b/components/esm/loadcrea.cpp @@ -2,11 +2,6 @@ namespace ESM { -void Creature::setID(const std::string& id) -{ - mId = id; -} - void Creature::load(ESMReader &esm) { model = esm.getHNString("MODL"); diff --git a/components/esm/loadcrea.hpp b/components/esm/loadcrea.hpp index 3035003cf8..348c14b234 100644 --- a/components/esm/loadcrea.hpp +++ b/components/esm/loadcrea.hpp @@ -63,9 +63,6 @@ struct Creature : public Record // Defined in loadcont.hpp InventoryList inventory; - std::string mId; - - void setID(const std::string& id); void load(ESMReader &esm); void save(ESMWriter &esm); diff --git a/components/esm/loadnpc.cpp b/components/esm/loadnpc.cpp index 34b5e69ed1..b689ba5e84 100644 --- a/components/esm/loadnpc.cpp +++ b/components/esm/loadnpc.cpp @@ -3,11 +3,6 @@ namespace ESM { -void NPC::setID(const std::string& id) -{ - mId = id; -} - void NPC::load(ESMReader &esm) { npdt52.gold = -10; diff --git a/components/esm/loadnpc.hpp b/components/esm/loadnpc.hpp index 3f8a60304c..13ee9ef6d7 100644 --- a/components/esm/loadnpc.hpp +++ b/components/esm/loadnpc.hpp @@ -100,10 +100,9 @@ struct NPC : public Record std::string name, model, race, cls, faction, script, hair, head; // body parts - std::string mId; + //std::string mId; // Implementation moved to load_impl.cpp - void setID(const std::string& id); void load(ESMReader &esm); void save(ESMWriter &esm); diff --git a/components/esm/record.hpp b/components/esm/record.hpp index d273b175ab..dfecab7b93 100644 --- a/components/esm/record.hpp +++ b/components/esm/record.hpp @@ -64,7 +64,7 @@ public: virtual void load(ESMReader& esm) = 0; virtual void save(ESMWriter& esm) = 0; - std::string getId() { return m_id; } + std::string getId() const { return m_id; } void setId(const std::string& in) { m_id = in; } virtual int getName() = 0; diff --git a/components/esm_store/reclists.hpp b/components/esm_store/reclists.hpp index bc3b676a21..22bb55b52c 100644 --- a/components/esm_store/reclists.hpp +++ b/components/esm_store/reclists.hpp @@ -104,7 +104,7 @@ namespace ESMS void load(ESMReader &esm, const std::string &id) { std::string id2 = toLower (id); - list[id2].setID(id2); + list[id2].setId(id2); list[id2].load(esm); } From f16a9ce5ed26bfad1cfe55e480abeb56bd970113 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Thu, 12 Apr 2012 14:00:58 +0200 Subject: [PATCH 11/14] Working on making output identical to input. --- apps/esmtool/esmtool.cpp | 146 +++++++++++++++++++++++----------- components/esm/esm_writer.cpp | 23 ++++++ components/esm/esm_writer.hpp | 25 +++--- components/esm/loadclas.cpp | 2 +- components/esm/loadfact.cpp | 7 +- components/esm/loadrace.cpp | 2 +- components/esm/loadscpt.cpp | 15 ++-- 7 files changed, 150 insertions(+), 70 deletions(-) diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp index 06348e949c..002758bed0 100644 --- a/apps/esmtool/esmtool.cpp +++ b/apps/esmtool/esmtool.cpp @@ -19,13 +19,13 @@ namespace bpo = boost::program_options; struct ESMData { std::string author; - std::string description; + string description; int version; int type; ESMReader::MasterList masters; - std::list records; - std::map > cellRefs; + list records; + map > cellRefs; }; // Based on the legacy struct @@ -35,17 +35,17 @@ struct Arguments unsigned int quiet_given; unsigned int loadcells_given; - std::string mode; - std::string encoding; - std::string filename; - std::string outname; + string mode; + string encoding; + string filename; + string outname; ESMData data; }; 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\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"); desc.add_options() ("help,h", "print help message.") @@ -54,7 +54,7 @@ bool parseOptions (int argc, char** argv, Arguments &info) ("quiet,q", "Supress all record information. Useful for speed tests.") ("loadcells,C", "Browse through contents of all cells.") - ( "encoding,e", bpo::value(&(info.encoding))-> + ( "encoding,e", bpo::value(&(info.encoding))-> default_value("win1252"), "Character encoding used in ESMTool:\n" "\n\twin1250 - Central and Eastern European such as Polish, Czech, Slovak, Hungarian, Slovene, Bosnian, Croatian, Serbian (Latin script), Romanian and Albanian languages\n" @@ -62,14 +62,14 @@ bool parseOptions (int argc, char** argv, Arguments &info) "\n\twin1252 - Western European (Latin) alphabet, used by default") ; - std::string finalText = "\nIf no option is given, the default action is to parse all records in the archive\nand display diagnostic information."; + string finalText = "\nIf no option is given, the default action is to parse all records in the archive\nand display diagnostic information."; // input-file is hidden and used as a positional argument bpo::options_description hidden("Hidden Options"); hidden.add_options() - ( "mode,m", bpo::value(), "esmtool mode") - ( "input-file,i", bpo::value< vector >(), "input file") + ( "mode,m", bpo::value(), "esmtool mode") + ( "input-file,i", bpo::value< vector >(), "input file") ; bpo::positional_options_description p; @@ -87,70 +87,70 @@ bool parseOptions (int argc, char** argv, Arguments &info) if (variables.count ("help")) { - std::cout << desc << finalText << std::endl; + cout << desc << finalText << endl; return false; } if (variables.count ("version")) { - std::cout << "ESMTool version " << ESMTOOL_VERSION << std::endl; + cout << "ESMTool version " << ESMTOOL_VERSION << endl; return false; } if (!variables.count("mode")) { - std::cout << "No mode specified!" << std::endl << std::endl - << desc << finalText << std::endl; + cout << "No mode specified!" << endl << endl + << desc << finalText << endl; return false; } - info.mode = variables["mode"].as(); - if (!(info.mode == "dump" || info.mode == "clone")) + info.mode = variables["mode"].as(); + if (!(info.mode == "dump" || info.mode == "clone" || info.mode == "comp")) { - std::cout << std::endl << "ERROR: invalid mode \"" << info.mode << "\"" << std::endl << std::endl - << desc << finalText << std::endl; + cout << endl << "ERROR: invalid mode \"" << info.mode << "\"" << endl << endl + << desc << finalText << endl; return false; } if ( !variables.count("input-file") ) { - std::cout << "\nERROR: missing ES file\n\n"; - std::cout << desc << finalText << std::endl; + cout << "\nERROR: missing ES file\n\n"; + cout << desc << finalText << endl; return false; } // handling gracefully the user adding multiple files -/* if (variables["input-file"].as< vector >().size() > 1) +/* if (variables["input-file"].as< vector >().size() > 1) { - std::cout << "\nERROR: more than one ES file specified\n\n"; - std::cout << desc << finalText << std::endl; + cout << "\nERROR: more than one ES file specified\n\n"; + cout << desc << finalText << endl; return false; }*/ - info.filename = variables["input-file"].as< vector >()[0]; - if (variables["input-file"].as< vector >().size() > 1) - info.outname = variables["input-file"].as< vector >()[1]; + info.filename = variables["input-file"].as< vector >()[0]; + if (variables["input-file"].as< vector >().size() > 1) + info.outname = variables["input-file"].as< vector >()[1]; info.raw_given = variables.count ("raw"); info.quiet_given = variables.count ("quiet"); info.loadcells_given = variables.count ("loadcells"); // Font encoding settings - info.encoding = variables["encoding"].as(); + info.encoding = variables["encoding"].as(); if (info.encoding == "win1250") { - std::cout << "Using Central and Eastern European font encoding." << std::endl; + cout << "Using Central and Eastern European font encoding." << endl; } else if (info.encoding == "win1251") { - std::cout << "Using Cyrillic font encoding." << std::endl; + cout << "Using Cyrillic font encoding." << endl; } else { if(info.encoding != "win1252") { - std::cout << info.encoding << " is not a valid encoding option." << std::endl; + cout << info.encoding << " is not a valid encoding option." << endl; info.encoding = "win1252"; } - std::cout << "Using default (English) font encoding." << std::endl; + cout << "Using default (English) font encoding." << endl; } return true; @@ -161,6 +161,7 @@ void loadCell(Cell &cell, ESMReader &esm, Arguments& info); int load(Arguments& info); int clone(Arguments& info); +int comp(Arguments& info); int main(int argc, char**argv) { @@ -172,6 +173,8 @@ int main(int argc, char**argv) return load(info); else if (info.mode == "clone") return clone(info); + else if (info.mode == "comp") + return comp(info); else { cout << "Invalid or no mode specified, dying horribly. Have a nice day." << endl; @@ -231,9 +234,9 @@ int load(Arguments& info) esm.setEncoding(info.encoding); string filename = info.filename; - cout << "\nFile: " << filename << endl; + cout << "Loading file: " << filename << endl; - std::list skipped; + list skipped; try { @@ -734,7 +737,7 @@ int load(Arguments& info) { cout << "\nERROR:\n\n " << e.what() << endl; - for (std::list::iterator it = info.data.records.begin(); it != info.data.records.end();) + for (list::iterator it = info.data.records.begin(); it != info.data.records.end();) { delete *it; info.data.records.erase(it++); @@ -773,9 +776,9 @@ int clone(Arguments& info) cout << "Loaded " << recordCount << " records:" << endl << endl; - std::map records; + map records; - for (std::list::iterator it = info.data.records.begin(); it != info.data.records.end(); ++it) + for (list::iterator it = info.data.records.begin(); it != info.data.records.end(); ++it) { Record* rec = *it; NAME n; @@ -784,9 +787,9 @@ int clone(Arguments& info) } int i = 0; - for (std::map::iterator it = records.begin(); it != records.end(); ++it) + for (map::iterator it = records.begin(); it != records.end(); ++it) { - std::string n = it->first; + string n = it->first; float amount = it->second; cout << setw(digitCount) << amount << " " << n << " "; @@ -808,11 +811,11 @@ int clone(Arguments& info) for (ESMReader::MasterList::iterator it = info.data.masters.begin(); it != info.data.masters.end(); ++it) esm.addMaster(it->name, it->size); - std::fstream save(info.outname.c_str(), std::fstream::out | std::fstream::binary); + fstream save(info.outname.c_str(), fstream::out | fstream::binary); esm.save(save); int saved = 0; - for (std::list::iterator it = info.data.records.begin(); it != info.data.records.end() && i > 0; ++it) + for (list::iterator it = info.data.records.begin(); it != info.data.records.end() && i > 0; ++it) { Record* rec = *it; @@ -820,14 +823,18 @@ int clone(Arguments& info) n.val = rec->getName(); esm.startRecord(n.toString(), 0); - std::string id = rec->getId(); - esm.writeHNOString("NAME", id); + string id = rec->getId(); + + if (n.val == REC_GLOB || n.val == REC_CLAS || n.val == REC_FACT || n.val == REC_RACE) + esm.writeHNCString("NAME", id); + else + esm.writeHNOString("NAME", id); rec->save(esm); if (n.val == REC_CELL && !info.data.cellRefs[rec].empty()) { - std::list& refs = info.data.cellRefs[rec]; - for (std::list::iterator it = refs.begin(); it != refs.end(); ++it) + list& refs = info.data.cellRefs[rec]; + for (list::iterator it = refs.begin(); it != refs.end(); ++it) { it->save(esm); } @@ -848,5 +855,52 @@ int clone(Arguments& info) esm.close(); save.close(); + return 0; +} + +int comp(Arguments& info) +{ + if (info.filename.empty() || info.outname.empty()) + { + cout << "You need to specify two input files" << endl; + return 1; + } + + Arguments fileOne; + Arguments fileTwo; + + fileOne.raw_given = 0; + fileTwo.raw_given = 0; + + fileOne.mode = "clone"; + fileTwo.mode = "clone"; + + fileOne.encoding = info.encoding; + fileTwo.encoding = info.encoding; + + fileOne.filename = info.filename; + fileTwo.filename = info.outname; + + if (load(fileOne) != 0) + { + cout << "Failed to load " << info.filename << ", aborting comparison." << endl; + return 1; + } + + if (load(fileTwo) != 0) + { + cout << "Failed to load " << info.outname << ", aborting comparison." << endl; + return 1; + } + + if (fileOne.data.records.size() != fileTwo.data.records.size()) + { + cout << "Not equal, different amount of records." << endl; + return 1; + } + + + + return 0; } diff --git a/components/esm/esm_writer.cpp b/components/esm/esm_writer.cpp index 14e28f6ba9..4e0a6f4604 100644 --- a/components/esm/esm_writer.cpp +++ b/components/esm/esm_writer.cpp @@ -53,12 +53,14 @@ void ESMWriter::save(const std::string& file) void ESMWriter::save(std::ostream& file) { + m_recordCount = 0; m_stream = &file; startRecord("TES3", 0); m_header.records = 0; writeHNT("HEDR", m_header, 300); + m_headerPos = m_stream->tellp() - (std::streampos)4; for (std::list::iterator it = m_masters.begin(); it != m_masters.end(); ++it) { @@ -71,6 +73,10 @@ void ESMWriter::save(std::ostream& file) void ESMWriter::close() { + std::cout << "Writing amount of saved records (" << m_recordCount - 1 << ")" << std::endl; + m_stream->seekp(m_headerPos); + writeT(m_recordCount-1); + m_stream->seekp(0, std::ios::end); m_stream->flush(); if (!m_records.empty()) @@ -79,6 +85,8 @@ void ESMWriter::close() void ESMWriter::startRecord(const std::string& name, uint32_t flags) { + m_recordCount++; + writeName(name); RecordData rec; rec.name = name; @@ -128,6 +136,21 @@ void ESMWriter::writeHNString(const std::string& name, const std::string& data) endRecord(name); } + void ESMWriter::writeHNString(const std::string& name, const std::string& data, int size) +{ + assert(data.size() <= size); + startSubRecord(name); + writeHString(data); + + if (data.size() < size) + { + for (int i = data.size(); i < size; ++i) + write("\0",1); + } + + endRecord(name); +} + void ESMWriter::writeHString(const std::string& data) { if (data.size() == 0) diff --git a/components/esm/esm_writer.hpp b/components/esm/esm_writer.hpp index 4439693c4d..337af9e5ed 100644 --- a/components/esm/esm_writer.hpp +++ b/components/esm/esm_writer.hpp @@ -34,6 +34,15 @@ public: void close(); void writeHNString(const std::string& name, const std::string& data); + void writeHNString(const std::string& name, const std::string& data, int size); + void writeHNCString(const std::string& name, const std::string& data) + { + startSubRecord(name); + writeHString(data); + if (data.size() > 0 && data[data.size()-1] != '\0') + write("\0", 1); + endRecord(name); + } void writeHNOString(const std::string& name, const std::string& data) { if (!data.empty()) @@ -56,20 +65,6 @@ public: endRecord(name); } - /*template - void writeHT(const T& data) - { - writeT((unsigned int)sizeof(T)); - writeT(data); - } - - template - void writeHT(const T& data, int size) - { - assert(sizeof(T) == size); - writeHT(data); - }*/ - template void writeT(const T& data) { @@ -93,6 +88,8 @@ private: std::list m_masters; std::list m_records; std::ostream* m_stream; + std::streampos m_headerPos; + int m_recordCount; HEDRstruct m_header; SaveData m_saveData; diff --git a/components/esm/loadclas.cpp b/components/esm/loadclas.cpp index e13442dcf4..6e6de4e71b 100644 --- a/components/esm/loadclas.cpp +++ b/components/esm/loadclas.cpp @@ -27,7 +27,7 @@ void Class::load(ESMReader &esm) } void Class::save(ESMWriter &esm) { - esm.writeHNString("FNAM", name); + esm.writeHNCString("FNAM", name); esm.writeHNT("CLDT", data, 60); esm.writeHNOString("DESC", description); } diff --git a/components/esm/loadfact.cpp b/components/esm/loadfact.cpp index 2a927ad28c..1a151cbe1c 100644 --- a/components/esm/loadfact.cpp +++ b/components/esm/loadfact.cpp @@ -29,11 +29,14 @@ void Faction::load(ESMReader &esm) } void Faction::save(ESMWriter &esm) { - esm.writeHNString("FNAM", name); + esm.writeHNCString("FNAM", name); for (int i = 0; i < 10; i++) { - esm.writeHNString("RNAM", ranks[i]); + if (ranks[i].empty()) + break; + + esm.writeHNString("RNAM", ranks[i], 32); } esm.writeHNT("FADT", data, 240); diff --git a/components/esm/loadrace.cpp b/components/esm/loadrace.cpp index 04752add1e..8c82bd38a4 100644 --- a/components/esm/loadrace.cpp +++ b/components/esm/loadrace.cpp @@ -12,7 +12,7 @@ void Race::load(ESMReader &esm) } void Race::save(ESMWriter &esm) { - esm.writeHNString("FNAM", name); + esm.writeHNCString("FNAM", name); esm.writeHNT("RADT", data, 140); powers.save(esm); esm.writeHNOString("DESC", description); diff --git a/components/esm/loadscpt.cpp b/components/esm/loadscpt.cpp index ecb58cc31e..658f97a49b 100644 --- a/components/esm/loadscpt.cpp +++ b/components/esm/loadscpt.cpp @@ -40,19 +40,22 @@ void Script::load(ESMReader &esm) } void Script::save(ESMWriter &esm) { - esm.writeHNT("SCHD", data, 52); - + std::string varNameString; if (!varNames.empty()) { - esm.startSubRecord("SCVR"); for (std::vector::iterator it = varNames.begin(); it != varNames.end(); ++it) { - esm.writeT(it->c_str(), it->size()); - esm.writeT('\0'); + varNameString.append(*it); + //varNameString.append("\0"); } - esm.endRecord("SCVR"); + + data.stringTableSize = varNameString.size(); } + esm.writeHNT("SCHD", data, 52); + + esm.writeHNOString("SCVR", varNameString); + esm.writeHNString("SCDT", std::string(&scriptData[0], scriptData.size())); esm.writeHNOString("SCTX", scriptText); } From a74aeace73ddd41ca80a2506f2944f46beefba2c Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Sat, 14 Apr 2012 00:14:04 +0200 Subject: [PATCH 12/14] Can now save strings with proper encoding, byte-perfect clones up until land records --- apps/esmtool/esmtool.cpp | 20 ++- components/esm/defs.hpp | 216 ++++++++++++++++++++++++++++++++- components/esm/esm_writer.cpp | 37 +++++- components/esm/esm_writer.hpp | 14 ++- components/esm/loadacti.cpp | 6 +- components/esm/loadalch.cpp | 8 +- components/esm/loadappa.cpp | 8 +- components/esm/loadarmo.cpp | 10 +- components/esm/loadbody.cpp | 4 +- components/esm/loadbook.cpp | 10 +- components/esm/loadbsgn.cpp | 6 +- components/esm/loadcell.cpp | 2 +- components/esm/loadclot.cpp | 10 +- components/esm/loadcont.cpp | 6 +- components/esm/loadcrea.cpp | 13 +- components/esm/loadcrea.hpp | 3 + components/esm/loaddoor.cpp | 10 +- components/esm/loadingr.cpp | 8 +- components/esm/loadlevlist.cpp | 2 +- components/esm/loadligh.cpp | 10 +- components/esm/loadlocks.cpp | 16 ++- components/esm/loadltex.cpp | 2 +- components/esm/loadmgef.cpp | 20 +-- components/esm/loadmisc.cpp | 8 +- components/esm/loadnpc.cpp | 29 ++--- components/esm/loadnpc.hpp | 15 +-- components/esm/loadregn.cpp | 4 +- components/esm/loadscpt.cpp | 22 ++-- components/esm/loadsoun.cpp | 2 +- components/esm/loadspel.cpp | 2 +- components/esm/loadstat.cpp | 2 +- components/esm/loadweap.cpp | 10 +- components/esm/record.hpp | 4 + components/to_utf8/to_utf8.cpp | 164 +++++++++++++++++++++++++ components/to_utf8/to_utf8.hpp | 1 + 35 files changed, 570 insertions(+), 134 deletions(-) diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp index 002758bed0..2eab0bc1a8 100644 --- a/apps/esmtool/esmtool.cpp +++ b/apps/esmtool/esmtool.cpp @@ -282,7 +282,9 @@ int load(Arguments& info) while(esm.hasMoreRecs()) { NAME n = esm.getRecName(); - esm.getRecHeader(); + uint32_t flags; + esm.getRecHeader(flags); + string id = esm.getHNOString("NAME"); if(!quiet) cout << "\nRecord: " << n.toString() @@ -726,6 +728,8 @@ int load(Arguments& info) { rec->setId(id); + rec->setFlags((int)flags); + if (save) info.data.records.push_back(rec); else @@ -803,6 +807,7 @@ int clone(Arguments& info) cout << endl << "Saving records to: " << info.outname << "..." << endl; ESMWriter esm; + esm.setEncoding(info.encoding); esm.setAuthor(info.data.author); esm.setDescription(info.data.description); esm.setVersion(info.data.version); @@ -822,13 +827,22 @@ int clone(Arguments& info) NAME n; n.val = rec->getName(); - esm.startRecord(n.toString(), 0); + esm.startRecord(n.toString(), rec->getFlags()); string id = rec->getId(); - if (n.val == REC_GLOB || n.val == REC_CLAS || n.val == REC_FACT || n.val == REC_RACE) + if (n.val == REC_GLOB || n.val == REC_CLAS || n.val == REC_FACT || n.val == REC_RACE || n.val == REC_SOUN + || n.val == REC_REGN || n.val == REC_BSGN || n.val == REC_LTEX || n.val == REC_STAT || n.val == REC_DOOR + || n.val == REC_MISC || n.val == REC_WEAP || n.val == REC_CONT || n.val == REC_SPEL || n.val == REC_CREA + || n.val == REC_BODY || n.val == REC_LIGH || n.val == REC_ENCH || n.val == REC_NPC_ || n.val == REC_ARMO + || n.val == REC_CLOT || n.val == REC_REPA || n.val == REC_ACTI || n.val == REC_APPA || n.val == REC_LOCK + || n.val == REC_PROB || n.val == REC_INGR || n.val == REC_BOOK || n.val == REC_ALCH || n.val == REC_LEVI + || n.val == REC_LEVC) esm.writeHNCString("NAME", id); + else if (n.val == REC_CELL) + esm.writeHNString("NAME", id); else esm.writeHNOString("NAME", id); + rec->save(esm); if (n.val == REC_CELL && !info.data.cellRefs[rec].empty()) diff --git a/components/esm/defs.hpp b/components/esm/defs.hpp index a332479069..caf81aad14 100644 --- a/components/esm/defs.hpp +++ b/components/esm/defs.hpp @@ -51,7 +51,7 @@ struct SpellList void save(ESMWriter &esm) { for (std::vector::iterator it = list.begin(); it != list.end(); ++it) - esm.writeHNString("NPCS", *it); + esm.writeHNString("NPCS", *it, 32); } }; @@ -83,6 +83,139 @@ struct ENAMstruct // Struct size should be 24 bytes }; + +struct AIDTstruct +{ + // These are probabilities + char hello, u1, fight, flee, alarm, u2, u3, u4; + // The last u's might be the skills that this NPC can train you + // in? + int services; // See the Services enum +}; // 12 bytes + +struct DODTstruct +{ + float pos[3]; + float rot[3]; +}; + +struct AI_Package +{ + void load(ESMReader& esm) + { + getData(esm); + cndt = esm.getHNOString("CNDT"); + } + + void save(ESMWriter& esm) + { + esm.startSubRecord(getName()); + saveData(esm); + esm.endRecord(getName()); + + esm.writeHNOCString("CNDT", cndt); + } + + std::string cndt; + + virtual void getData(ESMReader&) = 0; + virtual void saveData(ESMWriter&) = 0; + + virtual std::string getName() const = 0; + virtual int size() const = 0; +}; + +struct AI_Wstruct : AI_Package +{ + struct Data + { + short distance, duration; + char timeofday; + char idle[8]; + char unknown; + }; + + Data data; + + void getData(ESMReader& esm) { esm.getHExact(&data, sizeof(data)); } + void saveData(ESMWriter& esm) { esm.writeT(data); } + + std::string getName() const { return "AI_W"; } + int size() const { return sizeof(AI_Wstruct); } +}; + +struct AI_Tstruct : AI_Package +{ + struct Data + { + float pos[3]; + int unknown; + }; + + Data data; + + void getData(ESMReader& esm) { esm.getHExact(&data, sizeof(data)); } + void saveData(ESMWriter& esm) { esm.writeT(data); } + + std::string getName() const { return "AI_T"; } + int size() const { return sizeof(AI_Tstruct); } +}; + +struct AI_Fstruct : AI_Package +{ + struct Data + { + float pos[3]; + short duration; + NAME32 id; + short unknown; + }; + + Data data; + + void getData(ESMReader& esm) { esm.getHExact(&data, sizeof(data)); } + void saveData(ESMWriter& esm) { esm.writeT(data); } + + std::string getName() const { return "AI_F"; } + int size() const { return sizeof(AI_Fstruct); } +}; + +struct AI_Estruct : AI_Package +{ + struct Data + { + float pos[3]; + short duration; + NAME32 id; + short unknown; + }; + + Data data; + + void getData(ESMReader& esm) { esm.getHExact(&data, sizeof(data)); } + void saveData(ESMWriter& esm) { esm.writeT(data); } + + std::string getName() const { return "AI_E"; } + int size() const { return sizeof(AI_Estruct); } +}; + +struct AI_Astruct : AI_Package +{ + struct Data + { + NAME32 name; + char unknown; + }; + + Data data; + + void getData(ESMReader& esm) { esm.getHExact(&data, sizeof(data)); } + void saveData(ESMWriter& esm) { esm.writeT(data); } + + std::string getName() const { return "AI_A"; } + int size() const { return sizeof(AI_Astruct); } +}; + #pragma pack(pop) struct EffectList @@ -107,5 +240,86 @@ struct EffectList } }; +struct AIData +{ + struct Travelstruct + { + DODTstruct dodt; + std::string dnam; + }; + + AIDTstruct aidt; + bool hasAI; + std::vector packages; + std::vector travel; + + void load(ESMReader &esm) + { + if (esm.isNextSub("AIDT")) + { + esm.getHExact(&aidt, sizeof(aidt)); + hasAI = true; + } + else + hasAI = false; + +#define LOAD_IF_FOUND(x) \ + if (esm.isNextSub(#x)) \ + { \ + found = true; \ + x##struct *t = new x##struct(); \ + t->load(esm); \ + packages.push_back(t); \ + } + + bool found = true; + while (esm.hasMoreSubs() && found) + { + found = false; + + if (esm.isNextSub("DODT")) + { + found = true; + Travelstruct t; + esm.getHExact(&t.dodt, sizeof(t.dodt)); + t.dnam = esm.getHNOString("DNAM"); + travel.push_back(t); + } + + LOAD_IF_FOUND(AI_W); + LOAD_IF_FOUND(AI_T); + LOAD_IF_FOUND(AI_F); + LOAD_IF_FOUND(AI_E); + LOAD_IF_FOUND(AI_A); + } + } + + void save(ESMWriter &esm) + { + if (hasAI) + esm.writeHNT("AIDT", aidt); + + for (std::vector::iterator it = travel.begin(); it != travel.end(); ++it) + { + esm.writeHNT("DODT", it->dodt); + esm.writeHNOCString("DNAM", it->dnam); + } + + for (std::vector::iterator it = packages.begin(); it != packages.end(); ++it) + { + (*it)->save(esm); + } + } + + ~AIData() + { + for (std::vector::iterator it = packages.begin(); it != packages.end();) + { + delete *it; + packages.erase(it++); + } + } +}; + } #endif diff --git a/components/esm/esm_writer.cpp b/components/esm/esm_writer.cpp index 4e0a6f4604..ef8a9c1b86 100644 --- a/components/esm/esm_writer.cpp +++ b/components/esm/esm_writer.cpp @@ -136,7 +136,7 @@ void ESMWriter::writeHNString(const std::string& name, const std::string& data) endRecord(name); } - void ESMWriter::writeHNString(const std::string& name, const std::string& data, int size) +void ESMWriter::writeHNString(const std::string& name, const std::string& data, int size) { assert(data.size() <= size); startSubRecord(name); @@ -156,7 +156,23 @@ void ESMWriter::writeHString(const std::string& data) if (data.size() == 0) write("\0", 1); else - write(data.c_str(), data.size()); + { + char *ptr = ToUTF8::getBuffer(data.size()+1); + strncpy(ptr, &data[0], data.size()); + ptr[data.size()] = '\0'; + + // Convert to UTF8 and return + std::string ascii = ToUTF8::getASCII(m_encoding); + + write(ascii.c_str(), ascii.size()); + } +} + +void ESMWriter::writeHCString(const std::string& data) +{ + writeHString(data); + if (data.size() > 0 && data[data.size()-1] != '\0') + write("\0", 1); } void ESMWriter::writeName(const std::string& name) @@ -176,4 +192,21 @@ void ESMWriter::write(const char* data, int size) m_stream->write(data, size); } +void ESMWriter::setEncoding(const std::string& encoding) +{ + if (encoding == "win1250") + { + m_encoding = ToUTF8::WINDOWS_1250; + } + else if (encoding == "win1251") + { + m_encoding = ToUTF8::WINDOWS_1251; + } + else + { + // Default Latin encoding + m_encoding = ToUTF8::WINDOWS_1252; + } +} + } diff --git a/components/esm/esm_writer.hpp b/components/esm/esm_writer.hpp index 337af9e5ed..6eb34a97c9 100644 --- a/components/esm/esm_writer.hpp +++ b/components/esm/esm_writer.hpp @@ -6,6 +6,7 @@ #include #include "esm_common.hpp" +#include "../to_utf8/to_utf8.hpp" namespace ESM { @@ -23,7 +24,7 @@ public: void setVersion(int ver); int getType(); void setType(int type); -// void setEncoding(const std::string& encoding); // Write strings as UTF-8? + void setEncoding(const std::string& encoding); // Write strings as UTF-8? void setAuthor(const std::string& author); void setDescription(const std::string& desc); @@ -38,9 +39,7 @@ public: void writeHNCString(const std::string& name, const std::string& data) { startSubRecord(name); - writeHString(data); - if (data.size() > 0 && data[data.size()-1] != '\0') - write("\0", 1); + writeHCString(data); endRecord(name); } void writeHNOString(const std::string& name, const std::string& data) @@ -48,6 +47,11 @@ public: if (!data.empty()) writeHNString(name, data); } + void writeHNOCString(const std::string& name, const std::string& data) + { + if (!data.empty()) + writeHNCString(name, data); + } template void writeHNT(const std::string& name, const T& data) @@ -81,6 +85,7 @@ public: void startSubRecord(const std::string& name); void endRecord(const std::string& name); void writeHString(const std::string& data); + void writeHCString(const std::string& data); void writeName(const std::string& data); void write(const char* data, int size); @@ -89,6 +94,7 @@ private: std::list m_records; std::ostream* m_stream; std::streampos m_headerPos; + ToUTF8::FromType m_encoding; int m_recordCount; HEDRstruct m_header; diff --git a/components/esm/loadacti.cpp b/components/esm/loadacti.cpp index b62a461586..9b08ad2667 100644 --- a/components/esm/loadacti.cpp +++ b/components/esm/loadacti.cpp @@ -10,8 +10,8 @@ void Activator::load(ESMReader &esm) } void Activator::save(ESMWriter &esm) { - esm.writeHNString("MODL", model); - esm.writeHNString("FNAM", name); - esm.writeHNOString("SCRI", script); + esm.writeHNCString("MODL", model); + esm.writeHNCString("FNAM", name); + esm.writeHNOCString("SCRI", script); } } diff --git a/components/esm/loadalch.cpp b/components/esm/loadalch.cpp index e5d3d8e271..969fb0aae1 100644 --- a/components/esm/loadalch.cpp +++ b/components/esm/loadalch.cpp @@ -13,10 +13,10 @@ void Potion::load(ESMReader &esm) } void Potion::save(ESMWriter &esm) { - esm.writeHNString("MODL", model); - esm.writeHNOString("TEXT", icon); - esm.writeHNOString("SCRI", script); - esm.writeHNOString("FNAM", name); + esm.writeHNCString("MODL", model); + esm.writeHNOCString("TEXT", icon); + esm.writeHNOCString("SCRI", script); + esm.writeHNOCString("FNAM", name); esm.writeHNT("ALDT", data, 12); effects.save(esm); } diff --git a/components/esm/loadappa.cpp b/components/esm/loadappa.cpp index 6eb164ec25..55dc8dc888 100644 --- a/components/esm/loadappa.cpp +++ b/components/esm/loadappa.cpp @@ -12,10 +12,10 @@ void Apparatus::load(ESMReader &esm) } void Apparatus::save(ESMWriter &esm) { - esm.writeHNString("MODL", model); - esm.writeHNString("FNAM", name); + esm.writeHNCString("MODL", model); + esm.writeHNCString("FNAM", name); esm.writeHNT("AADT", data, 16); - esm.writeHNOString("SCRI", script); - esm.writeHNString("ITEX", icon); + esm.writeHNOCString("SCRI", script); + esm.writeHNCString("ITEX", icon); } } diff --git a/components/esm/loadarmo.cpp b/components/esm/loadarmo.cpp index ca5865083f..c79e1fed23 100644 --- a/components/esm/loadarmo.cpp +++ b/components/esm/loadarmo.cpp @@ -38,13 +38,13 @@ void Armor::load(ESMReader &esm) void Armor::save(ESMWriter &esm) { - esm.writeHNString("MODL", model); - esm.writeHNString("FNAM", name); - esm.writeHNOString("SCRI", script); + esm.writeHNCString("MODL", model); + esm.writeHNCString("FNAM", name); + esm.writeHNOCString("SCRI", script); esm.writeHNT("AODT", data, 24); - esm.writeHNOString("ITEX", icon); + esm.writeHNOCString("ITEX", icon); parts.save(esm); - esm.writeHNOString("ENAM", enchant); + esm.writeHNOCString("ENAM", enchant); } } diff --git a/components/esm/loadbody.cpp b/components/esm/loadbody.cpp index 72d56eac35..376320fb55 100644 --- a/components/esm/loadbody.cpp +++ b/components/esm/loadbody.cpp @@ -11,8 +11,8 @@ void BodyPart::load(ESMReader &esm) } void BodyPart::save(ESMWriter &esm) { - esm.writeHNString("MODL", model); - esm.writeHNString("FNAM", name); + esm.writeHNCString("MODL", model); + esm.writeHNCString("FNAM", name); esm.writeHNT("BYDT", data, 4); } diff --git a/components/esm/loadbook.cpp b/components/esm/loadbook.cpp index ed21d71e14..9dba838083 100644 --- a/components/esm/loadbook.cpp +++ b/components/esm/loadbook.cpp @@ -15,13 +15,13 @@ void Book::load(ESMReader &esm) } void Book::save(ESMWriter &esm) { - esm.writeHNString("MODL", model); - esm.writeHNOString("FNAM", name); + esm.writeHNCString("MODL", model); + esm.writeHNOCString("FNAM", name); esm.writeHNT("BKDT", data, 20); - esm.writeHNOString("SCRI", script); - esm.writeHNOString("ITEX", icon); + esm.writeHNOCString("SCRI", script); + esm.writeHNOCString("ITEX", icon); esm.writeHNOString("TEXT", text); - esm.writeHNOString("ENAM", enchant); + esm.writeHNOCString("ENAM", enchant); } } diff --git a/components/esm/loadbsgn.cpp b/components/esm/loadbsgn.cpp index de76e1949a..3b7bae9f7e 100644 --- a/components/esm/loadbsgn.cpp +++ b/components/esm/loadbsgn.cpp @@ -13,9 +13,9 @@ void BirthSign::load(ESMReader &esm) } void BirthSign::save(ESMWriter &esm) { - esm.writeHNString("FNAM", name); - esm.writeHNOString("TNAM", texture); - esm.writeHNOString("DESC", description); + esm.writeHNCString("FNAM", name); + esm.writeHNOCString("TNAM", texture); + esm.writeHNOCString("DESC", description); powers.save(esm); } diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index 920fa8ad90..57d951658f 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -108,7 +108,7 @@ void Cell::save(ESMWriter &esm) } else { - esm.writeHNOString("RGNN", region); + esm.writeHNOCString("RGNN", region); if (mapColor != 0) esm.writeHNT("NAM5", mapColor); } diff --git a/components/esm/loadclot.cpp b/components/esm/loadclot.cpp index cd884d2065..37a445c19d 100644 --- a/components/esm/loadclot.cpp +++ b/components/esm/loadclot.cpp @@ -18,16 +18,16 @@ void Clothing::load(ESMReader &esm) } void Clothing::save(ESMWriter &esm) { - esm.writeHNString("MODL", model); - esm.writeHNOString("FNAM", name); + esm.writeHNCString("MODL", model); + esm.writeHNOCString("FNAM", name); esm.writeHNT("CTDT", data, 12); - esm.writeHNOString("SCRI", script); - esm.writeHNOString("ITEX", icon); + esm.writeHNOCString("SCRI", script); + esm.writeHNOCString("ITEX", icon); parts.save(esm); - esm.writeHNOString("ENAM", enchant); + esm.writeHNOCString("ENAM", enchant); } } diff --git a/components/esm/loadcont.cpp b/components/esm/loadcont.cpp index 176c4ec050..125ec72d4a 100644 --- a/components/esm/loadcont.cpp +++ b/components/esm/loadcont.cpp @@ -40,12 +40,12 @@ void Container::load(ESMReader &esm) void Container::save(ESMWriter &esm) { - esm.writeHNString("MODL", model); - esm.writeHNOString("FNAM", name); + esm.writeHNCString("MODL", model); + esm.writeHNOCString("FNAM", name); esm.writeHNT("CNDT", weight, 4); esm.writeHNT("FLAG", flags, 4); - esm.writeHNOString("SCRI", script); + esm.writeHNOCString("SCRI", script); inventory.save(esm); } diff --git a/components/esm/loadcrea.cpp b/components/esm/loadcrea.cpp index 259d37b4a1..c4f9dca487 100644 --- a/components/esm/loadcrea.cpp +++ b/components/esm/loadcrea.cpp @@ -16,6 +16,8 @@ void Creature::load(ESMReader &esm) esm.getHNOT(scale, "XSCL"); inventory.load(esm); + spells.load(esm); + aiData.load(esm); // More subrecords: @@ -37,15 +39,18 @@ void Creature::load(ESMReader &esm) void Creature::save(ESMWriter &esm) { - esm.writeHNString("MODL", model); - esm.writeHNOString("CNAM", original); - esm.writeHNOString("FNAM", name); - esm.writeHNOString("SCRI", script); + esm.writeHNCString("MODL", model); + esm.writeHNOCString("CNAM", original); + esm.writeHNOCString("FNAM", name); + esm.writeHNOCString("SCRI", script); esm.writeHNT("NPDT", data, 96); esm.writeHNT("FLAG", flags); if (scale != 1.0) esm.writeHNT("XSCL", scale); + inventory.save(esm); + spells.save(esm); + aiData.save(esm); } } diff --git a/components/esm/loadcrea.hpp b/components/esm/loadcrea.hpp index 348c14b234..355065aeb7 100644 --- a/components/esm/loadcrea.hpp +++ b/components/esm/loadcrea.hpp @@ -5,6 +5,7 @@ #include "esm_reader.hpp" #include "esm_writer.hpp" #include "loadcont.hpp" +#include "defs.hpp" namespace ESM { @@ -54,6 +55,7 @@ struct Creature : public Record }; // 96 bytes NPDTstruct data; + AIData aiData; int flags; float scale; @@ -62,6 +64,7 @@ struct Creature : public Record // Defined in loadcont.hpp InventoryList inventory; + SpellList spells; void load(ESMReader &esm); void save(ESMWriter &esm); diff --git a/components/esm/loaddoor.cpp b/components/esm/loaddoor.cpp index 45af407e17..fe00ceb507 100644 --- a/components/esm/loaddoor.cpp +++ b/components/esm/loaddoor.cpp @@ -13,11 +13,11 @@ void Door::load(ESMReader &esm) } void Door::save(ESMWriter &esm) { - esm.writeHNString("MODL", model); - esm.writeHNOString("FNAM", name); - esm.writeHNOString("SCRI", script); - esm.writeHNOString("SNAM", openSound); - esm.writeHNOString("ANAM", closeSound); + esm.writeHNCString("MODL", model); + esm.writeHNOCString("FNAM", name); + esm.writeHNOCString("SCRI", script); + esm.writeHNOCString("SNAM", openSound); + esm.writeHNOCString("ANAM", closeSound); } } diff --git a/components/esm/loadingr.cpp b/components/esm/loadingr.cpp index b8b8aea06e..d539f8d7e0 100644 --- a/components/esm/loadingr.cpp +++ b/components/esm/loadingr.cpp @@ -13,11 +13,11 @@ void Ingredient::load(ESMReader &esm) } void Ingredient::save(ESMWriter &esm) { - esm.writeHNString("MODL", model); - esm.writeHNString("FNAM", name); + esm.writeHNCString("MODL", model); + esm.writeHNCString("FNAM", name); esm.writeHNT("IRDT", data, 56); - esm.writeHNOString("SCRI", script); - esm.writeHNOString("ITEX", script); + esm.writeHNOCString("SCRI", script); + esm.writeHNOCString("ITEX", icon); } } diff --git a/components/esm/loadlevlist.cpp b/components/esm/loadlevlist.cpp index f63a720256..e0d5140885 100644 --- a/components/esm/loadlevlist.cpp +++ b/components/esm/loadlevlist.cpp @@ -38,7 +38,7 @@ void LeveledListBase::save(ESMWriter &esm) for (std::vector::iterator it = list.begin(); it != list.end(); ++it) { - esm.writeHNString(recName, it->id); + esm.writeHNCString(recName, it->id); esm.writeHNT("INTV", it->level); } } diff --git a/components/esm/loadligh.cpp b/components/esm/loadligh.cpp index 2b1d37461f..ce2ffe61f2 100644 --- a/components/esm/loadligh.cpp +++ b/components/esm/loadligh.cpp @@ -15,12 +15,12 @@ void Light::load(ESMReader &esm) } void Light::save(ESMWriter &esm) { - esm.writeHNString("MODL", model); - esm.writeHNOString("FNAM", name); - esm.writeHNOString("ITEX", icon); + esm.writeHNCString("MODL", model); + esm.writeHNOCString("FNAM", name); + esm.writeHNOCString("ITEX", icon); esm.writeHNT("LHDT", data, 24); - esm.writeHNOString("SCRI", script); - esm.writeHNOString("SNAM", sound); + esm.writeHNOCString("SCRI", script); + esm.writeHNOCString("SNAM", sound); } } diff --git a/components/esm/loadlocks.cpp b/components/esm/loadlocks.cpp index b3d53f4588..6b0dc3cc8e 100644 --- a/components/esm/loadlocks.cpp +++ b/components/esm/loadlocks.cpp @@ -33,8 +33,8 @@ void Tool::load(ESMReader &esm) } void Tool::save(ESMWriter &esm) { - esm.writeHNString("MODL", model); - esm.writeHNString("FNAM", name); + esm.writeHNCString("MODL", model); + esm.writeHNCString("FNAM", name); std::string typeName; switch(type) @@ -44,9 +44,17 @@ void Tool::save(ESMWriter &esm) case Type_Probe: typeName = "PBDT"; break; } - esm.writeHNT(typeName, data, 16); + Data write = data; + if (type == Type_Repair) + { + float tmp = *((float*) &write.uses); + write.uses = *((int*) &write.quality); + write.quality = tmp; + } + + esm.writeHNT(typeName, write, 16); esm.writeHNOString("SCRI", script); - esm.writeHNOString("ITEX", icon); + esm.writeHNOCString("ITEX", icon); } diff --git a/components/esm/loadltex.cpp b/components/esm/loadltex.cpp index b4820d9ec3..7c3d95b71f 100644 --- a/components/esm/loadltex.cpp +++ b/components/esm/loadltex.cpp @@ -11,7 +11,7 @@ void LandTexture::load(ESMReader &esm) void LandTexture::save(ESMWriter &esm) { esm.writeHNT("INTV", index); - esm.writeHNString("DATA", texture); + esm.writeHNCString("DATA", texture); } } diff --git a/components/esm/loadmgef.cpp b/components/esm/loadmgef.cpp index 8de37f065e..282bcf52ae 100644 --- a/components/esm/loadmgef.cpp +++ b/components/esm/loadmgef.cpp @@ -28,17 +28,17 @@ void MagicEffect::save(ESMWriter &esm) esm.writeHNT("INDX", index); esm.writeHNT("MEDT", data, 36); - esm.writeHNOString("ITEX", icon); - esm.writeHNOString("PTEX", particle); - esm.writeHNOString("BSND", boltSound); - esm.writeHNOString("CSND", castSound); - esm.writeHNOString("HSND", hitSound); - esm.writeHNOString("ASND", areaSound); + esm.writeHNOCString("ITEX", icon); + esm.writeHNOCString("PTEX", particle); + esm.writeHNOCString("BSND", boltSound); + esm.writeHNOCString("CSND", castSound); + esm.writeHNOCString("HSND", hitSound); + esm.writeHNOCString("ASND", areaSound); - esm.writeHNOString("CVFX", casting); - esm.writeHNOString("BVFX", bolt); - esm.writeHNOString("HVFX", hit); - esm.writeHNOString("AVFX", area); + esm.writeHNOCString("CVFX", casting); + esm.writeHNOCString("BVFX", bolt); + esm.writeHNOCString("HVFX", hit); + esm.writeHNOCString("AVFX", area); esm.writeHNOString("DESC", description); } diff --git a/components/esm/loadmisc.cpp b/components/esm/loadmisc.cpp index cf5cf92ae1..6d5aa3f5ea 100644 --- a/components/esm/loadmisc.cpp +++ b/components/esm/loadmisc.cpp @@ -13,11 +13,11 @@ void Miscellaneous::load(ESMReader &esm) } void Miscellaneous::save(ESMWriter &esm) { - esm.writeHNString("MODL", model); - esm.writeHNOString("FNAM", name); + esm.writeHNCString("MODL", model); + esm.writeHNOCString("FNAM", name); esm.writeHNT("MCDT", data, 12); - esm.writeHNOString("SCRI", script); - esm.writeHNOString("ITEX", icon); + esm.writeHNOCString("SCRI", script); + esm.writeHNOCString("ITEX", icon); } } diff --git a/components/esm/loadnpc.cpp b/components/esm/loadnpc.cpp index b689ba5e84..d250ad455b 100644 --- a/components/esm/loadnpc.cpp +++ b/components/esm/loadnpc.cpp @@ -37,27 +37,20 @@ void NPC::load(ESMReader &esm) inventory.load(esm); spells.load(esm); - - if (esm.isNextSub("AIDT")) - { - esm.getHExact(&AI, sizeof(AI)); - hasAI = true; - } - else - hasAI = false; + aiData.load(esm); esm.skipRecord(); } void NPC::save(ESMWriter &esm) { - esm.writeHNOString("MODL", model); - esm.writeHNOString("FNAM", name); - esm.writeHNString("RNAM", race); - esm.writeHNString("CNAM", cls); - esm.writeHNString("ANAM", faction); - esm.writeHNString("BNAM", head); - esm.writeHNString("KNAM", hair); - esm.writeHNOString("SCRI", script); + esm.writeHNOCString("MODL", model); + esm.writeHNOCString("FNAM", name); + esm.writeHNCString("RNAM", race); + esm.writeHNCString("CNAM", cls); + esm.writeHNCString("ANAM", faction); + esm.writeHNCString("BNAM", head); + esm.writeHNCString("KNAM", hair); + esm.writeHNOCString("SCRI", script); if (npdtType == 52) esm.writeHNT("NPDT", npdt52, 52); @@ -68,9 +61,7 @@ void NPC::save(ESMWriter &esm) inventory.save(esm); spells.save(esm); - - if (hasAI) - esm.writeHNT("AIDT", AI); + aiData.save(esm); } } diff --git a/components/esm/loadnpc.hpp b/components/esm/loadnpc.hpp index 13ee9ef6d7..042d803b7b 100644 --- a/components/esm/loadnpc.hpp +++ b/components/esm/loadnpc.hpp @@ -74,15 +74,6 @@ struct NPC : public Record int gold; // ?? not certain }; // 12 bytes - struct AIDTstruct - { - // These are probabilities - char hello, u1, fight, flee, alarm, u2, u3, u4; - // The last u's might be the skills that this NPC can train you - // in? - int services; // See the Services enum - }; // 12 bytes - #pragma pack(pop) char npdtType; @@ -93,12 +84,10 @@ struct NPC : public Record InventoryList inventory; SpellList spells; - - AIDTstruct AI; - bool hasAI; + AIData aiData; std::string name, model, race, cls, faction, script, - hair, head; // body parts + hair, head; // body parts //std::string mId; diff --git a/components/esm/loadregn.cpp b/components/esm/loadregn.cpp index f9e4a151e7..7a8c5b5b92 100644 --- a/components/esm/loadregn.cpp +++ b/components/esm/loadregn.cpp @@ -27,14 +27,14 @@ void Region::load(ESMReader &esm) } void Region::save(ESMWriter &esm) { - esm.writeHNString("FNAM", name); + esm.writeHNCString("FNAM", name); if (esm.getVersion() == VER_12) esm.writeHNT("WEAT", data, sizeof(data) - 2); else esm.writeHNT("WEAT", data); - esm.writeHNOString("BNAM", sleepList); + esm.writeHNOCString("BNAM", sleepList); esm.writeHNT("CNAM", mapColor); for (std::vector::iterator it = soundList.begin(); it != soundList.end(); ++it) diff --git a/components/esm/loadscpt.cpp b/components/esm/loadscpt.cpp index 658f97a49b..5fdedf4f0f 100644 --- a/components/esm/loadscpt.cpp +++ b/components/esm/loadscpt.cpp @@ -42,21 +42,25 @@ void Script::save(ESMWriter &esm) { std::string varNameString; if (!varNames.empty()) - { for (std::vector::iterator it = varNames.begin(); it != varNames.end(); ++it) - { varNameString.append(*it); - //varNameString.append("\0"); - } - - data.stringTableSize = varNameString.size(); - } esm.writeHNT("SCHD", data, 52); - esm.writeHNOString("SCVR", varNameString); + if (!varNames.empty()) + { + esm.startSubRecord("SCVR"); + for (std::vector::iterator it = varNames.begin(); it != varNames.end(); ++it) + { + esm.writeHCString(*it); + } + esm.endRecord("SCVR"); + } + + esm.startSubRecord("SCDT"); + esm.write(&scriptData[0], data.scriptDataSize); + esm.endRecord("SCDT"); - esm.writeHNString("SCDT", std::string(&scriptData[0], scriptData.size())); esm.writeHNOString("SCTX", scriptText); } diff --git a/components/esm/loadsoun.cpp b/components/esm/loadsoun.cpp index a160f3d1ca..49afaee7f2 100644 --- a/components/esm/loadsoun.cpp +++ b/components/esm/loadsoun.cpp @@ -16,7 +16,7 @@ void Sound::load(ESMReader &esm) } void Sound::save(ESMWriter &esm) { - esm.writeHNString("FNAM", sound); + esm.writeHNCString("FNAM", sound); esm.writeHNT("DATA", data, 3); } diff --git a/components/esm/loadspel.cpp b/components/esm/loadspel.cpp index a87dfb620d..4fe3e27893 100644 --- a/components/esm/loadspel.cpp +++ b/components/esm/loadspel.cpp @@ -11,7 +11,7 @@ void Spell::load(ESMReader &esm) } void Spell::save(ESMWriter &esm) { - esm.writeHNOString("FNAM", name); + esm.writeHNOCString("FNAM", name); esm.writeHNT("SPDT", data, 12); effects.save(esm); } diff --git a/components/esm/loadstat.cpp b/components/esm/loadstat.cpp index 2252e9b030..65e2d724f0 100644 --- a/components/esm/loadstat.cpp +++ b/components/esm/loadstat.cpp @@ -9,7 +9,7 @@ void Static::load(ESMReader &esm) } void Static::save(ESMWriter &esm) { - esm.writeHNString("MODL", model); + esm.writeHNCString("MODL", model); } } diff --git a/components/esm/loadweap.cpp b/components/esm/loadweap.cpp index 6cc7fa02db..557013d620 100644 --- a/components/esm/loadweap.cpp +++ b/components/esm/loadweap.cpp @@ -14,12 +14,12 @@ void Weapon::load(ESMReader &esm) } void Weapon::save(ESMWriter &esm) { - esm.writeHNString("MODL", model); - esm.writeHNOString("FNAM", name); + esm.writeHNCString("MODL", model); + esm.writeHNOCString("FNAM", name); esm.writeHNT("WPDT", data, 32); - esm.writeHNOString("SCRI", script); - esm.writeHNOString("ITEX", icon); - esm.writeHNOString("ENAM", enchant); + esm.writeHNOCString("SCRI", script); + esm.writeHNOCString("ITEX", icon); + esm.writeHNOCString("ENAM", enchant); } } diff --git a/components/esm/record.hpp b/components/esm/record.hpp index dfecab7b93..6154cbd48e 100644 --- a/components/esm/record.hpp +++ b/components/esm/record.hpp @@ -67,10 +67,14 @@ public: std::string getId() const { return m_id; } void setId(const std::string& in) { m_id = in; } + int getFlags() const { return (m_flags & 0x1 ? 0x00002000 : 0) | (m_flags & 0x2 ? 0x00000400 : 0); } + void setFlags(int in) { m_flags = (in & 0x00002000 ? 0x1 : 0) | (in & 0x00000400 ? 0x2 : 0); } + virtual int getName() = 0; protected: std::string m_id; + char m_flags; }; } diff --git a/components/to_utf8/to_utf8.cpp b/components/to_utf8/to_utf8.cpp index 3fbbeb733c..3f5f9f61d6 100644 --- a/components/to_utf8/to_utf8.cpp +++ b/components/to_utf8/to_utf8.cpp @@ -193,3 +193,167 @@ std::string ToUTF8::getUtf8(ToUTF8::FromType from) return std::string(&output[0], outlen); } +static size_t getLength2(const char *arr, const char* input, bool &ascii) +{ + ascii = true; + size_t len = 0; + const char* ptr = input; + unsigned char inp = *ptr; + + // Do away with the ascii part of the string first (this is almost + // always the entire string.) + while(inp && inp < 128) + inp = *(++ptr); + len += (ptr-input); + + // If we're not at the null terminator at this point, then there + // were some non-ascii characters to deal with. Go to slow-mode for + // the rest of the string. + if(inp) + { + ascii = false; + while(inp) + { + len += 1; + // Find the translated length of this character in the + // lookup table. + switch(inp) + { + case 0xe2: len -= 2; break; + case 0xc2: + case 0xcb: + case 0xc4: + case 0xc6: + case 0xc3: + case 0xd0: + case 0xd1: + case 0xd2: + case 0xc5: len -= 1; break; + } + + inp = *(++ptr); + } + } + return len; +} + +#include +#include + +static void copyFromArray2(const char *arr, char*& chp, char* &out) +{ + unsigned char ch = *(chp++); + // Optimize for ASCII values + if(ch < 128) + { + *(out++) = ch; + return; + } + + int len = 1; + switch (ch) + { + case 0xe2: len = 3; break; + case 0xc2: + case 0xcb: + case 0xc4: + case 0xc6: + case 0xc3: + case 0xd0: + case 0xd1: + case 0xd2: + case 0xc5: len = 2; break; + } + + if (len == 1) // There is no 1 length utf-8 glyph that is not 0x20 (empty space) + { + *(out++) = ch; + return; + } + + unsigned char ch2 = *(chp++); + unsigned char ch3 = '\0'; + if (len == 3) + ch3 = *(chp++); + + for (int i = 128; i < 256; i++) + { + unsigned char b1 = arr[i*6 + 1], b2 = arr[i*6 + 2], b3 = arr[i*6 + 3]; + if (b1 == ch && b2 == ch2 && (len != 3 || b3 == ch3)) + { + *(out++) = (char)i; + return; + } + } + + std::cout << "Could not find glyph " << std::hex << (int)ch << " " << (int)ch2 << " " << (int)ch3 << std::endl; + + *(out++) = ch; // Could not find glyph, just put whatever +} + +std::string ToUTF8::getASCII(ToUTF8::FromType to) +{ + // Pick translation array + const char *arr; + switch (to) + { + case ToUTF8::WINDOWS_1252: + { + arr = ToUTF8::windows_1252; + break; + } + case ToUTF8::WINDOWS_1250: + { + arr = ToUTF8::windows_1250; + break; + } + case ToUTF8::WINDOWS_1251: + { + arr = ToUTF8::windows_1251; + break; + } + default: + { + assert(0); + } + } + + // Double check that the input string stops at some point (it might + // contain zero terminators before this, inside its own data, which + // is also ok.) + char* input = &buf[0]; + assert(input[size] == 0); + + // TODO: The rest of this function is designed for single-character + // input encodings only. It also assumes that the input the input + // encoding shares its first 128 values (0-127) with ASCII. These + // conditions must be checked again if you add more input encodings + // later. + + // Compute output length, and check for pure ascii input at the same + // time. + bool ascii; + size_t outlen = getLength2(arr, input, ascii); + + // If we're pure ascii, then don't bother converting anything. + if(ascii) + return std::string(input, outlen); + + // Make sure the output is large enough + resize(output, outlen); + char *out = &output[0]; + + // Translate + while(*input) + copyFromArray2(arr, input, out); + + // Make sure that we wrote the correct number of bytes + assert((out-&output[0]) == (int)outlen); + + // And make extra sure the output is null terminated + assert(output.size() > outlen); + assert(output[outlen] == 0); + + // Return a string + return std::string(&output[0], outlen); +} diff --git a/components/to_utf8/to_utf8.hpp b/components/to_utf8/to_utf8.hpp index 4cbee10196..1a6a077be9 100644 --- a/components/to_utf8/to_utf8.hpp +++ b/components/to_utf8/to_utf8.hpp @@ -21,6 +21,7 @@ namespace ToUTF8 // Convert the previously written buffer to UTF8 from the given code // page. std::string getUtf8(FromType from); + std::string getASCII(FromType to); } #endif From 0c9dfcc0179dfd35984087667cfb22f15b6d60e3 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Sun, 29 Apr 2012 09:26:03 +0200 Subject: [PATCH 13/14] Some changes --- apps/esmtool/esmtool.cpp | 6 ++++-- components/esm/loadland.cpp | 10 +++++++--- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp index 2eab0bc1a8..abbf5ca0e6 100644 --- a/apps/esmtool/esmtool.cpp +++ b/apps/esmtool/esmtool.cpp @@ -41,6 +41,8 @@ struct Arguments string outname; ESMData data; + ESMReader reader; + ESMWriter writer; }; bool parseOptions (int argc, char** argv, Arguments &info) @@ -230,7 +232,7 @@ void printRaw(ESMReader &esm) int load(Arguments& info) { - ESMReader esm; + ESMReader& esm = info.reader; esm.setEncoding(info.encoding); string filename = info.filename; @@ -806,7 +808,7 @@ int clone(Arguments& info) cout << endl << "Saving records to: " << info.outname << "..." << endl; - ESMWriter esm; + ESMWriter& esm = info.writer; esm.setEncoding(info.encoding); esm.setAuthor(info.data.author); esm.setDescription(info.data.description); diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp index 222772041a..512363fa0b 100644 --- a/components/esm/loadland.cpp +++ b/components/esm/loadland.cpp @@ -91,13 +91,17 @@ void Land::save(ESMWriter &esm) esm.writeHNT("DATA", flags); - /* TODO: Land! - if (hasData && !dataLoaded) + // TODO: Land! + bool wasLoaded = dataLoaded; + if (hasData) loadData(); // I think it might be a good idea to have // the data loaded before trying to save it - */ + if (dataLoaded) landData->save(esm); + + if (!wasLoaded) + unloadData(); } void Land::loadData() From 76c4aa41bb4a528197a0fb25d74a374e077cb631 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Mon, 11 Jun 2012 20:02:03 +0200 Subject: [PATCH 14/14] More land and cell work --- components/esm/loadcell.cpp | 15 +++++++--- components/esm/loadcell.hpp | 1 + components/esm/loadland.cpp | 58 +++++++++++++++++++++++-------------- components/esm/loadland.hpp | 14 +++++++-- 4 files changed, 60 insertions(+), 28 deletions(-) diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index 57d951658f..34bcaf34c9 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -9,7 +9,7 @@ namespace ESM void CellRef::save(ESMWriter &esm) { esm.writeHNT("FRMR", refnum); - esm.writeHNString("NAME", refID); + esm.writeHNCString("NAME", refID); if (scale != 1.0) esm.writeHNT("XSCL", scale); @@ -33,7 +33,7 @@ void CellRef::save(ESMWriter &esm) if (teleport) { esm.writeHNT("DODT", doorDest); - esm.writeHNOString("DNAM", destCell); + esm.writeHNOCString("DNAM", destCell); } if (lockLevel != 0) @@ -60,6 +60,7 @@ void Cell::load(ESMReader &esm) // Water level water = 0; + NAM0 = 0; if (data.flags & Interior) { @@ -87,6 +88,8 @@ void Cell::load(ESMReader &esm) region = esm.getHNOString("RGNN"); esm.getHNOT(mapColor, "NAM5"); } + if (esm.isNextSub("NAM0")) + esm.getHT(NAM0); // Save position of the cell references and move on context = esm.getContext(); @@ -112,6 +115,9 @@ void Cell::save(ESMWriter &esm) if (mapColor != 0) esm.writeHNT("NAM5", mapColor); } + + if (NAM0 != 0) + esm.writeHNT("NAM0", NAM0); } void Cell::restore(ESMReader &esm) const @@ -141,9 +147,10 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref) // Number of references in the cell? Maximum once in each cell, // but not always at the beginning, and not always right. In other // words, completely useless. + if (esm.isNextSub("NAM0")) { - int i; - esm.getHNOT(i, "NAM0"); + esm.skipHSubSize(4); + //esm.getHNOT(NAM0, "NAM0"); } esm.getHNT(ref.refnum, "FRMR"); diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index f03c541b7e..a485ceb1fa 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -120,6 +120,7 @@ struct Cell : public Record AMBIstruct ambi; float water; // Water level int mapColor; + int NAM0; void load(ESMReader &esm); void save(ESMWriter &esm); diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp index 512363fa0b..0a6fa63973 100644 --- a/components/esm/loadland.cpp +++ b/components/esm/loadland.cpp @@ -7,11 +7,18 @@ void Land::LandData::save(ESMWriter &esm) { // TODO: Make this actually work. - //esm.writeHNT("VNML", normals, sizeof(VNML)); + esm.writeHNT("VNML", normals, sizeof(VNML)); esm.writeHNT("VHGT", heights, sizeof(VHGT)); - esm.writeHNT("WNAM", 0, 81); - esm.writeHNT("VCLR", colours, 3*LAND_NUM_VERTS); - esm.writeHNT("VTEX", textures, 512); + //esm.writeHNT("WNAM", 0, 81); + esm.startSubRecord("WNAM"); + for (int i = 0; i < 81; i++) + esm.writeT((char)0x80, 1); + esm.endRecord("WNAM"); + + if (dataTypes & Land::DATA_VCLR) + esm.writeHNT("VCLR", colours, 3*LAND_NUM_VERTS); + if (dataTypes & Land::DATA_VTEX) + esm.writeHNT("VTEX", textures, 512); } Land::Land() @@ -19,7 +26,8 @@ Land::Land() , X(0) , Y(0) , mEsm(NULL) - , hasData(false) +// , hasData(false) + , dataTypes(0) , dataLoaded(false) , landData(NULL) { @@ -30,7 +38,6 @@ Land::~Land() delete landData; } - void Land::load(ESMReader &esm) { mEsm = &esm; @@ -47,36 +54,37 @@ void Land::load(ESMReader &esm) context = esm.getContext(); hasData = false; - int cnt = 0; // Skip these here. Load the actual data when the cell is loaded. if (esm.isNextSub("VNML")) { esm.skipHSubSize(12675); - cnt++; + dataTypes |= DATA_VNML; } if (esm.isNextSub("VHGT")) { esm.skipHSubSize(4232); - cnt++; + dataTypes |= DATA_VHGT; } if (esm.isNextSub("WNAM")) { esm.skipHSubSize(81); + dataTypes |= DATA_WNAM; } if (esm.isNextSub("VCLR")) { esm.skipHSubSize(12675); + dataTypes |= DATA_VCLR; } if (esm.isNextSub("VTEX")) { esm.skipHSubSize(512); - cnt++; + dataTypes |= DATA_VTEX; } // We need all three of VNML, VHGT and VTEX in order to use the - // landscape. - hasData = (cnt == 3); + // landscape. (Though Morrowind seems to accept terrain without VTEX/VCLR entries) + hasData = dataTypes & (DATA_VNML|DATA_VHGT|DATA_WNAM); dataLoaded = false; landData = NULL; @@ -101,7 +109,7 @@ void Land::save(ESMWriter &esm) landData->save(esm); if (!wasLoaded) - unloadData(); + unloadData(); // Don't need to keep the data loaded if it wasn't already } void Land::loadData() @@ -117,6 +125,8 @@ void Land::loadData() { mEsm->restoreContext(context); + memset(landData->normals, 0, LAND_NUM_VERTS * 3); + //esm.getHNExact(landData->normals, sizeof(VNML), "VNML"); if (mEsm->isNextSub("VNML")) { @@ -151,16 +161,19 @@ void Land::loadData() }else{ landData->usingColours = false; } - //TODO fix magic numbers - uint16_t vtex[512]; - mEsm->getHNExact(&vtex, 512, "VTEX"); + if (mEsm->isNextSub("VTEX")) + { + //TODO fix magic numbers + uint16_t vtex[512]; + mEsm->getHExact(&vtex, 512); - int readPos = 0; //bit ugly, but it works - for ( int y1 = 0; y1 < 4; y1++ ) - for ( int x1 = 0; x1 < 4; x1++ ) - for ( int y2 = 0; y2 < 4; y2++) - for ( int x2 = 0; x2 < 4; x2++ ) - landData->textures[(y1*4+y2)*16+(x1*4+x2)] = vtex[readPos++]; + int readPos = 0; //bit ugly, but it works + for ( int y1 = 0; y1 < 4; y1++ ) + for ( int x1 = 0; x1 < 4; x1++ ) + for ( int y2 = 0; y2 < 4; y2++) + for ( int x2 = 0; x2 < 4; x2++ ) + landData->textures[(y1*4+y2)*16+(x1*4+x2)] = vtex[readPos++]; + } } else { @@ -172,6 +185,7 @@ void Land::loadData() } } + landData->dataTypes = dataTypes; dataLoaded = true; } diff --git a/components/esm/loadland.hpp b/components/esm/loadland.hpp index 6a14891f19..1cbe4db12e 100644 --- a/components/esm/loadland.hpp +++ b/components/esm/loadland.hpp @@ -26,9 +26,18 @@ struct Land : public Record ESM_Context context; bool hasData; - + int dataTypes; bool dataLoaded; + enum + { + DATA_VNML = 1, + DATA_VHGT = 2, + DATA_WNAM = 4, + DATA_VCLR = 8, + DATA_VTEX = 16 + }; + // number of vertices per side static const int LAND_SIZE = 65; @@ -62,11 +71,12 @@ struct Land : public Record { float heightOffset; float heights[LAND_NUM_VERTS]; - //float normals[LAND_NUM_VERTS * 3]; + VNML normals; uint16_t textures[LAND_NUM_TEXTURES]; bool usingColours; char colours[3 * LAND_NUM_VERTS]; + int dataTypes; void save(ESMWriter &esm); };