From 742521c20db68e965761ba9309bb0a3dea379217 Mon Sep 17 00:00:00 2001 From: Einar Johan Trøan Sømåen Date: Sun, 22 Jul 2012 07:24:48 +0200 Subject: WINTERMUTE: Redo base_file_manager, to use FSLists for registering/opening packages. This is helpfull for consistency between registering and lookup, and allows for explicit removal/adding of sub_paths for the engine. But most importantly it keeps the loading consistent and non-duplicated for detection. --- engines/wintermute/base/base_file_manager.cpp | 171 +++++++++++------------- engines/wintermute/base/base_file_manager.h | 14 +- engines/wintermute/base/file/base_disk_file.cpp | 57 +++----- engines/wintermute/base/file/base_package.cpp | 4 +- engines/wintermute/base/file/base_package.h | 2 +- engines/wintermute/dcpackage.h | 40 +++--- 6 files changed, 128 insertions(+), 160 deletions(-) diff --git a/engines/wintermute/base/base_file_manager.cpp b/engines/wintermute/base/base_file_manager.cpp index a2c81b8a8c..4dcc1c6948 100644 --- a/engines/wintermute/base/base_file_manager.cpp +++ b/engines/wintermute/base/base_file_manager.cpp @@ -50,6 +50,7 @@ #include "common/fs.h" #include "common/file.h" #include "common/savefile.h" +#include "common/fs.h" namespace WinterMute { @@ -75,15 +76,8 @@ BaseFileManager::~BaseFileManager() { ////////////////////////////////////////////////////////////////////////// bool BaseFileManager::cleanup() { // delete registered paths - for (uint32 i = 0; i < _singlePaths.size(); i++) - delete [] _singlePaths[i]; - _singlePaths.clear(); - - for (uint32 i = 0; i < _packagePaths.size(); i++) - delete [] _packagePaths[i]; _packagePaths.clear(); - // delete file entries _filesIter = _files.begin(); while (_filesIter != _files.end()) { @@ -226,7 +220,7 @@ bool BaseFileManager::saveFile(const Common::String &filename, byte *buffer, uin bool BaseFileManager::requestCD(int cd, char *packageFile, const char *filename) { // unmount all non-local packages for (uint32 i = 0; i < _packages.size(); i++) { - if (_packages[i]->_cD > 0) _packages[i]->close(); + if (_packages[i]->_cd > 0) _packages[i]->close(); } @@ -235,24 +229,25 @@ bool BaseFileManager::requestCD(int cd, char *packageFile, const char *filename) ////////////////////////////////////////////////////////////////////////// -bool BaseFileManager::addPath(TPathType type, const Common::String &path) { - if (path.c_str() == NULL || strlen(path.c_str()) < 1) return STATUS_FAILED; +bool BaseFileManager::addPath(TPathType type, const Common::FSNode &path) { + if (path.getName().c_str() == NULL || strlen(path.getName().c_str()) < 1) return STATUS_FAILED; - bool slashed = (path[path.size() - 1] == '\\' || path[path.size() - 1] == '/'); +// bool slashed = (path[path.size() - 1] == '\\' || path[path.size() - 1] == '/'); - char *buffer = new char [strlen(path.c_str()) + 1 + (slashed ? 0 : 1)]; +/* char *buffer = new char [strlen(path.c_str()) + 1 + (slashed ? 0 : 1)]; if (buffer == NULL) return STATUS_FAILED; strcpy(buffer, path.c_str()); - if (!slashed) strcat(buffer, "\\"); + if (!slashed) strcat(buffer, "\\");*/ //BasePlatform::strlwr(buffer); switch (type) { case PATH_SINGLE: - _singlePaths.push_back(buffer); + // _singlePaths.push_back(path); + error("TODO: Allow adding single-paths"); break; case PATH_PACKAGE: - _packagePaths.push_back(buffer); + _packagePaths.push_back(path); break; } @@ -262,12 +257,12 @@ bool BaseFileManager::addPath(TPathType type, const Common::String &path) { ////////////////////////////////////////////////////////////////////////// bool BaseFileManager::reloadPaths() { // delete registered paths - for (uint32 i = 0; i < _singlePaths.size(); i++) - delete [] _singlePaths[i]; - _singlePaths.clear(); +/* for (uint32 i = 0; i < _singlePaths.size(); i++) + delete [] _singlePaths[i];*/ + //_singlePaths.clear(); - for (uint32 i = 0; i < _packagePaths.size(); i++) - delete [] _packagePaths[i]; +/* for (uint32 i = 0; i < _packagePaths.size(); i++) + delete [] _packagePaths[i];*/ _packagePaths.clear(); return initPaths(); @@ -289,16 +284,17 @@ bool BaseFileManager::initPaths() { for (int i = 0; i < numPaths; i++) { char *path = BaseUtils::strEntry(i, pathList.c_str(), ';'); if (path && strlen(path) > 0) { - addPath(PATH_SINGLE, path); + error("BaseFileManager::initPaths - Game wants to add customPath: %s", path); // TODO +// addPath(PATH_SINGLE, path); } delete[] path; path = NULL; } - addPath(PATH_SINGLE, ".\\"); - +// addPath(PATH_SINGLE, ".\\"); // package files paths - addPath(PATH_PACKAGE, "./"); + const Common::FSNode gameData(ConfMan.get("path")); + addPath(PATH_PACKAGE, gameData); pathList = _gameRef->_registry->readString("Resource", "PackagePaths", ""); numPaths = BaseUtils::strNumEntries(pathList.c_str(), ';'); @@ -306,16 +302,32 @@ bool BaseFileManager::initPaths() { for (int i = 0; i < numPaths; i++) { char *path = BaseUtils::strEntry(i, pathList.c_str(), ';'); if (path && strlen(path) > 0) { - addPath(PATH_PACKAGE, path); + error("BaseFileManager::initPaths - Game wants to add packagePath: %s", path); // TODO +// addPath(PATH_PACKAGE, path); } delete[] path; path = NULL; } - addPath(PATH_PACKAGE, "data"); + + Common::FSNode dataSubFolder = gameData.getChild("data"); + if (dataSubFolder.exists()) { + addPath(PATH_PACKAGE, dataSubFolder); + } return STATUS_OK; } +bool BaseFileManager::registerPackages(const Common::FSList &fslist) { + for (Common::FSList::const_iterator it = fslist.begin(); it != fslist.end(); it++) { + warning("Adding %s", (*it).getName().c_str()); + if ((*it).getName().contains(".dcp")) { + if (registerPackage((*it).createReadStream())) { + addPath(PATH_PACKAGE, (*it)); + } + } + } + warning(" Registered %d files in %d package(s)", _files.size(), _packages.size()); +} ////////////////////////////////////////////////////////////////////////// bool BaseFileManager::registerPackages() { @@ -324,11 +336,24 @@ bool BaseFileManager::registerPackages() { _gameRef->LOG(0, "Scanning packages..."); debugC(kWinterMuteDebugFileAccess, "Scanning packages"); - Common::ArchiveMemberList files; +/* Common::ArchiveMemberList files; SearchMan.listMatchingMembers(files, "*.dcp"); for (Common::ArchiveMemberList::iterator it = files.begin(); it != files.end(); it++) { registerPackage((*it)->getName().c_str()); + }*/ + // Register without using SearchMan, as otherwise the FSNode-based lookup in openPackage will fail + // and that has to be like that to support the detection-scheme. + Common::FSList files; + for (Common::FSList::iterator it = _packagePaths.begin(); it != _packagePaths.end(); it++) { + warning("Should register %s %s", (*it).getPath().c_str(), (*it).getName().c_str()); + (*it).getChildren(files, Common::FSNode::kListFilesOnly); + for (Common::FSList::iterator fileIt = files.begin(); fileIt != files.end(); fileIt++) { + if (!fileIt->getName().contains(".dcp")) + continue; + warning("Registering %s %s", (*fileIt).getPath().c_str(), (*fileIt).getName().c_str()); + registerPackage((*fileIt).createReadStream()); + } } #if 0 AnsiString extension = AnsiString(PACKAGE_EXTENSION); @@ -373,7 +398,10 @@ bool BaseFileManager::registerPackage(const Common::String &filename , bool sear _gameRef->LOG(0, " Error opening package file '%s'. Ignoring.", filename.c_str()); return STATUS_OK; } + return registerPackage(package, filename); +} +bool BaseFileManager::registerPackage(Common::SeekableReadStream *package, const Common::String &filename, bool searchSignature) { uint32 absoluteOffset = 0; bool boundToExe = false; @@ -392,25 +420,25 @@ bool BaseFileManager::registerPackage(const Common::String &filename , bool sear TPackageHeader hdr; hdr.readFromStream(package); // package->read(&hdr, sizeof(TPackageHeader), 1, f); - if (hdr.Magic1 != PACKAGE_MAGIC_1 || hdr.Magic2 != PACKAGE_MAGIC_2 || hdr.PackageVersion > PACKAGE_VERSION) { + if (hdr._magic1 != PACKAGE_MAGIC_1 || hdr._magic2 != PACKAGE_MAGIC_2 || hdr._packageVersion > PACKAGE_VERSION) { _gameRef->LOG(0, " Invalid header in package file '%s'. Ignoring.", filename.c_str()); delete package; return STATUS_OK; } - if (hdr.PackageVersion != PACKAGE_VERSION) { + if (hdr._packageVersion != PACKAGE_VERSION) { _gameRef->LOG(0, " Warning: package file '%s' is outdated.", filename.c_str()); } // new in v2 - if (hdr.PackageVersion == PACKAGE_VERSION) { + if (hdr._packageVersion == PACKAGE_VERSION) { uint32 dirOffset; dirOffset = package->readUint32LE(); dirOffset += absoluteOffset; package->seek(dirOffset, SEEK_SET); } - for (uint32 i = 0; i < hdr.NumDirs; i++) { + for (uint32 i = 0; i < hdr._numDirs; i++) { BasePackage *pkg = new BasePackage(_gameRef); if (!pkg) return STATUS_FAILED; @@ -420,10 +448,10 @@ bool BaseFileManager::registerPackage(const Common::String &filename , bool sear byte nameLength = package->readByte(); pkg->_name = new char[nameLength]; package->read(pkg->_name, nameLength); - pkg->_cD = package->readByte(); - pkg->_priority = hdr.Priority; + pkg->_cd = package->readByte(); + pkg->_priority = hdr._priority; - if (!hdr.MasterIndex) pkg->_cD = 0; // override CD to fixed disk + if (!hdr._masterIndex) pkg->_cd = 0; // override CD to fixed disk _packages.push_back(pkg); @@ -439,7 +467,7 @@ bool BaseFileManager::registerPackage(const Common::String &filename , bool sear package->read(name, nameLength); // v2 - xor name - if (hdr.PackageVersion == PACKAGE_VERSION) { + if (hdr._packageVersion == PACKAGE_VERSION) { for (int k = 0; k < nameLength; k++) { ((byte *)name)[k] ^= 'D'; } @@ -458,7 +486,7 @@ bool BaseFileManager::registerPackage(const Common::String &filename , bool sear compLength = package->readUint32LE(); flags = package->readUint32LE(); - if (hdr.PackageVersion == PACKAGE_VERSION) { + if (hdr._packageVersion == PACKAGE_VERSION) { timeDate1 = package->readUint32LE(); timeDate2 = package->readUint32LE(); } @@ -474,7 +502,7 @@ bool BaseFileManager::registerPackage(const Common::String &filename , bool sear _files[name] = file; } else { // current package has lower CD number or higher priority, than the registered - if (pkg->_cD < _filesIter->_value->_package->_cD || pkg->_priority > _filesIter->_value->_package->_priority) { + if (pkg->_cd < _filesIter->_value->_package->_cd || pkg->_priority > _filesIter->_value->_package->_priority) { _filesIter->_value->_package = pkg; _filesIter->_value->_offset = offset; _filesIter->_value->_length = length; @@ -511,13 +539,21 @@ Common::File *BaseFileManager::openPackage(const Common::String &name) { Common::File *ret = new Common::File(); char filename[MAX_PATH_LENGTH]; - for (uint32 i = 0; i < _packagePaths.size(); i++) { + for (Common::FSList::iterator it = _packagePaths.begin(); it != _packagePaths.end(); it++) { + Common::String packageName = (*it).getName(); + if (packageName == (name + ".dcp")) + ret->open((*it)); + if (ret->isOpen()) { + return ret; + } + } +/* for (uint32 i = 0; i < _packagePaths.size(); i++) { sprintf(filename, "%s%s.%s", _packagePaths[i], name.c_str(), PACKAGE_EXTENSION); ret->open(filename); if (ret->isOpen()) { return ret; } - } + }*/ sprintf(filename, "%s.%s", name.c_str(), PACKAGE_EXTENSION); ret->open(filename); @@ -530,61 +566,6 @@ Common::File *BaseFileManager::openPackage(const Common::String &name) { } -////////////////////////////////////////////////////////////////////////// -Common::File *BaseFileManager::openSingleFile(const Common::String &name) { - restoreCurrentDir(); - - Common::File *ret = NULL; - char filename[MAX_PATH_LENGTH]; - - for (uint32 i = 0; i < _singlePaths.size(); i++) { - sprintf(filename, "%s%s", _singlePaths[i], name.c_str()); - ret->open(filename); - if (ret->isOpen()) - return ret; - } - - // didn't find in search paths, try to open directly - ret->open(name); - if (ret->isOpen()) { - return ret; - } else { - delete ret; - return NULL; - } -} - - -////////////////////////////////////////////////////////////////////////// -bool BaseFileManager::getFullPath(const Common::String &filename, char *fullname) { - restoreCurrentDir(); - - Common::File f; - bool found = false; - - for (uint32 i = 0; i < _singlePaths.size(); i++) { - sprintf(fullname, "%s%s", _singlePaths[i], filename.c_str()); - f.open(fullname); - if (f.isOpen()) { - f.close(); - found = true; - break; - } - } - - if (!found) { - f.open(filename.c_str()); - if (f.isOpen()) { - f.close(); - found = true; - strcpy(fullname, filename.c_str()); - } - } - - return found; -} - - ////////////////////////////////////////////////////////////////////////// BaseFileEntry *BaseFileManager::getPackageEntry(const Common::String &filename) { char *upc_name = new char[strlen(filename.c_str()) + 1]; @@ -703,7 +684,7 @@ bool BaseFileManager::setBasePath(const Common::String &path) { ////////////////////////////////////////////////////////////////////////// -bool BaseFileManager::findPackageSignature(Common::File *f, uint32 *offset) { +bool BaseFileManager::findPackageSignature(Common::SeekableReadStream *f, uint32 *offset) { byte buf[32768]; byte signature[8]; diff --git a/engines/wintermute/base/base_file_manager.h b/engines/wintermute/base/base_file_manager.h index 469108bee8..78e6cb737f 100644 --- a/engines/wintermute/base/base_file_manager.h +++ b/engines/wintermute/base/base_file_manager.h @@ -32,6 +32,7 @@ #include "engines/wintermute/base/file/base_file_entry.h" #include "common/archive.h" #include "common/str.h" +#include "common/fs.h" namespace Common { class File; @@ -41,39 +42,38 @@ namespace WinterMute { class BaseFile; class BaseFileManager: BaseClass { public: - bool findPackageSignature(Common::File *f, uint32 *offset); + bool findPackageSignature(Common::SeekableReadStream *f, uint32 *offset); bool cleanup(); bool setBasePath(const Common::String &path); bool restoreCurrentDir(); char *_basePath; - bool getFullPath(const Common::String &filename, char *fullname); Common::SeekableReadStream *openFileRaw(const Common::String &filename); bool closeFile(Common::SeekableReadStream *File); bool hasFile(const Common::String &filename); Common::SeekableReadStream *openFile(const Common::String &filename, bool absPathWarning = true, bool keepTrackOf = true); BaseFileEntry *getPackageEntry(const Common::String &filename); - Common::File *openSingleFile(const Common::String &name); Common::File *openPackage(const Common::String &name); + bool registerPackages(const Common::FSList &fslist); bool registerPackages(); bool initPaths(); bool reloadPaths(); typedef enum { PATH_PACKAGE, PATH_SINGLE } TPathType; - bool addPath(TPathType type, const Common::String &path); + bool addPath(TPathType type, const Common::FSNode &path); bool requestCD(int cd, char *packageFile, const char *filename); Common::SeekableReadStream *loadSaveGame(const Common::String &filename); bool saveFile(const Common::String &filename, byte *buffer, uint32 bufferSize, bool compressed = false, byte *prefixBuffer = NULL, uint32 prefixSize = 0); byte *readWholeFile(const Common::String &filename, uint32 *size = NULL, bool mustExist = true); BaseFileManager(BaseGame *inGame = NULL); virtual ~BaseFileManager(); - Common::Array _singlePaths; - Common::Array _packagePaths; +// Common::FSList _singlePaths; + Common::FSList _packagePaths; Common::Array _packages; Common::Array _openFiles; - Common::HashMap _files; private: + bool registerPackage(Common::SeekableReadStream *stream, const Common::String &filename = "", bool searchSignature = false); bool registerPackage(const Common::String &filename, bool searchSignature = false); Common::HashMap::iterator _filesIter; bool isValidPackage(const AnsiString &fileName) const; diff --git a/engines/wintermute/base/file/base_disk_file.cpp b/engines/wintermute/base/file/base_disk_file.cpp index 6c89fc22f1..b4653c2c80 100644 --- a/engines/wintermute/base/file/base_disk_file.cpp +++ b/engines/wintermute/base/file/base_disk_file.cpp @@ -36,6 +36,7 @@ #include "common/memstream.h" #include "common/file.h" #include "common/zlib.h" +#include "common/archive.h" namespace WinterMute { @@ -50,27 +51,13 @@ Common::SeekableReadStream *openDiskFile(const Common::String &filename, BaseFil uint32 prefixSize = 0; Common::SeekableReadStream *file = NULL; - for (uint32 i = 0; i < fileManager->_singlePaths.size(); i++) { - sprintf(fullPath, "%s%s", fileManager->_singlePaths[i], filename.c_str()); - correctSlashes(fullPath); - Common::File *tempFile = new Common::File(); - if (tempFile->open(fullPath)) { - file = tempFile; - } else { - delete tempFile; - } - } - - // if we didn't find it in search paths, try to open directly - if (!file) { - strcpy(fullPath, filename.c_str()); - correctSlashes(fullPath); - - Common::File *tempFile = new Common::File(); - if (tempFile->open(fullPath)) { - file = tempFile; - } else { - delete tempFile; + Common::ArchiveMemberList files; + SearchMan.listMatchingMembers(files, filename); + + for (Common::ArchiveMemberList::iterator it = files.begin(); it != files.end(); it++) { + if ((*it)->getName() == filename) { + file = (*it)->createReadStream(); + break; } } @@ -83,38 +70,38 @@ Common::SeekableReadStream *openDiskFile(const Common::String &filename, BaseFil if (magic1 == DCGF_MAGIC && magic2 == COMPRESSED_FILE_MAGIC) compressed = true; if (compressed) { - uint32 DataOffset, CompSize, UncompSize; - DataOffset = file->readUint32LE(); - CompSize = file->readUint32LE(); - UncompSize = file->readUint32LE(); + uint32 dataOffset, compSize, uncompSize; + dataOffset = file->readUint32LE(); + compSize = file->readUint32LE(); + uncompSize = file->readUint32LE(); - byte *CompBuffer = new byte[CompSize]; - if (!CompBuffer) { + byte *compBuffer = new byte[compSize]; + if (!compBuffer) { error("Error allocating memory for compressed file '%s'", filename.c_str()); delete file; return NULL; } - byte *data = new byte[UncompSize]; + byte *data = new byte[uncompSize]; if (!data) { error("Error allocating buffer for file '%s'", filename.c_str()); - delete [] CompBuffer; + delete [] compBuffer; delete file; return NULL; } - file->seek(DataOffset + prefixSize, SEEK_SET); - file->read(CompBuffer, CompSize); + file->seek(dataOffset + prefixSize, SEEK_SET); + file->read(compBuffer, compSize); - if (Common::uncompress(data, (unsigned long *)&UncompSize, CompBuffer, CompSize) != true) { + if (Common::uncompress(data, (unsigned long *)&uncompSize, compBuffer, compSize) != true) { error("Error uncompressing file '%s'", filename.c_str()); - delete [] CompBuffer; + delete [] compBuffer; delete file; return NULL; } - delete [] CompBuffer; + delete [] compBuffer; - return new Common::MemoryReadStream(data, UncompSize, DisposeAfterUse::YES); + return new Common::MemoryReadStream(data, uncompSize, DisposeAfterUse::YES); delete file; file = NULL; } else { diff --git a/engines/wintermute/base/file/base_package.cpp b/engines/wintermute/base/file/base_package.cpp index 03a80f3d8d..24f7c23422 100644 --- a/engines/wintermute/base/file/base_package.cpp +++ b/engines/wintermute/base/file/base_package.cpp @@ -43,7 +43,7 @@ namespace WinterMute { BasePackage::BasePackage(BaseGame *inGame): BaseClass(inGame) { _file = NULL; _name = NULL; - _cD = 0; + _cd = 0; _priority = 0; _boundToExe = false; } @@ -89,7 +89,7 @@ bool BasePackage::read(Common::SeekableReadStream *file, uint32 offset, byte *bu Common::SeekableReadStream *BasePackage::getFilePointer() { Common::File *file = _gameRef->_fileManager->openPackage(_name); if (!file) { - _gameRef->_fileManager->requestCD(_cD, _name, ""); + _gameRef->_fileManager->requestCD(_cd, _name, ""); file = _gameRef->_fileManager->openPackage(_name); } return file; diff --git a/engines/wintermute/base/file/base_package.h b/engines/wintermute/base/file/base_package.h index bf45087f91..2f305ea049 100644 --- a/engines/wintermute/base/file/base_package.h +++ b/engines/wintermute/base/file/base_package.h @@ -49,7 +49,7 @@ public: bool close(); bool open(); char *_name; - int _cD; + int _cd; Common::SeekableReadStream *_file; BasePackage(BaseGame *inGame); virtual ~BasePackage(); diff --git a/engines/wintermute/dcpackage.h b/engines/wintermute/dcpackage.h index 0b7bdf9b44..5e47edba56 100644 --- a/engines/wintermute/dcpackage.h +++ b/engines/wintermute/dcpackage.h @@ -40,33 +40,33 @@ namespace WinterMute { struct TPackageHeader { - uint32 Magic1; - uint32 Magic2; - uint32 PackageVersion; - uint32 GameVersion; - byte Priority; - byte CD; - bool MasterIndex; - uint32 CreationTime; - char Desc[100]; - uint32 NumDirs; + uint32 _magic1; + uint32 _magic2; + uint32 _packageVersion; + uint32 _gameVersion; + byte _priority; + byte _cd; + bool _masterIndex; + uint32 _creationTime; + char _desc[100]; + uint32 _numDirs; // TODO: Move this out of the header. void readFromStream(Common::ReadStream *stream) { - Magic1 = stream->readUint32LE(); - Magic2 = stream->readUint32LE(); - PackageVersion = stream->readUint32LE(); + _magic1 = stream->readUint32LE(); + _magic2 = stream->readUint32LE(); + _packageVersion = stream->readUint32LE(); - GameVersion = stream->readUint32LE(); + _gameVersion = stream->readUint32LE(); - Priority = stream->readByte(); - CD = stream->readByte(); - MasterIndex = stream->readByte(); + _priority = stream->readByte(); + _cd = stream->readByte(); + _masterIndex = stream->readByte(); stream->readByte(); // To align the next byte... - CreationTime = stream->readUint32LE(); + _creationTime = stream->readUint32LE(); - stream->read(Desc, 100); - NumDirs = stream->readUint32LE(); + stream->read(_desc, 100); + _numDirs = stream->readUint32LE(); } }; -- cgit v1.2.3