Files
scummvm-cursorfix/engines/zvision/file/file_manager.cpp
2026-02-02 04:50:13 +01:00

267 lines
8.2 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/debug.h"
#include "zvision/file/file_manager.h"
#include "zvision/file/zfs_archive.h"
namespace ZVision {
const char* genExcluded[] {"*.dll", "*.ini", "*.exe", "*.isu", "*.inf", "*path*.txt", "r.svr", "*.zix", "*.hlp", "*.gid"};
const char* zgiAlternates[] {
"c000h01q.raw", "cm00h01q.raw", "dm00h01q.raw", "e000h01q.raw", "em00h11p.raw", "em00h50q.raw", "gjnph65p.raw",
"gjnph72p.raw", "h000h01q.raw", "m000h01q.raw", "p000h01q.raw", "q000h01q.raw", "sw00h01q.raw", "t000h01q.raw",
"u000h01q.raw"
};
FileManager::FileManager(ZVision *engine) {
}
Common::File *FileManager::open(const Common::Path &filePath, bool allowSrc) {
debugC(5, kDebugFile, "FileManager::open()");
Common::File *file = new Common::File();
Common::File *out = nullptr;
Common::String fileName = filePath.baseName();
bool open = false;
bool altFound = false;
bool altOpen = false;
bool found = SearchMan.hasFile(filePath);
if(found) {
debugC(5, kDebugFile,"File %s found", fileName.c_str());
open = file->open(filePath);
if(open)
debugC(5, kDebugFile,"File %s opened", fileName.c_str());
}
if (allowSrc) {
Common::File *altFile = new Common::File();
Common::String altName = fileName;
altName.setChar('s', altName.size() - 3);
altName.setChar('r', altName.size() - 2);
altName.setChar('c', altName.size() - 1);
Common::Path altPath = filePath.getParent().appendComponent(altName);
altFound = SearchMan.hasFile(altPath);
if (altFound) {
debugC(5, kDebugFile,"Alternate file %s found", altName.c_str());
altOpen = altFile->open(altPath);
if (altOpen)
debugC(5, kDebugFile,"Alternate file %s opened", altName.c_str());
}
if(altOpen) {
if(open)
out = file->size() < altFile->size() ? altFile : file;
else
out = altFile;
}
else if(open)
out = file;
else {
if (found && altFound)
warning("Found file %s and alternate file %s but unable to open either", fileName.c_str(), altName.c_str());
else if (found)
warning("Found file %s but unable to open; alternate file %s not found", fileName.c_str(), altName.c_str());
else if (altFound)
warning("File %s not found; alternate file %s found but but unable to open", fileName.c_str(), altName.c_str());
else
warning("Unable to find file %s or alternate file %s", fileName.c_str(), altName.c_str());
}
if (out == altFile)
debugC(5, kDebugFile,"Returning alternate file %s", altName.c_str());
else {
if(altOpen)
altFile->close();
delete altFile;
}
}
else {
if(open)
out = file;
else if (found)
warning("File %s found, but unable to open", fileName.c_str());
else
warning("File %s not found", fileName.c_str());
}
if (out == file)
debugC(5, kDebugFile,"Returning file %s", fileName.c_str());
else {
if(open)
file->close();
delete file;
}
return out;
}
bool FileManager::exists(Common::Path filePath, bool allowSrc) {
Common::File file;
if (file.exists(filePath))
return true;
else if (allowSrc) {
if (file.exists(srcPath(filePath)))
return true;
}
return false;
}
Common::Path FileManager::srcPath(Common::Path filePath) {
Common::String name = filePath.baseName();
name.setChar('s', name.size() - 3);
name.setChar('r', name.size() - 2);
name.setChar('c', name.size() - 1);
return filePath.getParent().appendComponent(name);
}
bool FileManager::loadZix(const Common::Path &zixPath, const Common::FSNode &gameDataDir) {
Common::File zixFile;
if (!zixFile.open(zixPath))
return false;
Common::String line;
// Skip first block
while (!zixFile.eos()) {
line = zixFile.readLine();
if (line.matchString("----------*", true))
break;
}
if (zixFile.eos())
error("Corrupt ZIX file: %s", zixPath.toString(Common::Path::kNativeSeparator).c_str());
uint8 archives = 0;
// Parse subdirectories & archives
debugC(1, kDebugFile, "Parsing list of subdirectories & archives in %s", zixPath.toString(Common::Path::kNativeSeparator).c_str());
while (!zixFile.eos()) {
line = zixFile.readLine();
line.trim();
if (line.matchString("----------*", true))
break;
else if (line.matchString("DIR:*", true) || line.matchString("CD0:*", true) || line.matchString("CD1:*", true) || line.matchString("CD2:*", true)) {
line = Common::String(line.c_str() + 5);
for (uint i = 0; i < line.size(); i++)
if (line[i] == '\\')
line.setChar('/', i);
// Check if NEMESIS.ZIX/MEDIUM.ZIX refers to the znemesis folder, and
// check the game root folder instead
if (line.hasPrefix("znemesis/"))
line = Common::String(line.c_str() + 9);
// Check if INQUIS.ZIX refers to the ZGI folder, and check the game
// root folder instead
if (line.hasPrefix("zgi/"))
line = Common::String(line.c_str() + 4);
if (line.hasPrefix("zgi_e/"))
line = Common::String(line.c_str() + 6);
if (line.size() && line[0] == '.')
line.deleteChar(0);
if (line.size() && line[0] == '/')
line.deleteChar(0);
if (line.size() && line.hasSuffix("/"))
line.deleteLastChar();
Common::Path path(line, '/');
if (line.matchString("*.zfs", true)) {
if (!SearchMan.hasArchive(line)) {
path = path.getLastComponent(); //We are using the search manager in "flat" mode, so only filenames are needed
debugC(1, kDebugFile, "Adding archive %s to search manager.", path.toString().c_str());
Common::Archive *arc;
arc = new ZfsArchive(path);
SearchMan.add(line, arc);
}
}
else {
debugC(1, kDebugFile, "Adding directory %s to search manager.", path.toString().c_str());
SearchMan.addSubDirectoryMatching(gameDataDir,path.toString());
}
archives++;
}
}
if (zixFile.eos())
error("Corrupt ZIX file: %s", zixPath.toString(Common::Path::kNativeSeparator).c_str());
//Parse files
debugC(1, kDebugFile, "Parsing list of individual resource files in %s", zixPath.toString(Common::Path::kNativeSeparator).c_str());
while (!zixFile.eos()) {
line = zixFile.readLine();
line.trim();
uint dr = 0;
char buf[32];
if (sscanf(line.c_str(), "%u %s", &dr, buf) == 2) {
if (dr <= archives && dr > 0) {
Common::String name(buf);
bool exclude = false;
bool allowSrc = false;
for (auto excName : genExcluded)
if(name.matchString(excName, true)) {
exclude = true;
break;
}
for (auto altName : zgiAlternates)
if(name.matchString(altName, true)) {
allowSrc = true;
break;
}
if (!exclude) {
Common::Path path(name);
// No need to add file, just verify that it exists
if (allowSrc) {
Common::Path altPath = srcPath(path);
if (!SearchMan.hasFile(path) && !SearchMan.hasFile(altPath))
warning("Missing files %s and/or %s", path.toString().c_str(), altPath.toString().c_str());
else if (SearchMan.hasFile(path))
debugC(5, kDebugFile, "File found: %s", path.toString().c_str());
else
debugC(5, kDebugFile, "Alternate file found: %s", altPath.toString().c_str());
}
else {
if (!SearchMan.hasFile(path))
warning("Missing file %s", path.toString().c_str());
else
debugC(5, kDebugFile, "File found: %s", path.toString().c_str());
}
if (name.matchString("*.zfs", true))
if (!SearchMan.hasArchive(name)) {
Common::Path path_(path);
debugC(kDebugFile, "Adding archive %s to search manager.", path.toString().c_str());
Common::Archive *arc;
arc = new ZfsArchive(path_);
SearchMan.add(name, arc);
}
}
}
}
}
return true;
}
} // End of namespace Zvision