aboutsummaryrefslogtreecommitdiff
path: root/engines/agi/wagparser.h
blob: 81cfecef1bcd7831880fcdfa41224cb5b8b85ce3 (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
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
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
/* ScummVM - Graphic Adventure Engine
 *
 * ScummVM is the legal property of its developers, whose names
 * are too numerous to list here. Please refer to the COPYRIGHT
 * file distributed with this source distribution.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 */

namespace Agi {

/**
 * WagProperty represents a single property from WinAGI's *.wag file.
 * A property consists of a header and of data.
 * The header consists of the following:
 * - Property code (Integer/Enumeration, 1 byte)
 * - Property type (Integer/Enumeration, 1 byte)
 * - Property number (Integer, 1 byte)
 * - Property size (Little endian integer, 2 bytes)
 * And then there's the data with as many bytes as defined in the header's property size variable.
 */
class WagProperty {
// Constants, enumerations etc
public:
	/**
	 * Property codes taken from WinAGI 1.1.21's source code file WinAGI/AGIObjects.bas.
	 */
	enum WagPropertyCode {
		PC_GAMEDESC = 129, ///< Game description (WinAGI 1.1.21 limits these to 4096 bytes)
		PC_GAMEAUTHOR,     ///< Game author (WinAGI 1.1.21 limits these to 256 bytes)
		PC_GAMEID,         ///< Game ID
		PC_INTVERSION,     ///< Interpreter version (WinAGI 1.1.21 defaults to version 2.917)
		PC_GAMELAST,       ///< Last edit date
		PC_GAMEVERSION,    ///< Game version (WinAGI 1.1.21 limits these to 256 bytes)
		PC_GAMEABOUT,      ///< About game (WinAGI 1.1.21 limits these to 4096 bytes)
		PC_GAMEEXEC,       ///< Game executable
		PC_RESDIR,         ///< Resource directory name
		PC_DEFSYNTAX,      ///< Default syntax
		PC_INVOBJDESC = 144,
		PC_VOCABWORDDESC = 160,
		PC_PALETTE = 172,
		PC_USERESNAMES = 180,
		PC_LOGIC = 192,
		PC_PICTURE = 208,
		PC_SOUND = 224,
		PC_VIEW = 240,
		PC_UNDEFINED = 0x100 ///< An undefined property code (Added for ScummVM).
	};

	/**
	 * Property types taken from WinAGI 1.1.21's source code file WinAGI/AGIObjects.bas.
	 * At the moment these aren't really at all needed by ScummVM. Just here if anyone decides to use them.
	 */
	enum WagPropertyType {
		PT_ID,
		PT_DESC,
		PT_SYNTAX,
		PT_CRC32,
		PT_KEY,
		PT_INST0,
		PT_INST1,
		PT_INST2,
		PT_MUTE0,
		PT_MUTE1,
		PT_MUTE2,
		PT_MUTE3,
		PT_TPQN,
		PT_ROOM,
		PT_VIS0,
		PT_VIS1,
		PT_VIS2,
		PT_VIS3,
		PT_ALL = 0xff,
		PT_UNDEFINED = 0x100 ///< An undefined property type (Added for ScummVM).
	};

// Constructors, destructors, operators etc
public:
	/**
	 * Creates an empty WagProperty object.
	 * No property header or property data in it.
	 */
	WagProperty();

	/**
	 * Destructor. Releases allocated memory if any etc. The usual.
	 */
	~WagProperty();

	/**
	 * Copy constructor. Deep copies the variables.
	 */
	WagProperty(const WagProperty &other);

	/**
	 * Assignment operator. Deep copies the variables.
	 */
	WagProperty &operator=(const WagProperty &other);

// Non-public helper methods
protected:
	/**
	 * Sets the default values for member variables.
	 */
	void setDefaults();

	/**
	 * Delete's the property's data from memory if we have it, otherwise does nothing.
	 */
	void deleteData();

	/**
	 * Deep copies the parameter object to this object.
	 * @param other The object to be deep copied to this object.
	 */
	void deepCopy(const WagProperty &other);

// Public methods that have side-effects
public:
	/**
	 * Read in a property (Header and data).
	 * @return True if reading was a success, false otherwise.
	 */
	bool read(Common::SeekableReadStream &stream);

	/**
	 * Clears the property.
	 * After this the property is empty. No header or data.
	 */
	void clear();

// Public access functions
public:
	/**
	 * Was the property read ok from the source stream?
	 */
	bool readOk() const { return _readOk; }

	/**
	 * Return the property's code.
	 * @return The property's code if readOk(), PC_UNDEFINED otherwise.
	 */
	enum WagPropertyCode getCode() const { return _propCode; }

	/**
	 * Return the property's type.
	 * @return The property's type if readOk(), PT_UNDEFINED otherwise.
	 */
	enum WagPropertyType getType() const { return _propType; }

	/**
	 * Return the property's number.
	 * @return The property's number if readOk(), 0 otherwise.
	 */
	byte getNumber() const { return _propNum; }

	/**
	 * Return the property's data's length.
	 * @return The property's data's length if readOk(), 0 otherwise.
	 */
	uint16 getSize() const { return _propSize; }

	/**
	 * Return property's data. Constant access version.
	 * Can be used as a C-style string (i.e. this is guaranteed to have a trailing zero).
	 * @return The property's data if readOk(), NULL otherwise.
	 */
	const char *getData() const { return _propData; }

// Member variables
protected:
	bool _readOk;                   ///< Was the property read ok from the source stream?
	enum WagPropertyCode _propCode; ///< Property code (Part of the property's header)
	enum WagPropertyType _propType; ///< Property type (Part of the property's header)
	byte _propNum;                  ///< Property number (Part of the property's header)
	uint16 _propSize;               ///< Property's size (Part of the property's header)
	char *_propData;                ///< The property's data (Plus a trailing zero for C-style string access)
};


/**
 * Class for parsing *.wag files created by WinAGI.
 * Using this class you can get information about fanmade AGI games if they have provided a *.wag file with them.
 */
class WagFileParser {
// Constants, type definitions, enumerations etc.
public:
	enum {
		WINAGI_VERSION_LENGTH = 16 ///< WinAGI's version string's length (Always 16)
	};
	typedef Common::Array<WagProperty> PropertyList; ///< A type definition for an array of *.wag file properties

public:
	/**
	 * Constructor. Creates a WagFileParser object in a default state.
	 */
	WagFileParser();

	/**
	 * Destructor.
	 */
	~WagFileParser();

	/**
	 * Loads a *.wag file and parses it.
	 * @note After this you can access the loaded properties using getProperty() and getProperties() etc.
	 * @param filename Name of the file to be parsed.
	 * @return True if parsed successfully, false otherwise.
	 */
	bool parse(const Common::FSNode &node);

	/**
	 * Get list of the loaded properties.
	 * @note Use only after a call to parse() first.
	 * @return The list of loaded properties.
	 */
	const PropertyList &getProperties() const { return _propList; }

	/**
	 * Get property with the given property code.
	 * @note Use only after a call to parse() first.
	 * @return Pointer to the property if its found in memory, NULL otherwise.
	 *
	 * TODO/FIXME: Handle cases where several properties with the given property code are found.
	 *             At the moment we don't need this functionality because the properties we use
	 *             for fallback detection probably don't have multiples in the WAG-file.
	 * TODO: Make this faster than linear time if desired/needed.
	 */
	const WagProperty *getProperty(const WagProperty::WagPropertyCode code) const;

	/**
	 * Tests if the given property contains a valid AGI interpreter version string.
	 * A valid AGI interpreter version string is of the form "X.Y" or "X,Y" where
	 * X is a single decimal digit and Y is a string of decimal digits (At least one digit).
	 * @param version The property to be tested.
	 * @return True if the given property contains a valid AGI interpreter version string, false otherwise.
	 */
	bool checkAgiVersionProperty(const WagProperty &version) const;

	/**
	 * Convert property's data to an AGI interpreter version number.
	 * @param version The property to be converted (Property code should be PC_INTVERSION).
	 * @return AGI interpreter version number if successful, 0 otherwise.
	 */
	uint16 convertToAgiVersionNumber(const WagProperty &version);

	/**
	 * Was the file parsed successfully?
	 * @return True if file was parsed successfully, false otherwise.
	 */
	bool parsedOk() const { return _parsedOk; }

protected:
	/**
	 * Checks if stream has a valid WinAGI version string in its end.
	 * @param stream The stream to be checked.
	 * @return True if reading was successful and stream contains a valid WinAGI version string, false otherwise.
	 */
	bool checkWagVersion(Common::SeekableReadStream &stream);

	/**
	 * Checks if we're at or past the end of the properties stored in the stream.
	 * @param stream The stream whose seeking position is to be checked.
	 * @return True if stream's seeking position is at or past the end of the properties, false otherwise.
	 */
	bool endOfProperties(const Common::SeekableReadStream &stream) const;

// Member variables
protected:
	PropertyList _propList; ///< List of loaded properties from the file.
	bool         _parsedOk; ///< Did the parsing of the file go ok?
};

} // End of namespace Agi