1 //------------------------------------------------------------------------
2 //  WAD Reading / Writing
3 //------------------------------------------------------------------------
4 //
5 //  Eureka DOOM Editor
6 //
7 //  Copyright (C) 2001-2016 Andrew Apted
8 //  Copyright (C) 1997-2003 André Majorel et al
9 //
10 //  This program is free software; you can redistribute it and/or
11 //  modify it under the terms of the GNU General Public License
12 //  as published by the Free Software Foundation; either version 2
13 //  of the License, or (at your option) any later version.
14 //
15 //  This program is distributed in the hope that it will be useful,
16 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
17 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 //  GNU General Public License for more details.
19 //
20 //------------------------------------------------------------------------
21 //
22 //  Based on Yadex which incorporated code from DEU 5.21 that was put
23 //  in the public domain in 1994 by Raphaël Quinet and Brendon Wyber.
24 //
25 //------------------------------------------------------------------------
26 
27 #ifndef __EUREKA_W_WAD_H__
28 #define __EUREKA_W_WAD_H__
29 
30 class Wad_file;
31 
32 
33 class Lump_c
34 {
35 friend class Wad_file;
36 
37 private:
38 	Wad_file *parent;
39 
40 	const char *name;
41 
42 	int l_start;
43 	int l_length;
44 
45 	// constructor is private
46 	Lump_c(Wad_file *_par, const char *_nam, int _start, int _len);
47 	Lump_c(Wad_file *_par, const struct raw_wad_entry_s *entry);
48 
49 	void MakeEntry(struct raw_wad_entry_s *entry);
50 
51 public:
52 	~Lump_c();
53 
Name()54 	const char *Name() const { return name; }
Length()55 	int Length() const { return l_length; }
56 
57 	// do not call this directly, use Wad_file::RenameLump()
58 	void Rename(const char *new_name);
59 
60 	// attempt to seek to a position within the lump (default is
61 	// the beginning).  Returns true if OK, false on error.
62 	bool Seek(int offset = 0);
63 
64 	// read some data from the lump, returning true if OK.
65 	bool Read(void *data, int len);
66 
67 	// read a line of text, returns true if OK, false on EOF
68 	bool GetLine(char *buffer, size_t buf_size);
69 
70 	// write some data to the lump.  Only the lump which had just
71 	// been created with Wad_file::AddLump() or RecreateLump() can be
72 	// written to.
73 	bool Write(const void *data, int len);
74 
75 	// write some text to the lump
76 	void Printf(const char *msg, ...);
77 
78 	// mark the lump as finished (after writing data to it).
79 	bool Finish();
80 
81 	// predicate for std::sort()
82 	struct offset_CMP_pred
83 	{
operatoroffset_CMP_pred84 		inline bool operator() (const Lump_c * A, const Lump_c * B) const
85 		{
86 			return A->l_start < B->l_start;
87 		}
88 	};
89 
90 private:
91 	// deliberately don't implement these
92 	Lump_c(const Lump_c& other);
93 	Lump_c& operator= (const Lump_c& other);
94 };
95 
96 
97 //------------------------------------------------------------------------
98 
99 
100 class Wad_file
101 {
102 friend class Lump_c;
103 friend void W_LoadFlats();
104 friend void W_LoadTextures_TX_START(Wad_file *wf);
105 
106 private:
107 	const char *filename;
108 
109 	char mode;  // mode value passed to ::Open()
110 
111 	FILE * fp;
112 
113 	char kind;  // 'P' for PWAD, 'I' for IWAD
114 
115 	// zero means "currently unknown", which only occurs after a
116 	// call to BeginWrite() and before any call to AddLump() or
117 	// the finalizing EndWrite().
118 	int total_size;
119 
120 	std::vector<Lump_c *> directory;
121 
122 	int dir_start;
123 	int dir_count;
124 	u32_t dir_crc;
125 
126 	// these are lump indices (into 'directory' vector)
127 	std::vector<short> levels;
128 	std::vector<short> patches;
129 	std::vector<short> sprites;
130 	std::vector<short> flats;
131 	std::vector<short> tx_tex;
132 
133 	bool begun_write;
134 	int  begun_max_size;
135 
136 	// when >= 0, the next added lump is placed _before_ this
137 	int insert_point;
138 
139 	// constructor is private
140 	Wad_file(const char *_name, char _mode, FILE * _fp);
141 
142 public:
143 	~Wad_file();
144 
145 	// open a wad file.
146 	//
147 	// mode is similar to the fopen() function:
148 	//   'r' opens the wad for reading ONLY
149 	//   'a' opens the wad for appending (read and write)
150 	//   'w' opens the wad for writing (i.e. create it)
151 	//
152 	// Note: if 'a' is used and the file is read-only, it will be
153 	//       silently opened in 'r' mode instead.
154 	//
155 	static Wad_file * Open(const char *filename, char mode = 'a');
156 
157 	// check the given wad file exists and is a WAD file
158 	static bool Validate(const char *filename);
159 
PathName()160 	const char *PathName() const { return filename; }
IsReadOnly()161 	bool IsReadOnly() const { return mode == 'r'; }
IsIWAD()162 	bool IsIWAD() const { return kind == 'I'; }
163 
TotalSize()164 	int TotalSize() const { return total_size; }
165 
NumLumps()166 	short NumLumps() const { return (short)directory.size(); }
167 	Lump_c * GetLump(short index);
168 	Lump_c * FindLump(const char *name);
169 	short FindLumpNum(const char *name);
170 
171 	Lump_c * FindLumpInNamespace(const char *name, char group);
172 
LevelCount()173 	short LevelCount() const { return (short)levels.size(); }
174 	short LevelHeader(short lev_num);
175 	short LevelLastLump(short lev_num);
176 
177 	// these return a level number (0 .. count-1)
178 	short LevelFind(const char *name);
179 	short LevelFindByNumber(int number);
180 	short LevelFindFirst();
181 
182 	// returns a lump index, -1 if not found
183 	short LevelLookupLump(short lev_num, const char *name);
184 
185 	map_format_e LevelFormat(short lev_num);
186 
187 	void  SortLevels();
188 
189 	// check whether another program has modified this WAD, and return
190 	// either true or false.  We test for change in file size, change
191 	// in directory size or location, and directory contents (CRC).
192 	// [ NOT USED YET.... ]
193 	bool WasExternallyModified();
194 
195 	// backup the current wad into the given filename.
196 	// returns true if successful, false on error.
197 	bool Backup(const char *new_filename);
198 
199 	// all changes to the wad must occur between calls to BeginWrite()
200 	// and EndWrite() methods.  the on-disk wad directory may be trashed
201 	// during this period, it will be re-written by EndWrite().
202 	void BeginWrite();
203 	void EndWrite();
204 
205 	// change name of a lump (can be a level marker too)
206 	void RenameLump(short index, const char *new_name);
207 
208 	// remove the given lump(s)
209 	// this will change index numbers on existing lumps
210 	// (previous results of FindLumpNum or LevelHeader are invalidated).
211 	void RemoveLumps(short index, short count = 1);
212 
213 	// this removes the level marker PLUS all associated level lumps
214 	// which follow it.
215 	void RemoveLevel(short lev_num);
216 
217 	// removes any GL-Nodes lumps that are associated with the given
218 	// level.
219 	void RemoveGLNodes(short lev_num);
220 
221 	// removes any ZNODES lump from a UDMF level.
222 	void RemoveZNodes(short lev_num);
223 
224 	// insert a new lump.
225 	// The second form is for a level marker.
226 	// The 'max_size' parameter (if >= 0) specifies the most data
227 	// you will write into the lump -- writing more will corrupt
228 	// something else in the WAD.
229 	Lump_c * AddLump (const char *name, int max_size = -1);
230 	Lump_c * AddLevel(const char *name, int max_size = -1, short *lev_num = NULL);
231 
232 	// setup lump to write new data to it.
233 	// the old contents are lost.
234 	void RecreateLump(Lump_c *lump, int max_size = -1);
235 
236 	// set the insertion point -- the next lump will be added _before_
237 	// this index, and it will be incremented so that a sequence of
238 	// AddLump() calls produces lumps in the same order.
239 	//
240 	// passing a negative value or invalid index will reset the
241 	// insertion point -- future lumps get added at the END.
242 	// RemoveLumps(), RemoveLevel() and EndWrite() also reset it.
243 	void InsertPoint(short index = -1);
244 
245 private:
246 	static Wad_file * Create(const char *filename, char mode);
247 
248 	// read the existing directory.
249 	bool ReadDirectory();
250 
251 	void DetectLevels();
252 	void ProcessNamespaces();
253 
254 	// look at all the lumps and determine the lowest offset from
255 	// start of file where we can write new data.  The directory itself
256 	// is ignored for this.
257 	int HighWaterMark();
258 
259 	// look at all lumps in directory and determine the lowest offset
260 	// where a lump of the given length will fit.  Returns same as
261 	// HighWaterMark() when no largest gaps exist.  The directory itself
262 	// is ignored since it will be re-written at EndWrite().
263 	int FindFreeSpace(int length);
264 
265 	// find a place (possibly at end of WAD) where we can write some
266 	// data of max_size (-1 means unlimited), and seek to that spot
267 	// (possibly writing some padding zeros -- the difference should
268 	// be no more than a few bytes).  Returns new position.
269 	int PositionForWrite(int max_size = -1);
270 
271 	bool FinishLump(int final_size);
272 	int  WritePadding(int count);
273 
274 	// write the new directory, updating the dir_xxx variables
275 	// (including the CRC).
276 	void WriteDirectory();
277 
278 	void FixGroup(std::vector<short>& group, short index, short num_added, short num_removed);
279 
280 private:
281 	// deliberately don't implement these
282 	Wad_file(const Wad_file& other);
283 	Wad_file& operator= (const Wad_file& other);
284 
285 private:
286 	// predicate for sorting the levels[] vector
287 	struct level_name_CMP_pred
288 	{
289 	private:
290 		Wad_file *wad;
291 
292 	public:
level_name_CMP_predlevel_name_CMP_pred293 		level_name_CMP_pred(Wad_file * _w) : wad(_w)
294 		{ }
295 
operatorlevel_name_CMP_pred296 		inline bool operator() (const short A, const short B) const
297 		{
298 			const Lump_c *L1 = wad->directory[A];
299 			const Lump_c *L2 = wad->directory[B];
300 
301 			return (strcmp(L1->Name(), L2->Name()) < 0);
302 		}
303 	};
304 };
305 
306 
307 // the IWAD, never NULL, always at master_dir.front()
308 extern Wad_file * game_wad;
309 
310 // the current PWAD, or NULL for none.
311 // when present it is also at master_dir.back()
312 extern Wad_file * edit_wad;
313 
314 extern std::vector<Wad_file *> master_dir;
315 
316 
317 // find a lump in any loaded wad (later ones tried first),
318 // returning NULL if not found.
319 Lump_c * W_FindLump(const char *name);
320 
321 // find a lump that only exists in a certain namespace (sprite,
322 // or patch) of a loaded wad (later ones tried first).
323 Lump_c * W_FindSpriteLump(const char *name);
324 Lump_c * W_FindPatchLump(const char *name);
325 
326 // load the lump into memory, returning the size
327 int  W_LoadLumpData(Lump_c *lump, byte ** buf_ptr);
328 void W_FreeLumpData(byte ** buf_ptr);
329 
330 
331 int W_FilenameAbsCompare(const char *A, const char *B);
332 
333 void W_StoreString(char *buf, const char *str, size_t buflen);
334 
335 
336 void MasterDir_Add   (Wad_file *wad);
337 void MasterDir_Remove(Wad_file *wad);
338 
339 bool MasterDir_HaveFilename(const char *chk_path);
340 void MasterDir_CloseAll();
341 
342 
343 extern bool udmf_testing;
344 
345 
346 #endif  /* __EUREKA_W_WAD_H__ */
347 
348 //--- editor settings ---
349 // vi:ts=4:sw=4:noexpandtab
350