summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source/tags.h
blob: 273e7eede1fbdf0b2f858cc283cf69e8f860fb4c (plain) (blame)
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
205
/*
 *  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>

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_LEVEL_ATTITUDE,                 // monster attitudes
    TAG_LOST_MONSTERS,                  // monsters in transit
    TAG_LEVEL_TILES,
    NUM_TAGS
};

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
};

// Let CDO updaters know if the syntax changes.
#define TAG_MAJOR_START     5
#define TAG_MAJOR_VERSION  16

// Minor version will be reset to zero when major version changes.
enum tag_minor_version
{
    TAG_MINOR_RESET     = 0, // Minor tags were reset
    TAG_MINOR_VERSION   = 0  // 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
 * *********************************************************************** */

class writer
{
public:
    writer(FILE* output)
        : _file(output), _pbuf(0) {}
    writer(std::vector<unsigned char>* poutput)
        : _file(0), _pbuf(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 marshallLong    (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(FILE* input, char minorVersion = TAG_MINOR_VERSION)
        : _file(input), _pbuf(0), _read_offset(0),
          _minorVersion(minorVersion) {}
    reader(const std::vector<unsigned char>& input,
           char minorVersion = TAG_MINOR_VERSION)
        : _file(0), _pbuf(&input), _read_offset(0),
          _minorVersion(minorVersion) {}

    unsigned char readByte();
    void read(void *data, size_t size);
    char getMinorVersion();

private:
    FILE* _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     unmarshallLong    (reader &);
float       unmarshallFloat   (reader &);
bool        unmarshallBoolean (reader &);
int         unmarshallCString (reader &, char *data, int maxSize);
std::string unmarshallString  (reader &, int maxSize = 1000);
void        unmarshallString4 (reader &, std::string&);
void        unmarshallCoord   (reader &, coord_def &c);
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);
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