summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source/tags.h
blob: 64eb097c8eb53a3c4fb3dd6592361b49664d1210 (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
/**
 * @file
 * @brief Auxiliary functions to make savefile versioning simpler.
**/

#ifndef TAGS_H
#define TAGS_H

#include <cstdio>

#include "package.h"

struct show_type;
struct monster_info;
struct map_cell;

enum tag_type   // used during save/load process to identify data blocks
{
    TAG_NO_TAG = 0,                     // should NEVER be read in!
    TAG_CHR = 1,                        // basic char info
    TAG_YOU,                            // the main part of the save
    TAG_LEVEL,                          // a single dungeon level
    TAG_GHOST,                          // ghost
    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
};

/* ***********************************************************************
 * writer API
 * *********************************************************************** */

class writer
{
public:
    writer(const string &filename, FILE* output, bool ignore_errors = false)
        : _filename(filename), _file(output), _chunk(0),
          _ignore_errors(ignore_errors), _pbuf(0), failed(false)
    {
        ASSERT(output);
    }
    writer(vector<unsigned char>* poutput)
        : _filename(), _file(0), _chunk(0), _ignore_errors(false),
          _pbuf(poutput), failed(false) { ASSERT(poutput); }
    writer(package *save, const string &chunkname)
        : _filename(), _file(0), _chunk(0), _ignore_errors(false),
          failed(false)
    {
        ASSERT(save);
        _chunk = save->writer(chunkname);
    }

    ~writer() { if (_chunk) delete _chunk; }

    void writeByte(unsigned char byte);
    void write(const void *data, size_t size);
    long tell();

    bool succeeded() const { return !failed; }

private:
    void check_ok(bool ok);

private:
    string _filename;
    FILE* _file;
    chunk_writer *_chunk;
    bool _ignore_errors;

    vector<unsigned char>* _pbuf;

    bool failed;
};

void marshallByte    (writer &, int8_t);
void marshallShort   (writer &, int16_t);
void marshallInt     (writer &, int32_t);
void marshallFloat   (writer &, float);
void marshallUByte   (writer &, uint8_t);
void marshallBoolean (writer &, bool);
void marshallString  (writer &, const string &);
void marshallString4 (writer &, const string &);
void marshallCoord   (writer &, const coord_def &);
void marshallItem    (writer &, const item_def &, bool info = false);
void marshallMonster (writer &, const monster&);
void marshall_level_id(writer& th, const level_id& id);
void marshallUnsigned(writer& th, uint64_t v);
void marshallSigned(writer& th, int64_t v);

/* ***********************************************************************
 * reader API
 * *********************************************************************** */

class reader
{
public:
    reader(const string &filename, int minorVersion = TAG_MINOR_INVALID);
    reader(FILE* input, int minorVersion = TAG_MINOR_INVALID)
        : _file(input), _chunk(0), opened_file(false), _pbuf(0),
          _read_offset(0), _minorVersion(minorVersion), _safe_read(false) {}
    reader(const vector<unsigned char>& input,
           int minorVersion = TAG_MINOR_INVALID)
        : _file(0), _chunk(0), opened_file(false), _pbuf(&input),
          _read_offset(0), _minorVersion(minorVersion), _safe_read(false) {}
    reader(package *save, const string &chunkname,
           int minorVersion = TAG_MINOR_INVALID);
    ~reader();

    unsigned char readByte();
    void read(void *data, size_t size);
    void advance(size_t size);
    int getMinorVersion() const;
    void setMinorVersion(int minorVersion);
    bool valid() const;
    void fail_if_not_eof(const string &name);
    void close();

    string filename() const { return _filename; }

    void set_safe_read(bool setting) { _safe_read = setting; }

private:
    string _filename;
    FILE* _file;
    chunk_reader *_chunk;
    bool  opened_file;
    const vector<unsigned char>* _pbuf;
    unsigned int _read_offset;
    int _minorVersion;
    // always throw an exception rather than dying when reading past EOF
    bool _safe_read;
};

class short_read_exception : exception {};

int8_t      unmarshallByte    (reader &);
int16_t     unmarshallShort   (reader &);
int32_t     unmarshallInt     (reader &);
float       unmarshallFloat   (reader &);
uint8_t     unmarshallUByte   (reader &);
bool        unmarshallBoolean (reader &);
string      unmarshallString  (reader &);
void        unmarshallString4 (reader &, string&);
coord_def   unmarshallCoord   (reader &);
void        unmarshallItem    (reader &, item_def &item);
void        unmarshallMonster (reader &, monster& item);
level_id    unmarshall_level_id(reader& th);

uint64_t unmarshallUnsigned(reader& th);
template<typename T>
static inline void unmarshallUnsigned(reader& th, T& v)
{
    v = (T)unmarshallUnsigned(th);
}

int64_t unmarshallSigned(reader& th);
template<typename T>
static inline void unmarshallSigned(reader& th, T& v)
{
    v = (T)unmarshallSigned(th);
}

/* ***********************************************************************
 * Tag interface
 * *********************************************************************** */

void tag_read(reader &inf, tag_type tag_id);
void tag_write(tag_type tagID, writer &outf);
void tag_read_char(reader &th, uint8_t format, uint8_t major, uint8_t minor);

/* ***********************************************************************
 * misc
 * *********************************************************************** */

string make_date_string(time_t in_date);

#endif // TAGS_H