1 /* ScummVM - Graphic Adventure Engine 2 * 3 * ScummVM is the legal property of its developers, whose names 4 * are too numerous to list here. Please refer to the COPYRIGHT 5 * file distributed with this source distribution. 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2 10 * of the License, or (at your option) any later version. 11 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 * 21 */ 22 23 #ifndef XEEN_FILES_H 24 #define XEEN_FILES_H 25 26 #include "common/scummsys.h" 27 #include "common/array.h" 28 #include "common/file.h" 29 #include "common/memstream.h" 30 #include "common/savefile.h" 31 #include "common/serializer.h" 32 #include "common/str-array.h" 33 #include "graphics/surface.h" 34 35 namespace Xeen { 36 37 class XeenEngine; 38 class CCArchive; 39 class BaseCCArchive; 40 class File; 41 class SaveArchive; 42 class Party; 43 class OutFile; 44 class SavesManager; 45 46 #define SYNC_AS(SUFFIX,STREAM,TYPE,SIZE) \ 47 template<typename T> \ 48 void syncAs ## SUFFIX(T &val, Version minVersion = 0, Version maxVersion = kLastVersion) { \ 49 if (_version < minVersion || _version > maxVersion) \ 50 return; \ 51 if (_loadStream) \ 52 val = static_cast<TYPE>(_loadStream->read ## STREAM()); \ 53 else { \ 54 TYPE tmp = (TYPE)val; \ 55 _saveStream->write ## STREAM(tmp); \ 56 } \ 57 _bytesSynced += SIZE; \ 58 } 59 60 /** 61 * Details of a single entry in a CC file index 62 */ 63 struct CCEntry { 64 uint16 _id; 65 int _offset; 66 uint16 _size; 67 int _writeOffset; 68 CCEntryCCEntry69 CCEntry() : _id(0), _offset(0), _size(0), _writeOffset(0) {} CCEntryCCEntry70 CCEntry(uint16 id, uint32 offset, uint32 size) 71 : _id(id), _offset(offset), _size(size) { 72 } 73 }; 74 75 /* 76 * Main resource manager 77 */ 78 class FileManager { 79 public: 80 int _ccNum; 81 public: 82 /** 83 * Constructor 84 */ 85 FileManager(XeenEngine *vm); 86 87 /** 88 * Destructor 89 */ 90 ~FileManager(); 91 92 /** 93 * Sets up the CC files 94 * @returns Returns true if the setup was successful 95 */ 96 bool setup(); 97 98 /** 99 * Set which game side files to use 100 * @param ccMode 0=Clouds, 1=Dark Side 101 */ 102 void setGameCc(int ccMode); 103 104 /** 105 * Loads a save archive from a stream 106 */ 107 void load(Common::SeekableReadStream &stream); 108 109 /** 110 * Saves a save archive to a savegame 111 */ 112 void save(Common::WriteStream &s); 113 }; 114 115 /** 116 * Derived file class 117 */ 118 class File : public Common::File { 119 friend class FileManager; 120 friend class OutFile; 121 friend class SavesManager; 122 private: 123 static CCArchive *_xeenCc, *_darkCc, *_introCc; 124 static SaveArchive *_xeenSave, *_darkSave; 125 static BaseCCArchive *_currentArchive; 126 static SaveArchive *_currentSave; 127 public: 128 /** 129 * Sets which archive is used by default 130 */ 131 static void setCurrentArchive(int ccMode); 132 133 /** 134 * Synchronizes a boolean array as a bitfield set 135 */ 136 static void syncBitFlags(Common::Serializer &s, bool *startP, bool *endP); 137 public: File()138 File() : Common::File() {} 139 File(const Common::String &filename); 140 File(const Common::String &filename, int ccMode); 141 File(const Common::String &filename, Common::Archive &archive); ~File()142 ~File() override {} 143 144 /** 145 * Opens the given file, throwing an error if it can't be opened 146 */ 147 bool open(const Common::Path &filename) override; 148 149 /** 150 * Opens the given file, throwing an error if it can't be opened 151 */ 152 bool open(const Common::Path &filename, Common::Archive &archive) override; 153 154 /** 155 * Opens the given file, throwing an error if it can't be opened 156 */ 157 virtual bool open(const Common::String &filename, int ccMode); 158 159 /** 160 * Opens the given file 161 */ open(const Common::FSNode & node)162 bool open(const Common::FSNode &node) override { 163 return Common::File::open(node); 164 } 165 166 /** 167 * Opens the given file 168 */ open(SeekableReadStream * stream,const Common::String & name)169 bool open(SeekableReadStream *stream, const Common::String &name) override { 170 return Common::File::open(stream, name); 171 } 172 173 /** 174 * Reads in a null terminated string 175 */ 176 Common::String readString(); 177 178 /** 179 * Checks if a given file exists 180 * 181 * @param filename the file to check for 182 * @return true if the file exists, false otherwise 183 */ 184 static bool exists(const Common::String &filename); 185 186 /** 187 * Checks if a given file exists 188 * 189 * @param filename the file to check for 190 * @param ccMode Archive to use 191 * @return true if the file exists, false otherwise 192 */ 193 static bool exists(const Common::String &filename, int ccMode); 194 195 /** 196 * Checks if a given file exists 197 * 198 * @param filename the file to check for 199 * @param archive Archive to use 200 * @return true if the file exists, false otherwise 201 */ 202 static bool exists(const Common::String &filename, Common::Archive &archive); 203 }; 204 205 /** 206 * SubWriteStream provides a way of compartmentalizing writing to a subsection of 207 * a file. This is primarily useful for the pos() function which can, for example, 208 * be used in asserts to ensure writing is being done at the correct offset within 209 * the bounds of the structure being written. 210 */ 211 class SubWriteStream : virtual public Common::WriteStream { 212 protected: 213 Common::WriteStream *_parentStream; 214 uint32 _begin; 215 public: SubWriteStream(Common::WriteStream * parentStream)216 SubWriteStream(Common::WriteStream *parentStream) : 217 _parentStream(parentStream), _begin(parentStream->pos()) { 218 } 219 write(const void * dataPtr,uint32 dataSize)220 uint32 write(const void *dataPtr, uint32 dataSize) override { 221 return _parentStream->write(dataPtr, dataSize); 222 } flush()223 bool flush() override { return _parentStream->flush(); } finalize()224 void finalize() override {} pos()225 int64 pos() const override { return _parentStream->pos() - _begin; } 226 }; 227 228 class StringArray : public Common::StringArray { 229 public: StringArray()230 StringArray() {} StringArray(const Common::String & name)231 StringArray(const Common::String &name) { load(name); } 232 233 /** 234 * Loads a string array from the specified file 235 */ 236 void load(const Common::String &name); 237 238 /** 239 * Loads a string array from the specified file 240 */ 241 void load(const Common::String &name, int ccMode); 242 }; 243 244 class XeenSerializer : public Common::Serializer { 245 private: 246 Common::SeekableReadStream *_in; 247 int _filesize; 248 public: XeenSerializer(Common::SeekableReadStream * in,Common::WriteStream * out)249 XeenSerializer(Common::SeekableReadStream *in, Common::WriteStream *out) : 250 Common::Serializer(in, out), _in(in), _filesize(-1) {} 251 252 SYNC_AS(Sint8, Byte, int8, 1) 253 finished()254 bool finished() { 255 if (_in && _filesize == -1) 256 _filesize = _in->size(); 257 return _in != nullptr && _in->pos() >= _filesize; 258 } 259 }; 260 261 /** 262 * Base Xeen CC file implementation 263 */ 264 class BaseCCArchive : public Common::Archive { 265 protected: 266 Common::Array<CCEntry> _index; 267 268 /** 269 * Load the index of a given CC file 270 */ 271 void loadIndex(Common::SeekableReadStream &stream); 272 273 /** 274 * Saves out the contents of the index. Used when creating savegames 275 */ 276 void saveIndex(Common::WriteStream &stream); 277 278 /** 279 * Given a resource name, returns whether an entry exists, and returns 280 * the header index data for that entry 281 */ 282 virtual bool getHeaderEntry(const Common::String &resourceName, CCEntry &ccEntry) const; 283 284 /** 285 * Given a resource Id, returns whether an entry exists, and returns 286 * the header index data for that entry 287 */ 288 virtual bool getHeaderEntry(uint16 id, CCEntry &ccEntry) const; 289 public: 290 /** 291 * Hash a given filename to produce the Id that represents it 292 */ 293 static uint16 convertNameToId(const Common::String &resourceName); 294 public: BaseCCArchive()295 BaseCCArchive() {} 296 297 // Archive implementation 298 bool hasFile(const Common::Path &path) const override; 299 int listMembers(Common::ArchiveMemberList &list) const override; 300 const Common::ArchiveMemberPtr getMember(const Common::Path &path) const override; 301 }; 302 303 /** 304 * Xeen CC file implementation 305 */ 306 class CCArchive : public BaseCCArchive { 307 private: 308 Common::String _filename; 309 Common::String _prefix; 310 bool _encoded; 311 protected: 312 bool getHeaderEntry(const Common::String &resourceName, CCEntry &ccEntry) const override; 313 public: 314 CCArchive(const Common::String &filename, bool encoded); 315 CCArchive(const Common::String &filename, const Common::String &prefix, bool encoded); 316 ~CCArchive() override; 317 318 // Archive implementation 319 Common::SeekableReadStream *createReadStreamForMember(const Common::Path &path) const override; 320 }; 321 322 class SaveArchive : public BaseCCArchive { 323 friend class OutFile; 324 private: 325 Party *_party; 326 byte *_data; 327 uint32 _dataSize; 328 Common::HashMap<uint16, Common::MemoryWriteStreamDynamic *> _newData; 329 public: 330 SaveArchive(Party *party); 331 ~SaveArchive() override; 332 333 /** 334 * Sets up the dynamic data for the game for a new game 335 */ 336 void reset(CCArchive *src); 337 338 /** 339 * Archive implementation 340 */ 341 Common::SeekableReadStream *createReadStreamForMember(const Common::Path &path) const override; 342 343 /** 344 * Archive implementation 345 */ 346 virtual Common::SeekableReadStream *createReadStreamForMember(uint16 id) const; 347 348 /** 349 * Loads a save archive from a stream 350 */ 351 void load(Common::SeekableReadStream &stream); 352 353 /** 354 * Saves a save archive to a savegame 355 */ 356 void save(Common::WriteStream &s); 357 358 /** 359 * Load the character roster and party 360 */ 361 void loadParty(); 362 363 /** 364 * Sets a new resource entry 365 */ 366 void replaceEntry(uint16 id, const byte *data, size_t size); 367 }; 368 369 /** 370 * Provides an interface to updating files within the in-memory save state 371 */ 372 class OutFile : public Common::WriteStream { 373 private: 374 SaveArchive *_archive; 375 Common::String _filename; 376 Common::MemoryWriteStreamDynamic _backingStream; 377 public: 378 OutFile(const Common::String &filename); 379 OutFile(const Common::String &filename, SaveArchive *archive); 380 OutFile(const Common::String &filename, int ccMode); 381 382 /** 383 * Finishes any pending writes, pushing out the written data 384 */ 385 void finalize() override; 386 387 /** 388 * Writes data 389 */ 390 uint32 write(const void *dataPtr, uint32 dataSize) override; 391 392 /** 393 * Returns the current position 394 */ 395 int64 pos() const override; 396 }; 397 398 } // End of namespace Xeen 399 400 #endif /* XEEN_FILES_H */ 401