running with and without this patch applied for about a week, and none of my saves have broken, so I'm ready to commit it.
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@3685 c06c8d41-db1a-0410-9941-cceddc491573
52J7CYVAW3QCUEWA5OKWPDGOP6JZR5NJSE3JDLZFBCR7B6LH5ASAC
RS24ZF3Y47QA2534EHQWZ35O2CI4JUOIVHUPRANCCNLVINSCYFXQC
L3DRKFURVDCV3EJKGG6GVVQX3D5MZPICTVOKNOD3LGM2PECBA7PQC
SVY2PTCLXR3KNPQAWXVXTTGCC5DR334HOAKHYO3VDDRWM2BWMALAC
K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC
A5H6EHZ5L5Z3BW2MIEJSDZMGTUQIJT6HSQXJVFBN5ZR55SGNNQNQC
SDLKLUNFGVKDS55DDJZCBAVIB7NL3RRYPTACAY65SCUQKV6APFSAC
3PY3L3A4QRW3Z5Y7SHO4TMVOOP2VNCO27X2MX4DTOP2SADLBQUOAC
IVVTHLTTLOP5TSULXJWUSSXHOKYWVU3OWKYVK45A7RIB6V34MYQAC
RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC
EGV2HM7SD7UQSWJGLR65NQJTUBAJ7WHLM67FMH4UFP7JRSFKREPAC
7Y5HSDFKA5TPLS2TWTRFMQVX6UXUDHXU5MUMXQSDFAIY4THQ3BIQC
7AMQN7MITMXBNVDAK5VOXTQ4TZIAOD6ZLOFJG7GQMBTY23Y2BKSAC
RISMOCQM6BKK4XSIRKYLOBB2UPDYJNDAL6OGIIR5GGNZQAK5YSZAC
D27U7RT2C77NEUBP6JCSQJ2DRCJVHOXUO2PFZ45VFYMEVMKI4TSAC
DOZORMA366M4HB5JKSS27BMCR6ET7QNZNND2B7KV3NVEEPR5H7EAC
5ASC3STDYCNLZFEBN6UTMUCGDETHBR2OCBZCF5VIAZ5RRWLOTDYQC
7KWDC7XFNMBLSUO2HISIROBINZBX5T67LJEEXTAORXW2YZ7VWFGAC
475LL4U4ND6PTNV4XKC7WQAOJC7RF2VCCVX3DRILP2PKIBFYWE6QC
25CH7HH4LKXFIZ75YNMXS3TSXO6O27DYSOPLOD45K4OCNFWLS4LQC
RBAGQ2PB7V5YAM5KSHSZR2E3MLKDSRVM5XYGI2TIXP5QMVBOQHDQC
LCCGXSFIDQFIRXHGRJWOELNPQOHHCXCWXS366GOULDFPQVOKAIJAC
UZ6N6HOUPGVSPC5NQROEEDWMEGJA5XUWUY2AKH5QG65AZ25PVXDAC
AVCMVFA3MKCXHO6H44UK5KJNIHTGQV7UA7GYXM26VI6TXXU5ZN6QC
X5WLJCJVW55SXZVP7IKP7ADCJIGNKN4PKAXFECVR6TNK7XSMZR7QC
K2GMFKXUWN5R3KCW6OYVXHN47MIQZKEEIOSAU6LFFKBNKF6JBVWAC
GQL5SIGBHLU3FMCE54XVGLRY5AZHRM6DUEB722REA2DPLGJSN6EQC
TLO257LZSB6ZO36STDUEWJBO2LETXFKTFGXELA6Y4BZBVAEIIINAC
L4RYVF46EQKMVOEADGRG4WMPVTQ6NNFGYMU4SHAH6XJIKWVHT77QC
EJ4GIPFSSQCQASUMRF4CR2WPUQOTEHFRGLOYEZ7BH6YEMIR6DN4QC
AUXHSGS4EFOPZ6TVZYWNVOUDO7NYKUKE3HBKGQQWTALSVFOE3HAAC
DKRSOHZXL6EPSLKOKHF7GJXSZEJVY7CXGACSHWLM5B5FTRETWWCAC
BW72LH6NR2NBFFKPM3YZSQEDAFNI6AQIJJ6DV4WYCOXW5JZS5Z2QC
// last updated 22jan2001 {gdl}
/* ***********************************************************************
* called from: files tags
* *********************************************************************** */
int write2(FILE * file, const char *buffer, unsigned int count);
void marshallByte (writer &, char );
void marshallShort (writer &, short );
void marshallLong (writer &, long );
void marshallFloat (writer &, float );
void marshallBoolean (writer &, bool );
void marshallString (writer &, const std::string &, int maxSize = 0);
void marshallCoord (writer &, const coord_def &);
void marshallItem (writer &, const item_def &);
// last updated 22jan2001 {gdl}
/* ***********************************************************************
* called from: files tags
* *********************************************************************** */
void marshallByte(tagHeader &th, char data);
void marshallShort(tagHeader &th, short data);
void marshallLong(tagHeader &th, long data);
void marshallFloat(tagHeader &th, float data);
void marshallBoolean(tagHeader &th, bool data);
void marshallString(tagHeader &th, const std::string &data,
int maxSize = 0);
void marshallCoord(tagHeader &th, const coord_def &c);
void marshallItem(tagHeader &th, const item_def &item);
unsigned char readByte();
void read(void *data, size_t size);
// last updated 22jan2001 {gdl}
/* ***********************************************************************
* called from: tags files
* *********************************************************************** */
char unmarshallByte(tagHeader &th);
short unmarshallShort(tagHeader &th);
long unmarshallLong(tagHeader &th);
float unmarshallFloat(tagHeader &th);
bool unmarshallBoolean(tagHeader &th);
int unmarshallCString(tagHeader &th, char *data, int maxSize);
std::string unmarshallString(tagHeader &th, int maxSize = 1000);
void unmarshallCoord(tagHeader &th, coord_def &c);
void unmarshallItem(tagHeader &th, item_def &item);
std::string make_date_string( time_t in_date );
time_t parse_date_string( char[20] );
// last updated 22jan2001 {gdl}
/* ***********************************************************************
* called from: acr
* *********************************************************************** */
void tag_init(long largest_tag = 100000);
private:
FILE* _file;
const std::vector<unsigned char>* _pbuf;
unsigned int _read_offset;
};
// last updated 22jan2001 {gdl}
/* ***********************************************************************
* called from: files
* *********************************************************************** */
void tag_construct(tagHeader &th, int i);
char unmarshallByte (reader &);
short unmarshallShort (reader &);
long unmarshallLong (reader &);
float unmarshallFloat (reader &);
bool unmarshallBoolean (reader &);
int unmarshallCString (reader &, char *data, int maxSize);
std::string unmarshallString (reader &, int maxSize = 1000);
void unmarshallCoord (reader &, coord_def &c);
void unmarshallItem (reader &, item_def &item);
// last updated 22jan2001 {gdl}
/* ***********************************************************************
* called from: files
* *********************************************************************** */
tag_type tag_read(FILE* inf, char minorVersion);
void tag_write(tag_type tagID, FILE* outf);
// last updated 22jan2001 {gdl}
/* ***********************************************************************
* called from: files
* *********************************************************************** */
int tag_read(FILE *fp, char minorVersion);
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] );
1. Tag types are enumerated in tags.h, from TAG_VERSION (more a placeholder
than anything else, it is not actually saved as a tag) to TAG_XXX. NUM_TAGS
is equal to the actual number of defined tags.
1. Tag types are enumerated in tags.h.
2. Tags are created with tag_construct(), which forwards the construction
request appropriately. tag_write() is then used to write the tag to an
output stream.
2. Tags are written to a FILE* using tag_write(tag_type t). The serialization
request is forwarded appropriately.
3. Tags are parsed with tag_read(), which tries to read a tag header and then
forwards the request appropriately, returning the ID of the tag it found,
or zero if no tag was found.
3. Tags are read from a FILE* with tag_read(), which does not need a tag_type
argument. A header is read, which tells tag_read what to construct.
// static helpers
static void tag_construct_you(tagHeader &th);
static void tag_construct_you_items(tagHeader &th);
static void tag_construct_you_dungeon(tagHeader &th);
static void tag_construct_lost_monsters(tagHeader &th);
static void tag_construct_lost_items(tagHeader &th);
static void tag_read_you(tagHeader &th, char minorVersion);
static void tag_read_you_items(tagHeader &th, char minorVersion);
static void tag_read_you_dungeon(tagHeader &th);
static void tag_read_lost_monsters(tagHeader &th, int minorVersion);
static void tag_read_lost_items(tagHeader &th, int minorVersion);
static void tag_construct_level(tagHeader &th);
static void tag_construct_level_items(tagHeader &th);
static void tag_construct_level_monsters(tagHeader &th);
static void tag_construct_level_attitude(tagHeader &th);
static void tag_construct_level_tiles(struct tagHeader &th);
static void tag_read_level(tagHeader &th, char minorVersion);
static void tag_read_level_items(tagHeader &th, char minorVersion);
static void tag_read_level_monsters(tagHeader &th, char minorVersion);
static void tag_read_level_attitude(tagHeader &th);
static void tag_missing_level_attitude();
static void tag_read_level_tiles(struct tagHeader &th);
static void tag_missing_level_tiles();
static void tag_construct_ghost(tagHeader &th);
static void tag_read_ghost(tagHeader &th, char minorVersion);
static void marshallGhost(tagHeader &th, const ghost_demon &ghost);
static ghost_demon unmarshallGhost( tagHeader &th );
static void marshallResists(tagHeader &, const mon_resist_def &);
static void unmarshallResists(tagHeader &, mon_resist_def &);
static void marshallSpells(tagHeader &, const monster_spells &);
static void unmarshallSpells(tagHeader &, monster_spells &);
static void marshall_monster(tagHeader &th, const monsters &m);
static void unmarshall_monster(tagHeader &th, monsters &m);
template<typename T, typename T_iter, typename T_marshal>
static void marshall_iterator(tagHeader &th, T_iter beg, T_iter end,
T_marshal marshal);
template<typename T>
static void unmarshall_vector(tagHeader& th, std::vector<T>& vec,
T (*T_unmarshall)(tagHeader&));
//////////////////////////////////////////////////////////////////////
// tagHeader
unsigned char tagHeader::readByte()
// Reads input in network byte order, from a file or buffer.
unsigned char reader::readByte()
// static helpers
static void tag_construct_you(writer &th);
static void tag_construct_you_items(writer &th);
static void tag_construct_you_dungeon(writer &th);
static void tag_construct_lost_monsters(writer &th);
static void tag_construct_lost_items(writer &th);
static void tag_read_you(reader &th, char minorVersion);
static void tag_read_you_items(reader &th, char minorVersion);
static void tag_read_you_dungeon(reader &th);
static void tag_read_lost_monsters(reader &th, int minorVersion);
static void tag_read_lost_items(reader &th, int minorVersion);
static void tag_construct_level(writer &th);
static void tag_construct_level_items(writer &th);
static void tag_construct_level_monsters(writer &th);
static void tag_construct_level_attitude(writer &th);
static void tag_construct_level_tiles(writer &th);
static void tag_read_level(reader &th, char minorVersion);
static void tag_read_level_items(reader &th, char minorVersion);
static void tag_read_level_monsters(reader &th, char minorVersion);
static void tag_read_level_attitude(reader &th);
static void tag_missing_level_attitude();
static void tag_read_level_tiles(struct reader &th);
static void tag_missing_level_tiles();
void tagHeader::advance(int skip)
{
if (file)
fseek(file, skip, SEEK_CUR);
else
offset += skip;
}
static void tag_construct_ghost(writer &th);
static void tag_read_ghost(reader &th, char minorVersion);
static void marshallGhost(writer &th, const ghost_demon &ghost);
static ghost_demon unmarshallGhost( reader &th );
static void marshallResists(writer &, const mon_resist_def &);
static void unmarshallResists(reader &, mon_resist_def &);
static void marshallSpells(writer &, const monster_spells &);
static void unmarshallSpells(reader &, monster_spells &);
static void marshall_monster(writer &th, const monsters &m);
static void unmarshall_monster(reader &th, monsters &m);
template<typename T, typename T_iter, typename T_marshal>
static void marshall_iterator(writer &th, T_iter beg, T_iter end,
T_marshal marshal);
template<typename T>
static void unmarshall_vector(reader& th, std::vector<T>& vec,
T (*T_unmarshall)(reader&));
void marshallLong(std::vector<unsigned char>& buf, long data)
{
COMPILE_CHECK(sizeof(data)==4, c1);
buf.push_back((unsigned char) ((data & 0xFF000000) >> 24));
buf.push_back((unsigned char) ((data & 0x00FF0000) >> 16));
buf.push_back((unsigned char) ((data & 0x0000FF00) >> 8));
buf.push_back((unsigned char) ((data & 0x000000FF) ));
}
void marshallMap(tagHeader &th, const std::map<key,value>& data,
void (*key_marshall)(tagHeader&, const key&),
void (*value_marshall)(tagHeader&, const value&))
void marshallMap(writer &th, const std::map<key,value>& data,
void (*key_marshall)(writer&, const key&),
void (*value_marshall)(writer&, const value&))
void unmarshallMap(tagHeader& th, map& data,
key (*key_unmarshall) (tagHeader&),
value (*value_unmarshall)(tagHeader&) )
void unmarshallMap(reader& th, map& data,
key (*key_unmarshall) (reader&),
value (*value_unmarshall)(reader&) )
if (tagBuffer != NULL)
return;
tagBuffer = (char *)malloc(largest_tag);
}
void tag_construct(tagHeader &th, int tagID)
{
th.offset = 0;
th.tagID = tagID;
std::vector<unsigned char> buf;
writer th(&buf);
// swap out first few bytes
memcpy(swap, tagBuffer, tagHdrSize);
// save tag size
tagSize = th.offset;
// swap in the header
th.offset = 0;
marshallShort(th, th.tagID);
marshallLong(th, tagSize);
// write header
write2(saveFile, tagBuffer, th.offset);
// swap real data back in
memcpy(tagBuffer, swap, tagHdrSize);
// reset tag size
th.offset = tagSize;
writer tmp(outf);
marshallShort(tmp, tagID);
marshallLong(tmp, buf.size());
const int tagHdrSize = 6;
tagHeader hdr, th;
th.offset = 0;
// Read header info and data
short tag_id;
std::vector<unsigned char> buf;
{
reader tmp(fp);
tag_id = unmarshallShort(tmp);
if (tag_id < 0) return TAG_NO_TAG;
const long data_size = unmarshallLong(tmp);
if (data_size < 0) return TAG_NO_TAG;
// read tag header
if (read2(fp, tagBuffer, tagHdrSize) != tagHdrSize)
return 0;
// unmarshall tag type and length (not including header)
hdr.tagID = unmarshallShort(th);
hdr.offset = unmarshallLong(th);
// Fetch data in one go
buf.resize(data_size);
if (read2(fp, &buf[0], buf.size()) != (int)buf.size())
return TAG_NO_TAG;
}