diff options
Diffstat (limited to 'engines/xeen/files.cpp')
-rw-r--r-- | engines/xeen/files.cpp | 281 |
1 files changed, 235 insertions, 46 deletions
diff --git a/engines/xeen/files.cpp b/engines/xeen/files.cpp index 06dd3d12a7..375b9df65a 100644 --- a/engines/xeen/files.cpp +++ b/engines/xeen/files.cpp @@ -26,6 +26,7 @@ #include "common/textconsole.h" #include "xeen/xeen.h" #include "xeen/files.h" +#include "xeen/saves.h" namespace Xeen { @@ -120,7 +121,7 @@ int BaseCCArchive::listMembers(Common::ArchiveMemberList &list) const { CCArchive::CCArchive(const Common::String &filename, bool encoded): BaseCCArchive(), _filename(filename), _encoded(encoded) { - File f(filename); + File f(filename, SearchMan); loadIndex(&f); } @@ -128,7 +129,7 @@ CCArchive::CCArchive(const Common::String &filename, const Common::String &prefi bool encoded): BaseCCArchive(), _filename(filename), _prefix(prefix), _encoded(encoded) { _prefix.toLowercase(); - File f(filename); + File f(filename, SearchMan); loadIndex(&f); } @@ -183,71 +184,68 @@ Common::SeekableReadStream *CCArchive::createReadStreamForMember(const Common::S /*------------------------------------------------------------------------*/ -CCArchive *FileManager::_archives[3]; - FileManager::FileManager(XeenEngine *vm) { Common::File f; - int sideNum = 0; - - File::_currentArchive = ANY_ARCHIVE; _isDarkCc = vm->getGameID() == GType_DarkSide; - _archives[0] = _archives[1] = _archives[2] = nullptr; - - if (vm->getGameID() != GType_DarkSide) { - _archives[0] = new CCArchive("xeen.cc", "xeen", true); - SearchMan.add("xeen", _archives[0]); - sideNum = 1; + + File::_xeenCc = (vm->getGameID() == GType_DarkSide) ? nullptr : + new CCArchive("xeen.cc", "xeen", true); + File::_darkCc = (vm->getGameID() == GType_Clouds) ? nullptr : + new CCArchive("dark.cc", "dark", true); + if (Common::File::exists("intro.cc")) { + CCArchive *introCc = new CCArchive("intro.cc", "intro", true); + SearchMan.add("intro", introCc); } - if (vm->getGameID() == GType_DarkSide || vm->getGameID() == GType_WorldOfXeen) { - _archives[sideNum] = new CCArchive("dark.cc", "dark", true); - SearchMan.add("dark", _archives[sideNum]); - } + File::_currentArchive = vm->getGameID() == GType_DarkSide ? + File::_darkCc : File::_xeenCc; + assert(File::_currentArchive); +} - if (f.exists("intro.cc")) { - _archives[2] = new CCArchive("intro.cc", "intro", true); - SearchMan.add("intro", _archives[2]); - } +FileManager::~FileManager() { + SearchMan.remove("intro"); + delete File::_xeenCc; + delete File::_darkCc; } -void FileManager::setGameCc(bool isDarkCc) { - _isDarkCc = isDarkCc; - File::_currentArchive = isDarkCc ? ALTSIDE_ARCHIVE : GAME_ARCHIVE; +void FileManager::setGameCc(int ccMode) { + if (g_vm->getGameID() != GType_WorldOfXeen) + ccMode = 1; + + File::setCurrentArchive(ccMode); + _isDarkCc = ccMode != 0; } /*------------------------------------------------------------------------*/ -ArchiveType File::_currentArchive; +CCArchive *File::_xeenCc; +CCArchive *File::_darkCc; +SaveArchive *File::_xeenSave; +SaveArchive *File::_darkSave; +BaseCCArchive *File::_currentArchive; +SaveArchive *File::_currentSave; File::File(const Common::String &filename) { File::open(filename); } -File::File(const Common::String &filename, ArchiveType archiveType) { - File::open(filename, archiveType); -} - File::File(const Common::String &filename, Common::Archive &archive) { File::open(filename, archive); } +File::File(const Common::String &filename, int ccMode) { + File::open(filename, ccMode); +} + bool File::open(const Common::String &filename) { - return File::open(filename, _currentArchive); -} - -bool File::open(const Common::String &filename, ArchiveType archiveType) { - if (archiveType == ANY_ARCHIVE) { - Common::File::open(filename); - } else { - CCArchive &archive = *FileManager::_archives[archiveType]; - if (!Common::File::open(filename, archive)) - // If not in the designated archive, try opening from any archive, - // or as a standalone file in the filesystem - Common::File::open(filename); + if (!_currentSave || !Common::File::open(filename, *_currentSave)) { + if (!Common::File::open(filename, *_currentArchive)) { + // Could not find in current archive, so try intro.cc or in folder + if (!Common::File::open(filename)) + error("Could not open file - %s", filename.c_str()); + } } - if (!isOpen()) - error("Could not open file - %s", filename.c_str()); return true; } @@ -257,6 +255,36 @@ bool File::open(const Common::String &filename, Common::Archive &archive) { return true; } +bool File::open(const Common::String &filename, int ccMode) { + FileManager &files = *g_vm->_files; + int oldMode = files._isDarkCc ? 1 : 0; + + files.setGameCc(ccMode); + File::open(filename); + files.setGameCc(oldMode); + + return true; +} + +void File::setCurrentArchive(int ccMode) { + switch (ccMode) { + case 0: + _currentArchive = _xeenCc; + _currentSave = _xeenSave; + break; + + case 1: + _currentArchive = _darkCc; + _currentSave = _darkSave; + break; + + default: + break; + } + + assert(_currentArchive); +} + Common::String File::readString() { Common::String result; char c; @@ -267,18 +295,179 @@ Common::String File::readString() { return result; } +bool File::exists(const Common::String &filename) { + if (!_currentSave || !_currentSave->hasFile(filename)) { + if (!_currentArchive->hasFile(filename)) { + // Could not find in current archive, so try intro.cc or in folder + return Common::File::exists(filename); + } + } + + return true; +} + +bool File::exists(const Common::String &filename, int ccMode) { + FileManager &files = *g_vm->_files; + int oldMode = files._isDarkCc ? 1 : 0; + + files.setGameCc(ccMode); + bool result = exists(filename); + files.setGameCc(oldMode); + + return result; +} + +void File::syncBitFlags(Common::Serializer &s, bool *startP, bool *endP) { + byte data = 0; + + int bitCounter = 0; + for (bool *p = startP; p < endP; ++p, bitCounter = (bitCounter + 1) % 8) { + if (bitCounter == 0) { + if (s.isLoading() || p != startP) + s.syncAsByte(data); + + if (s.isSaving()) + data = 0; + } + + if (s.isLoading()) + *p = ((data >> bitCounter) & 1) != 0; + else if (*p) + data |= 1 << bitCounter; + } + + if (s.isSaving()) + s.syncAsByte(data); +} + /*------------------------------------------------------------------------*/ void StringArray::load(const Common::String &name) { - load(name, ANY_ARCHIVE); + File f(name); + clear(); + while (f.pos() < f.size()) + push_back(f.readString()); } -void StringArray::load(const Common::String &name, ArchiveType archiveType) { - File f(name, archiveType); +void StringArray::load(const Common::String &name, int ccMode) { + File f(name, ccMode); clear(); while (f.pos() < f.size()) push_back(f.readString()); } +/*------------------------------------------------------------------------*/ + +SaveArchive::SaveArchive(Party *party) : BaseCCArchive(), _party(party) { + _data = nullptr; +} + +SaveArchive::~SaveArchive() { + for (Common::HashMap<uint16, Common::MemoryWriteStreamDynamic *>::iterator it = _newData.begin(); it != _newData.end(); it++) { + delete (*it)._value; + } + delete[] _data; +} + +Common::SeekableReadStream *SaveArchive::createReadStreamForMember(const Common::String &name) const { + CCEntry ccEntry; + + // If the given resource has already been perviously "written" to the + // save manager, then return that new resource + uint16 id = BaseCCArchive::convertNameToId(name); + if (_newData.contains(id)) { + Common::MemoryWriteStreamDynamic *stream = _newData[id]; + return new Common::MemoryReadStream(stream->getData(), stream->size()); + } + + // Retrieve the resource from the loaded savefile + if (getHeaderEntry(name, ccEntry)) { + // Open the correct CC entry + return new Common::MemoryReadStream(_data + ccEntry._offset, ccEntry._size); + } + + return nullptr; +} + +void SaveArchive::load(Common::SeekableReadStream *stream) { + loadIndex(stream); + + delete[] _data; + _data = new byte[stream->size()]; + stream->seek(0); + stream->read(_data, stream->size()); + + // Load in the character stats and active party + Common::SeekableReadStream *chr = createReadStreamForMember("maze.chr"); + Common::Serializer sChr(chr, nullptr); + _party->_roster.synchronize(sChr); + delete chr; + + Common::SeekableReadStream *pty = createReadStreamForMember("maze.pty"); + Common::Serializer sPty(pty, nullptr); + _party->synchronize(sPty); + delete pty; +} + +void SaveArchive::reset(CCArchive *src) { + Common::MemoryWriteStreamDynamic saveFile(DisposeAfterUse::YES); + File fIn; + + g_vm->_files->setGameCc(g_vm->getGameID() == GType_DarkSide ? 1 : 0); + const int RESOURCES[6] = { 0x2A0C, 0x2A1C, 0x2A2C, 0x2A3C, 0x284C, 0x2A5C }; + for (int i = 0; i < 6; ++i) { + Common::String filename = Common::String::format("%.4x", RESOURCES[i]); + if (src->hasFile(filename)) { + // Read in the next resource + fIn.open(filename, *src); + byte *data = new byte[fIn.size()]; + fIn.read(data, fIn.size()); + + // Copy it to the combined savefile resource + saveFile.write(data, fIn.size()); + delete[] data; + fIn.close(); + } + } + + assert(saveFile.size() > 0); + Common::MemoryReadStream f(saveFile.getData(), saveFile.size()); + load(&f); +} + +/*------------------------------------------------------------------------*/ + +OutFile::OutFile(const Common::String &filename) : + _filename(filename), _backingStream(DisposeAfterUse::YES) { + _archive = File::_currentSave; +} + +OutFile::OutFile(const Common::String &filename, SaveArchive *archive) : + _filename(filename), _archive(archive), _backingStream(DisposeAfterUse::YES) { +} + +OutFile::OutFile(const Common::String &filename, int ccMode) : + _filename(filename), _backingStream(DisposeAfterUse::YES) { + g_vm->_files->setGameCc(ccMode); + _archive = File::_currentSave; +} + +uint32 OutFile::write(const void *dataPtr, uint32 dataSize) { + return _backingStream.write(dataPtr, dataSize); +} + +int32 OutFile::pos() const { + return _backingStream.pos(); +} + +void OutFile::finalize() { + uint16 id = BaseCCArchive::convertNameToId(_filename); + + if (!_archive->_newData.contains(id)) + _archive->_newData[id] = new Common::MemoryWriteStreamDynamic(DisposeAfterUse::YES); + + Common::MemoryWriteStreamDynamic *out = _archive->_newData[id]; + out->write(_backingStream.getData(), _backingStream.size()); +} } // End of namespace Xeen |