1 /*
2  * Copyright (c) 1997 - 2001 Hansj�rg Malthaner
3  *
4  * This file is part of the Simutrans project under the artistic licence.
5  * (see licence.txt)
6  */
7 
8 #ifndef loadsave_h
9 #define loadsave_h
10 
11 #include <stdio.h>
12 #include <string>
13 
14 #include "../simtypes.h"
15 
16 class plainstring;
17 struct file_descriptors_t;
18 
19 /**
20  * loadsave_t:
21  *
22  * This class replaces the FILE when loading and saving games.
23  * <p>
24  * Hj. Malthaner, 16-Feb-2002, added zlib compression support
25  * </p>
26  * Can now read and write 3 formats: text, binary and zipped
27  * Input format is automatically detected.
28  * Output format has a default, changeable with set_savemode, but can be
29  * overwritten in wr_open.
30  *
31  * @author V. Meyer, Hj. Malthaner
32  */
33 
34 
35 class loadsave_t {
36 public:
37 	enum mode_t {
38 		binary=0,
39 		text=1,
40 		xml=2,
41 		zipped=4,
42 		xml_zipped=6,
43 		bzip2=8,
44 		xml_bzip2=10
45 	};
46 
47 	enum file_error_t {
48 		FILE_ERROR_OK=0,
49 		FILE_ERROR_NOT_EXISTING,
50 		FILE_ERROR_BZ_CORRUPT,
51 		FILE_ERROR_GZ_CORRUPT,
52 		FILE_ERROR_NO_VERSION,
53 		FILE_ERROR_FUTURE_VERSION
54 	};
55 
56 private:
57 	file_error_t last_error;
58 	int mode; ///< See mode_t
59 	bool saving;
60 	bool buffered;
61 	unsigned curr_buff;
62 	unsigned buf_pos[2];
63 	unsigned buf_len[2];
64 	char* ls_buf[2];
65 	uint32 version; ///< savegame version
66 	int ident;		// only for XML formatting
67 	char pak_extension[64];	// name of the pak folder during savetime
68 
69 	std::string filename;	// the current name ...
70 
71 	file_descriptors_t *fd;
72 
73 	// Hajo: putc got a name clash on my system
74 	inline void lsputc(int c);
75 
76 	// Hajo: getc got a name clash on my system
77 	inline int lsgetc();
78 	size_t write(const void * buf, size_t len);
79 	size_t read(void *buf, size_t len);
80 
81 	void rdwr_xml_number(sint64 &s, const char *typ);
82 
83 	loadsave_t(const loadsave_t&);
84 	loadsave_t& operator=(const loadsave_t&);
85 
86 	friend void *save_thread( void *ptr );
87 	friend void *load_thread( void *ptr );
88 
89 	/**
90 	 * Reads into buffer number @p buf_num.
91 	 * @returns number of bytes read or -1 in case of error
92 	 */
93 	int fill_buffer(int buf_num);
94 
95 	void flush_buffer(int buf_num);
96 
97 public:
98 	static mode_t save_mode;     ///< default to use for saving
99 	static mode_t autosave_mode; ///< default to use for autosaves and network mode client temp saves
100 
101 	/**
102 	 * Parses the version information from @p version_text to a version number.
103 	 * @param[out] pak Pointer to a sufficiently large buffer (>= 64 chars); when the function returns,
104 	 *                 @p pak contains the pakset extension string. May be NULL.
105 	 * @retval 0   if an error occurred or the save cannot be loaded
106 	 * @retval !=0 the save version; in this case we can read the save file.
107 	 */
108 	static uint32 int_version(const char *version_text, char *pak);
109 
110 	loadsave_t();
111 	~loadsave_t();
112 
113 	bool rd_open(const char *filename);
114 	bool wr_open(const char *filename, mode_t mode, const char *pak_extension, const char *savegame_version );
115 	const char *close();
116 
get_last_error()117 	file_error_t get_last_error() { return last_error; }
118 
set_savemode(mode_t mode)119 	static void set_savemode(mode_t mode) { save_mode = mode; }
set_autosavemode(mode_t mode)120 	static void set_autosavemode(mode_t mode) { autosave_mode = mode; }
121 
122 	/**
123 	 * Checks end-of-file
124 	 * @author Hj. Malthaner
125 	 */
126 	bool is_eof();
127 
128 	void set_buffered(bool enable);
get_buf_pos(int buf_num)129 	unsigned get_buf_pos(int buf_num) const { return buf_pos[buf_num]; }
is_loading()130 	bool is_loading() const { return !saving; }
is_saving()131 	bool is_saving() const { return saving; }
is_zipped()132 	bool is_zipped() const { return mode&zipped; }
is_bzip2()133 	bool is_bzip2() const { return mode&bzip2; }
is_xml()134 	bool is_xml() const { return mode&xml; }
get_pak_extension()135 	const char *get_pak_extension() const { return pak_extension; }
136 
get_version_int()137 	uint32 get_version_int() const { return version; }
is_version_atleast(uint32 major,uint32 save_minor)138 	inline bool is_version_atleast(uint32 major, uint32 save_minor) const { return !is_version_less(major, save_minor); }
is_version_less(uint32 major,uint32 save_minor)139 	inline bool is_version_less(uint32 major, uint32 save_minor)    const { return version <  major * 1000U + save_minor; }
is_version_equal(uint32 major,uint32 save_minor)140 	inline bool is_version_equal(uint32 major, uint32 save_minor)   const { return version == major * 1000U + save_minor; }
141 
142 	void rdwr_byte(sint8 &c);
143 	void rdwr_byte(uint8 &c);
144 	void rdwr_short(sint16 &i);
145 	void rdwr_short(uint16 &i);
146 	void rdwr_long(sint32 &i);
147 	void rdwr_long(uint32 &i);
148 	void rdwr_longlong(sint64 &i);
149 	void rdwr_bool(bool &i);
150 	void rdwr_double(double &dbl);
151 
152 	void wr_obj_id(short id);
153 	short rd_obj_id();
154 	void wr_obj_id(const char *id_text);
155 	void rd_obj_id(char *id_buf, int size);
156 
157 	// s is a malloc-ed string (will be freed and newly allocated on load time!)
158 	void rdwr_str(const char *&s);
159 
160 	// s is a buf of size given
161 	void rdwr_str(char* s, size_t size);
162 
163 	/**
164 	 * Read/Write plainstring.
165 	 * @param str the string to be read/written
166 	 * @post str should not be NULL after reading.
167 	 */
168 	void rdwr_str(plainstring& str);
169 
170 	// only meaningful for XML
171 	void start_tag( const char *tag );
172 	void end_tag( const char *tag );
173 
174 	// use this for enum types
175 	template <class X>
rdwr_enum(X & x)176 	void rdwr_enum(X &x)
177 	{
178 		sint32 int_x;
179 
180 		if(is_saving()) {
181 			int_x = (sint32)x;
182 		}
183 		rdwr_long(int_x);
184 		if(is_loading()) {
185 			x = (X)int_x;
186 		}
187 	}
188 };
189 
190 
191 
192 // this produced semicautomatic hierarchies
193 class xml_tag_t {
194 private:
195 	loadsave_t *file;
196 	const char *tag;
197 public:
xml_tag_t(loadsave_t * f,const char * t)198 	xml_tag_t( loadsave_t *f, const char *t ) : file(f), tag(t) { file->start_tag(tag); }
~xml_tag_t()199 	~xml_tag_t() { file->end_tag(tag); }
200 };
201 
202 
203 
204 #endif
205