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 b48c50640..83ebcefe1 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 917c1031f..a33247906 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 000000000..abe0250df --- /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 0420f37cd..6e5592cf7 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 000000000..da040c664 --- /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 000000000..5adf32049 --- /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 40c9b635c..a5e59a006 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 783559e11..3f968bc7c 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 d3bc36a77..7db9ef9ac 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 c21e5dea0..b447fe50c 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 c76ad5350..17cc22087 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 2caca32b3..ff105a307 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 ddc25e176..14cb056bf 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 16b6b1d3a..5026696c2 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 1c72b0fe0..72d56eac3 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 de3db40fc..46cb1d899 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 ffa958e14..829b7d297 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 3a4ab441e..a46135cc0 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 976cb7d20..9488f355f 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 53964b02c..d00664bff 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 158cc0867..8b3d09183 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 8070f9c03..8d461369c 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 b15852cc2..05cbfe709 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 08412c838..a89481a7a 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 1d6c9d4a1..b1c678348 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 8fa06e7e4..77ef3786a 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 14699ccc5..ba90e52ce 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 4614c4230..bf6994f9a 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 651d9a318..0cab2761e 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 3c334ebbd..2f5f4061d 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 4d38d4a23..056f572ae 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 d2283d351..bdee27586 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 1f18a49d0..a19b0c7ad 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 d3cc69bd4..513eac753 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 2c0db4064..1234ac7f9 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 b2787492d..6157463cf 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 449589e25..609166983 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 346ad2a2e..fdbedcbd0 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 85874aa78..686554da3 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 c946b3fa0..cf43de957 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 5028679dd..669475fe7 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 677642e31..21c2d1fb1 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 01fbc3067..dc0400a4e 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 0f08b3c8a..c240aba87 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 c47af341e..6f2d5ab25 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 471f71780..b71f6f13d 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 af9599ed0..040118bbf 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 96afdf831..4d3a4a0ed 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 ebc314a28..ba506b63b 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 d1bff7972..811964775 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 4affce539..ff20ce9d1 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 721a818f7..b7530eb6c 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 178258a05..aecd8b99b 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 79e882d94..b9f1d35ca 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 a1e537a4c..1c2a709f1 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 08b1cf6dc..b4820d9ec 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 fa4cac10a..d171c8e11 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 2eda67b61..8de37f065 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 b0b330aeb..ed0b03d0b 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 0206661c4..cf5cf92ae 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 7e151f797..9aaa3c1be 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 5b0e90c84..6cb6b64c7 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 62a99e763..3e094a197 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 592d5b57f..a65f6a6b3 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 dc63ce335..572378dad 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 6e2c6e134..ec339240f 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 ce64f5f72..04752add1 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 d4506dbef..15fa43984 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 f31c9a827..d67922b4d 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 1748b3d28..81b8bc51d 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 9c0176725..86d1d8e29 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 3ce3d9636..55cfb053a 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 aa7103efc..adce2f361 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 836f70205..8cc90b063 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 b7b568132..10f010f48 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 2953369c4..e9e20c212 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 cd47f0f17..a160f3d1c 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 775a664be..9f0bdf509 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 c3c928ce6..a87dfb620 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 c97d037cd..971bf23a4 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 f4e79271c..f1099e67b 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 d18bde101..2cc7eccf9 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 654bf290a..2252e9b03 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 4f3121d18..a5b82c46d 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 1910631bc..6cc7fa02d 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 8bd3b147c..8e7947bf3 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 a5e59a006..b62a46158 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 7db9ef9ac..e5d3d8e27 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 17cc22087..6eb164ec2 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 14cb056bf..aecfc7e92 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 829b7d297..ed21d71e1 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 9488f355f..de76e1949 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 8b3d09183..f6db5c70c 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 05cbfe709..e13442dcf 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 b1c678348..cd884d206 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 ba90e52ce..176c4ec05 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 0cab2761e..f5ffb694f 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 513eac753..45af407e1 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 c240aba87..63b3fe3a2 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 b71f6f13d..b8b8aea06 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 b7530eb6c..2b1d37461 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 b9f1d35ca..ff01aac37 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 da040c664..b4690807c 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 4d3a4a0ed..9aa02e478 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 ff01aac37..f49de1bc8 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 572378dad..41dd34174 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 86d1d8e29..291259bc0 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 b4690807c..1875ae330 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 5adf32049..21cb42de9 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 | 879 +++++++++++++++++++++--------- 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, 940 insertions(+), 377 deletions(-) create mode 100644 components/esm/record.hpp diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp index f417d5c60..ea9a388a5 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; + + if (info.mode == "dump") + return load(info); + else if (info.mode == "clone") + return clone(info); + else + { + cout << "Invalid or no mode specified, dying horribly. Have a nice day." << endl; + return 1; + } + + return 0; +} - ESMReader esm; - esm.setEncoding(info.encoding); +void loadCell(Cell &cell, ESMReader &esm, bool quiet) +{ + // Skip back to the beginning of the reference list + cell.restore(esm); - string filename = info.filename; - cout << "\nFile: " << filename << endl; + // Loop through all the references + CellRef ref; + if(!quiet) cout << " References:\n"; + while(cell.getNextRef(esm, ref)) + { + if(quiet) continue; - try { + cout << " Refnum: " << ref.refnum << endl; + cout << " ID: '" << ref.refID << "'\n"; + cout << " Owner: '" << ref.owner << "'\n"; + cout << " INTV: " << ref.intv << " NAM9: " << ref.intv << endl; + } +} - if(info.raw_given) +void printRaw(ESMReader &esm) +{ + while(esm.hasMoreRecs()) { - cout << "RAW file listing:\n"; + NAME n = esm.getRecName(); + cout << "Record: " << n.toString() << endl; + esm.getRecHeader(); + while(esm.hasMoreSubs()) + { + uint64_t offs = esm.getOffset(); + esm.getSubName(); + esm.skipHSub(); + n = esm.retSubName(); + cout << " " << n.toString() << " - " << esm.getSubSize() + << " bytes @ 0x" << hex << offs << "\n"; + } + } +} - esm.openRaw(filename); +int load(Arguments& info) +{ + ESMReader esm; + esm.setEncoding(info.encoding); - printRaw(esm); + string filename = info.filename; + cout << "\nFile: " << filename << endl; - return 0; - } + std::list skipped; - bool quiet = info.quiet_given; - bool loadCells = info.loadcells_given; + try { - esm.open(filename); + if(info.raw_given) + { + cout << "RAW file listing:\n"; - 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; + return 0; } -void loadCell(Cell &cell, ESMReader &esm, bool quiet) +#include + +int clone(Arguments& info) { - // Skip back to the beginning of the reference list - cell.restore(esm); + 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; + } - // Loop through all the references - CellRef ref; - if(!quiet) cout << " References:\n"; - while(cell.getNextRef(esm, ref)) + 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();) { - if(quiet) continue; + Record* rec = *it; + NAME n; + n.val = rec->getName(); + records[n.toString()]++; - cout << " Refnum: " << ref.refnum << endl; - cout << " ID: '" << ref.refID << "'\n"; - cout << " Owner: '" << ref.owner << "'\n"; - cout << " INTV: " << ref.intv << " NAM9: " << ref.intv << endl; + delete rec; + info.data.records.erase(it++); } -} -void printRaw(ESMReader &esm) -{ - while(esm.hasMoreRecs()) + for (std::map::iterator it = records.begin(); it != records.end(); ++it) { - NAME n = esm.getRecName(); - cout << "Record: " << n.toString() << endl; - esm.getRecHeader(); - while(esm.hasMoreSubs()) - { - uint64_t offs = esm.getOffset(); - esm.getSubName(); - esm.skipHSub(); - n = esm.retSubName(); - cout << " " << n.toString() << " - " << esm.getSubSize() - << " bytes @ 0x" << hex << offs << "\n"; - } + 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 1875ae330..57517b0f5 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 21cb42de9..3999e987d 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 3f968bc7c..083c8fc67 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 b447fe50c..5adc44ee2 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 ff105a307..8321778db 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 5026696c2..1b2cb8653 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 46cb1d899..90605e39d 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 a46135cc0..a5a891a58 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 d00664bff..b094b2e49 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 8d461369c..f03c541b7 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 a89481a7a..084f1edb1 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 77ef3786a..4d0ec06cd 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 bf6994f9a..7d8952e38 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 f5ffb694f..7b84a7f29 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 2f5f4061d..3035003cf 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 056f572ae..0a575921a 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 a19b0c7ad..92818598e 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 1234ac7f9..e8b3be970 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 609166983..1cb417c9f 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 686554da3..f62c92e19 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 669475fe7..8a6991490 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 dc0400a4e..0854ea2aa 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 6f2d5ab25..36c31a422 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 040118bbf..8536d5b02 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 ba506b63b..6a14891f1 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 ff20ce9d1..c8591d7d2 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 aecd8b99b..75a78ae5f 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 1c2a709f1..c92a56ea7 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 d171c8e11..994e12024 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 ed0b03d0b..1c95be2bc 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 9aaa3c1be..3d6cdb526 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 6cb6b64c7..34b5e69ed 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 3e094a197..3f8a60304 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 a65f6a6b3..46d1bf9d2 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 ec339240f..db423204c 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 15fa43984..5c0593786 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 81b8bc51d..90444b5ad 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 55cfb053a..bf6082704 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 8cc90b063..68ada6020 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 e9e20c212..33b89726f 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 9f0bdf509..05663ba22 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 971bf23a4..674f7e35d 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 2cc7eccf9..2249b08ee 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 a5b82c46d..3ebbd4813 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 8e7947bf3..4d464a7ee 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 000000000..666a6c15b --- /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 704a11609..e05f74f5d 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 d7a4100aa..bc3b676a2 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 ea9a388a5..97f1aa2a5 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 6e5592cf7..3e69aa528 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 57517b0f5..14e28f6ba 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); + + m_header.records = 0; + writeHNT("HEDR", m_header, 300); - endRecord(); + for (std::list::iterator it = m_masters.begin(); it != m_masters.end(); ++it) + { + writeHNString("MAST", it->name); + writeHNT("DATA", it->size); + } - // TODO: Saving + 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 3999e987d..4439693c4 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 aecfc7e92..ca5865083 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 fdbedcbd0..2a927ad28 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 9aa02e478..222772041 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 811964775..f63a72025 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 f49de1bc8..b3d53f458 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 41dd34174..ebdb6e837 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 d67922b4d..f9e4a151e 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 291259bc0..ecb58cc31 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 666a6c15b..d273b175a 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 97f1aa2a5..a8eeaee7f 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 a8eeaee7f..dd9ed648c 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 f6db5c70c..920fa8ad9 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 dd9ed648c..06348e949 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 7270fd22b..8a5b149ff 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 83a94d27d..04ac31f98 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 7b84a7f29..259d37b4a 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 3035003cf..348c14b23 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 34b5e69ed..b689ba5e8 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 3f8a60304..13ee9ef6d 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 d273b175a..dfecab7b9 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 bc3b676a2..22bb55b52 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 06348e949..002758bed 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 14e28f6ba..4e0a6f460 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 4439693c4..337af9e5e 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 e13442dcf..6e6de4e71 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 2a927ad28..1a151cbe1 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 04752add1..8c82bd38a 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 ecb58cc31..658f97a49 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 | 20 +-- 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, 569 insertions(+), 133 deletions(-) diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp index 002758bed..2eab0bc1a 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 a33247906..caf81aad1 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 4e0a6f460..ef8a9c1b8 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 337af9e5e..6eb34a97c 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 b62a46158..9b08ad266 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 e5d3d8e27..969fb0aae 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 6eb164ec2..55dc8dc88 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 ca5865083..c79e1fed2 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 72d56eac3..376320fb5 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 ed21d71e1..9dba83808 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 de76e1949..3b7bae9f7 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 920fa8ad9..57d951658 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 cd884d206..37a445c19 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 176c4ec05..125ec72d4 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 259d37b4a..c4f9dca48 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 348c14b23..355065aeb 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 45af407e1..fe00ceb50 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 b8b8aea06..d539f8d7e 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 f63a72025..e0d514088 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 2b1d37461..ce2ffe61f 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 b3d53f458..6b0dc3cc8 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 b4820d9ec..7c3d95b71 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 8de37f065..282bcf52a 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 cf5cf92ae..6d5aa3f5e 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 b689ba5e8..d250ad455 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 13ee9ef6d..042d803b7 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 f9e4a151e..7a8c5b5b9 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 658f97a49..5fdedf4f0 100644 --- a/components/esm/loadscpt.cpp +++ b/components/esm/loadscpt.cpp @@ -41,22 +41,26 @@ void Script::load(ESMReader &esm) 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); + + esm.writeHNT("SCHD", data, 52); + if (!varNames.empty()) { + esm.startSubRecord("SCVR"); for (std::vector::iterator it = varNames.begin(); it != varNames.end(); ++it) { - varNameString.append(*it); - //varNameString.append("\0"); + esm.writeHCString(*it); } - - data.stringTableSize = varNameString.size(); + esm.endRecord("SCVR"); } - esm.writeHNT("SCHD", data, 52); - - esm.writeHNOString("SCVR", varNameString); + 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 a160f3d1c..49afaee7f 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 a87dfb620..4fe3e2789 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 2252e9b03..65e2d724f 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 6cc7fa02d..557013d62 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 dfecab7b9..6154cbd48 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 3fbbeb733..3f5f9f61d 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 4cbee1019..1a6a077be 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 2eab0bc1a..abbf5ca0e 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 222772041..512363fa0 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 | 60 +++++++++++++++++++++++-------------- components/esm/loadland.hpp | 14 +++++++-- 4 files changed, 61 insertions(+), 29 deletions(-) diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index 57d951658..34bcaf34c 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 f03c541b7..a485ceb1f 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 512363fa0..0a6fa6397 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"); - - 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++]; + 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++]; + } } 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 6a14891f1..1cbe4db12 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); };