1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
|
/*
* File: tags.h
* Summary: Auxilary functions to make savefile versioning simpler.
* Written by: Gordon Lipford
*/
#ifndef TAGS_H
#define TAGS_H
#include <cstdio>
#include <stdint.h>
#include "tag-version.h"
struct show_type;
enum tag_type // used during save/load process to identify data blocks
{
TAG_NO_TAG = 0, // should NEVER be read in!
TAG_YOU = 1, // 'you' structure
TAG_YOU_ITEMS, // your items
TAG_YOU_DUNGEON, // dungeon specs (stairs, branches, features)
TAG_LEVEL, // various grids & clouds
TAG_LEVEL_ITEMS, // items/traps
TAG_LEVEL_MONSTERS, // monsters
TAG_GHOST, // ghost
TAG_LOST_MONSTERS, // monsters in transit
TAG_LEVEL_TILES,
TAG_GAME_STATE,
NUM_TAGS,
// Returned when a known tag was deliberately not read. This value is
// never saved and can safely be changed at any point.
TAG_SKIP
};
enum tag_file_type // file types supported by tag system
{
TAGTYPE_PLAYER = 0, // Foo.sav
TAGTYPE_LEVEL, // Foo.00a, .01a, etc.
TAGTYPE_GHOST, // bones.xxx
TAGTYPE_PLAYER_NAME, // Used only to read the player name
};
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
* *********************************************************************** */
class writer
{
public:
writer(FILE* output)
: _file(output), _pbuf(0) { ASSERT(output); }
writer(std::vector<unsigned char>* poutput)
: _file(0), _pbuf(poutput) { ASSERT(poutput); }
void writeByte(unsigned char byte);
void write(const void *data, size_t size);
long tell();
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& );
void marshallShort (writer &, int16_t );
void marshallInt (writer &, int32_t );
void marshallFloat (writer &, float );
void marshallBoolean (writer &, bool );
void marshallString (writer &, const std::string &, int maxSize = 0);
void marshallString4 (writer &, const std::string &);
void marshallCoord (writer &, const coord_def &);
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
* *********************************************************************** */
class reader
{
public:
reader(const std::string &filename, char minorVersion = TAG_MINOR_VERSION);
reader(FILE* input, char minorVersion = TAG_MINOR_VERSION)
: _file(input), opened_file(false), _pbuf(0), _read_offset(0),
_minorVersion(minorVersion) {}
reader(const std::vector<unsigned char>& input,
char minorVersion = TAG_MINOR_VERSION)
: _file(0), opened_file(false), _pbuf(&input), _read_offset(0),
_minorVersion(minorVersion) {}
~reader();
unsigned char readByte();
void read(void *data, size_t size);
void advance(size_t size);
char getMinorVersion();
bool valid() const;
private:
FILE* _file;
bool opened_file;
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 &);
int16_t unmarshallShort (reader &);
int32_t unmarshallInt (reader &);
float unmarshallFloat (reader &);
bool unmarshallBoolean (reader &);
std::string unmarshallString (reader &, int maxSize = 1000);
void unmarshallString4 (reader &, std::string&);
coord_def unmarshallCoord (reader &);
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
* *********************************************************************** */
tag_type tag_read(FILE* inf, char minorVersion, char expected_tags[NUM_TAGS]);
void tag_write(tag_type tagID, FILE* outf);
void tag_set_expected(char tags[], int fileType);
void tag_missing(int tag, char minorVersion);
/* ***********************************************************************
* misc
* *********************************************************************** */
int write2(FILE * file, const void *buffer, unsigned int count);
int read2(FILE * file, void *buffer, unsigned int count);
std::string make_date_string( time_t in_date );
time_t parse_date_string( char[20] );
#endif // TAGS_H
|