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