diff options
-rw-r--r-- | crawl-ref/source/tags.cc | 106 | ||||
-rw-r--r-- | crawl-ref/source/tags.h | 63 |
2 files changed, 169 insertions, 0 deletions
diff --git a/crawl-ref/source/tags.cc b/crawl-ref/source/tags.cc index fabf242086..c5d71c37fb 100644 --- a/crawl-ref/source/tags.cc +++ b/crawl-ref/source/tags.cc @@ -621,6 +621,112 @@ std::string make_date_string( time_t in_date ) return (buff); } +void marshallEnumVal(writer& wr, const enum_info *ei, int val) +{ + enum_write_state& ews = wr.used_enums[ei]; + + if (!ews.store_type) + { + std::vector<std::pair<int, std::string> > values; + + ei->collect(values); + + for (unsigned i = 0; i < values.size(); ++i) + { + ews.names.insert(values[i]); + } + + ews.store_type = 1; + + if (ews.names.begin() != ews.names.end() + && (ews.names.rbegin()->first >= 128 + || ews.names.begin()->first <= -1)) + { + ews.store_type = 2; + } + + marshallByte(wr, ews.store_type); + } + + if (ews.store_type == 2) + marshallShort(wr, val); + else + marshallByte(wr, val); + + if (ews.used.find(val) == ews.used.end()) + { + ASSERT( ews.names.find(val) != ews.names.end() ); + marshallString( wr, ews.names[val] ); + + ews.used.insert(val); + } +} + +int unmarshallEnumVal(reader& rd, const enum_info *ei) +{ + enum_read_state& ers = rd.seen_enums[ei]; + + if (!ers.store_type) + { + std::vector<std::pair<int, std::string> > values; + + ei->collect(values); + + for (unsigned i = 0; i < values.size(); ++i) + { + ers.names.insert(make_pair(values[i].second, values[i].first)); + } + + if (rd.getMinorVersion() < ei->non_historical_first) + { + ers.store_type = ei->historic_bytes; + + const enum_info::enum_val *evi = ei->historical; + + for (; evi->name; ++evi) + { + if (ers.names.find(std::string(evi->name)) != ers.names.end()) + { + ers.mapping[evi->value] = ers.names[std::string(evi->name)]; + } + else + { + ers.mapping[evi->value] = ei->replacement; + } + } + } + else + { + ers.store_type = unmarshallByte(rd); + } + } + + int raw; + + if (ers.store_type == 2) + raw = unmarshallShort(rd); + else + raw = unmarshallByte(rd); + + if (ers.mapping.find(raw) != ers.mapping.end()) + return ers.mapping[raw]; + + ASSERT( rd.getMinorVersion() >= ei->non_historical_first ); + + std::string name = unmarshallString(rd); + + if (ers.names.find(name) != ers.names.end()) + { + ers.mapping[raw] = ers.names[name]; + } + else + { + ers.mapping[raw] = ei->replacement; + } + + return ers.mapping[raw]; +} + static int get_val_from_string( const char *ptr, int len ) { int ret = 0; diff --git a/crawl-ref/source/tags.h b/crawl-ref/source/tags.h index 773c686b49..1d72c856a0 100644 --- a/crawl-ref/source/tags.h +++ b/crawl-ref/source/tags.h @@ -65,6 +65,47 @@ enum tag_minor_version TAG_MINOR_VERSION = 12 // Current version. (Keep equal to max.) }; +struct enum_info +{ + void (*collect)(std::vector<std::pair<int,std::string> >& prs); + int replacement; + + struct enum_val + { + int value; + const char *name; + }; + + const enum_val *historical; + tag_minor_version non_historical_first; + char historic_bytes; +}; + +struct enum_write_state +{ + std::set<int> used; + std::map<int, std::string> names; + char store_type; + + enum_write_state() : used(), names(), store_type(0) {} +}; + +struct enum_read_state +{ + std::map<int, int> mapping; + std::map<std::string, int> names; + char store_type; + + enum_read_state() : mapping(), names(), store_type(0) {} +}; + +template<typename enm> struct enum_details; + +// TO ADD A NEW ENUM UNDER THE UMBRELLA OF marshallEnum: +// * Create an enum_info instance +// * Instanciate the enum_details template +// * Change existing serialization to use marshallEnum +// * Bump minor version /* *********************************************************************** * writer API @@ -85,6 +126,9 @@ public: private: FILE* _file; std::vector<unsigned char>* _pbuf; + + std::map<const enum_info*, enum_write_state> used_enums; + friend void marshallEnumVal(writer&, const enum_info*, int); }; void marshallByte (writer &, const char& ); @@ -99,6 +143,14 @@ void marshallItem (writer &, const item_def &); void marshallMonster (writer &, const monsters &); void marshallShowtype (writer &, const show_type &); +void marshallEnumVal (writer &, const enum_info *, int); + +template<typename enm> +inline void marshallEnum(writer& wr, enm value) +{ + marshallEnumVal(wr, &enum_details<enm>::desc, static_cast<int>(value)); +} + /* *********************************************************************** * reader API * *********************************************************************** */ @@ -123,6 +175,9 @@ private: const std::vector<unsigned char>* _pbuf; unsigned int _read_offset; char _minorVersion; + + std::map<const enum_info*, enum_read_state> seen_enums; + friend int unmarshallEnumVal(reader &, const enum_info *); }; char unmarshallByte (reader &); @@ -138,6 +193,14 @@ void unmarshallItem (reader &, item_def &item); void unmarshallMonster (reader &, monsters &item); show_type unmarshallShowtype (reader &); +int unmarshallEnumVal (reader &, const enum_info *); + +template<typename enm> +inline enm unmarshallEnum(writer& wr) +{ + return static_cast<enm>(unmarshallEnumVal(wr, &enum_details<enm>::desc)); +} + /* *********************************************************************** * Tag interface * *********************************************************************** */ |