summaryrefslogtreecommitdiff
path: root/src/saveload/oldloader.h
blob: 5cde06cc5871a529bbd53eb887a4e96fb2867d7f (plain)
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
/* $Id$ */

/** @file oldloader.h Declarations of strctures and function used in loader of old savegames */

#ifndef OLDLOADER_H
#define OLDLOADER_H

#include "saveload.h"

enum {
	BUFFER_SIZE = 4096,
	OLD_MAP_SIZE = 256 * 256,
};

struct LoadgameState {
	FILE *file;

	uint chunk_size;

	bool decoding;
	byte decode_char;

	uint buffer_count;
	uint buffer_cur;
	byte buffer[BUFFER_SIZE];

	uint total_read;
	bool failed;
};

/* OldChunk-Type */
enum OldChunkType {
	OC_SIMPLE    = 0,
	OC_NULL      = 1,
	OC_CHUNK     = 2,
	OC_ASSERT    = 3,
	/* 8 bits allocated (256 max) */

	OC_VAR_I8    = 1 << 8,
	OC_VAR_U8    = 2 << 8,
	OC_VAR_I16   = 3 << 8,
	OC_VAR_U16   = 4 << 8,
	OC_VAR_I32   = 5 << 8,
	OC_VAR_U32   = 6 << 8,
	OC_VAR_I64   = 7 << 8,
	/* 8 bits allocated (256 max) */

	OC_FILE_I8   = 1 << 16,
	OC_FILE_U8   = 2 << 16,
	OC_FILE_I16  = 3 << 16,
	OC_FILE_U16  = 4 << 16,
	OC_FILE_I32  = 5 << 16,
	OC_FILE_U32  = 6 << 16,
	/* 8 bits allocated (256 max) */

	OC_INT8      = OC_VAR_I8   | OC_FILE_I8,
	OC_UINT8     = OC_VAR_U8   | OC_FILE_U8,
	OC_INT16     = OC_VAR_I16  | OC_FILE_I16,
	OC_UINT16    = OC_VAR_U16  | OC_FILE_U16,
	OC_INT32     = OC_VAR_I32  | OC_FILE_I32,
	OC_UINT32    = OC_VAR_U32  | OC_FILE_U32,

	OC_TILE      = OC_VAR_U32  | OC_FILE_U16,

	/**
	 * Dereference the pointer once before writing to it,
	 * so we do not have to use big static arrays.
	 */
	OC_DEREFERENCE_POINTER = 1 << 31,

	OC_END       = 0 ///< End of the whole chunk, all 32 bits set to zero
};

DECLARE_ENUM_AS_BIT_SET(OldChunkType);

typedef bool OldChunkProc(LoadgameState *ls, int num);

struct OldChunks {
	OldChunkType type;   ///< Type of field
	uint32 amount;       ///< Amount of fields

	void *ptr;           ///< Pointer where to save the data (may only be set if offset is 0)
	uint offset;         ///< Offset from basepointer (may only be set if ptr is NULL)
	OldChunkProc *proc;  ///< Pointer to function that is called with OC_CHUNK
};

/* If it fails, check lines above.. */
assert_compile(sizeof(TileIndex) == 4);

extern uint _bump_assert_value;
byte ReadByte(LoadgameState *ls);
bool LoadChunk(LoadgameState *ls, void *base, const OldChunks *chunks);

bool LoadOldMain(LoadgameState *ls);

static inline uint16 ReadUint16(LoadgameState *ls)
{
	byte x = ReadByte(ls);
	return x | ReadByte(ls) << 8;
}

static inline uint32 ReadUint32(LoadgameState *ls)
{
	uint16 x = ReadUint16(ls);
	return x | ReadUint16(ls) << 16;
}

/* Help:
 *  - OCL_SVAR: load 'type' to offset 'offset' in a struct of type 'base', which must also
 *       be given via base in LoadChunk() as real pointer
 *  - OCL_VAR: load 'type' to a global var
 *  - OCL_END: every struct must end with this
 *  - OCL_NULL: read 'amount' of bytes and send them to /dev/null or something
 *  - OCL_CHUNK: load an other proc to load a part of the savegame, 'amount' times
 *  - OCL_ASSERT: to check if we are really at the place we expect to be.. because old savegames are too binary to be sure ;)
 */
#define OCL_SVAR(type, base, offset)         { type,          1, NULL,    (uint)cpp_offsetof(base, offset), NULL }
#define OCL_VAR(type, amount, pointer)       { type,     amount, pointer, 0,                      NULL }
#define OCL_END()                                   { OC_END,        0, NULL,    0,                      NULL }
#define OCL_NULL(amount)                            { OC_NULL,  amount, NULL,    0,                      NULL }
#define OCL_CHUNK(amount, proc)                     { OC_CHUNK, amount, NULL,    0,                      proc }
#define OCL_ASSERT(size)                            { OC_ASSERT,     1, NULL, size,                      NULL }

#endif /* OLDLOADER_H */