COMMON: Make getPath() return a Path

Also add a compatibility shim which acts like a String.
In addition, simplify path related code to avoid stringification when
it's not needed.
Use the native path separator to display paths inside filesystem.
This commit is contained in:
Le Philousophe 2023-09-02 13:20:19 +02:00 committed by Eugene Sandulenko
parent 1722511c32
commit 8b2e5ef649
2 changed files with 49 additions and 28 deletions

View File

@ -118,7 +118,7 @@ FSNode::FSNode(const Path &p) {
if (p.empty() || p == Path("."))
tmp = factory->makeCurrentDirectoryFileNode();
else
tmp = factory->makeFileNodePath(p.toString());
tmp = factory->makeFileNodePath(p.toString(Common::Path::kNativeSeparator));
_realNode = SharedPtr<AbstractFSNode>(tmp);
}
@ -183,7 +183,7 @@ String FSNode::getFileName() const {
}
Common::Path FSNode::getPathInArchive() const {
return getName();
return Common::Path(getName(), Common::Path::kNoSeparator);
}
String FSNode::getRealName() const {
@ -203,9 +203,9 @@ FSNode FSNode::getParent() const {
}
}
String FSNode::getPath() const {
PathProxy FSNode::getPath() const {
assert(_realNode);
return _realNode->getPath();
return PathProxy(_realNode->getPath(), Common::Path::kNativeSeparator);
}
bool FSNode::isDirectory() const {
@ -341,7 +341,7 @@ FSNode *FSDirectory::lookupCache(NodeCache &cache, const Path &name) const {
}
bool FSDirectory::hasFile(const Path &path) const {
if (path.toString().empty() || !_node.isDirectory())
if (path.empty() || !_node.isDirectory())
return false;
FSNode *node = lookupCache(_fileCache, path);
@ -349,7 +349,7 @@ bool FSDirectory::hasFile(const Path &path) const {
}
bool FSDirectory::isPathDirectory(const Path &path) const {
if (path.toString().empty() || !_node.isDirectory())
if (path.empty() || !_node.isDirectory())
return false;
FSNode *node = lookupCache(_fileCache, path);
@ -357,16 +357,16 @@ bool FSDirectory::isPathDirectory(const Path &path) const {
}
const ArchiveMemberPtr FSDirectory::getMember(const Path &path) const {
if (path.toString().empty() || !_node.isDirectory())
if (path.empty() || !_node.isDirectory())
return ArchiveMemberPtr();
FSNode *node = lookupCache(_fileCache, path);
if (!node || !node->exists()) {
warning("FSDirectory::getMember: '%s' does not exist", Common::toPrintable(path.toString()).c_str());
warning("FSDirectory::getMember: '%s' does not exist", Common::toPrintable(path.toString(Common::Path::kNativeSeparator)).c_str());
return ArchiveMemberPtr();
} else if (node->isDirectory()) {
warning("FSDirectory::getMember: '%s' is a directory", Common::toPrintable(path.toString()).c_str());
warning("FSDirectory::getMember: '%s' is a directory", Common::toPrintable(path.toString(Common::Path::kNativeSeparator)).c_str());
return ArchiveMemberPtr();
}
@ -374,35 +374,35 @@ const ArchiveMemberPtr FSDirectory::getMember(const Path &path) const {
}
SeekableReadStream *FSDirectory::createReadStreamForMember(const Path &path) const {
if (path.toString().empty() || !_node.isDirectory())
if (path.empty() || !_node.isDirectory())
return nullptr;
FSNode *node = lookupCache(_fileCache, path);
if (!node)
return nullptr;
debug(5, "FSDirectory::createReadStreamForMember('%s') -> '%s'", path.toString().c_str(), node->getPath().c_str());
debug(5, "FSDirectory::createReadStreamForMember('%s') -> '%s'", path.toString(Common::Path::kNativeSeparator).c_str(), node->getPath().toString(Common::Path::kNativeSeparator).c_str());
SeekableReadStream *stream = node->createReadStream();
if (!stream)
warning("FSDirectory::createReadStreamForMember: Can't create stream for file '%s'", Common::toPrintable(path.toString()).c_str());
warning("FSDirectory::createReadStreamForMember: Can't create stream for file '%s'", Common::toPrintable(path.toString(Common::Path::kNativeSeparator)).c_str());
return stream;
}
SeekableReadStream *FSDirectory::createReadStreamForMemberAltStream(const Path &path, AltStreamType altStreamType) const {
if (path.toString().empty() || !_node.isDirectory())
if (path.empty() || !_node.isDirectory())
return nullptr;
FSNode *node = lookupCache(_fileCache, path);
if (!node)
return nullptr;
debug(5, "FSDirectory::createReadStreamForMemberAltStream('%s', %i) -> '%s'", path.toString().c_str(), static_cast<int>(altStreamType), node->getPath().c_str());
debug(5, "FSDirectory::createReadStreamForMemberAltStream('%s', %i) -> '%s'", path.toString(Common::Path::kNativeSeparator).c_str(), static_cast<int>(altStreamType), node->getPath().toString(Common::Path::kNativeSeparator).c_str());
SeekableReadStream *stream = node->createReadStreamForAltStream(altStreamType);
if (!stream)
warning("FSDirectory::createReadStreamForMemberAltStream: Can't create stream for file '%s' alt stream type %i", Common::toPrintable(path.toString()).c_str(), static_cast<int>(altStreamType));
warning("FSDirectory::createReadStreamForMemberAltStream: Can't create stream for file '%s' alt stream type %i", Common::toPrintable(path.toString(Common::Path::kNativeSeparator)).c_str(), static_cast<int>(altStreamType));
return stream;
}
@ -413,7 +413,7 @@ FSDirectory *FSDirectory::getSubDirectory(const Path &name, int depth, bool flat
FSDirectory *FSDirectory::getSubDirectory(const Path &prefix, const Path &name, int depth,
bool flat, bool ignoreClashes) {
if (name.toString().empty() || !_node.isDirectory())
if (name.empty() || !_node.isDirectory())
return nullptr;
FSNode *node = lookupCache(_subDirCache, name);
@ -440,12 +440,12 @@ void FSDirectory::cacheDirectoryRecursive(FSNode node, int depth, const Path& pr
// Always warn in this case as it's when there are 2 directories at the same place with different case
// That means a problem in user installation as lookups are always done case insensitive
warning("FSDirectory::cacheDirectory: name clash when building cache, ignoring sub-directory '%s'",
Common::toPrintable(name.toString('/')).c_str());
Common::toPrintable(name.toString(Common::Path::kNativeSeparator)).c_str());
} else {
if (_subDirCache.contains(name)) {
if (!_ignoreClashes) {
warning("FSDirectory::cacheDirectory: name clash when building subDirCache with subdirectory '%s'",
Common::toPrintable(name.toString('/')).c_str());
Common::toPrintable(name.toString(Common::Path::kNativeSeparator)).c_str());
}
}
cacheDirectoryRecursive(*it, depth - 1, _flat ? prefix : name);
@ -455,7 +455,7 @@ void FSDirectory::cacheDirectoryRecursive(FSNode node, int depth, const Path& pr
if (_fileCache.contains(name)) {
if (!_ignoreClashes) {
warning("FSDirectory::cacheDirectory: name clash when building cache, ignoring file '%s'",
Common::toPrintable(name.toString('/')).c_str());
Common::toPrintable(name.toString(Common::Path::kNativeSeparator)).c_str());
}
} else
_fileCache[name] = *it;

View File

@ -49,6 +49,31 @@ class SeekableReadStream;
class WriteStream;
class SeekableWriteStream;
/**
* A minimal and temporary class which can act like a Path and like a String
* This is used to ease transition of getPath() from String to Path
* FIXME: Remove this class when it's not needed anymore
*/
class PathProxy : public Path {
private:
String str() const { return toString(Path::kNativeSeparator); }
public:
using Path::Path;
operator String() const { return str(); };
operator U32String() const { return decode(); }
const char *c_str() const { return str().c_str(); }
U32String decode(CodePage page = kUtf8) const { return str().decode(page); }
bool matchString(const char *pat, bool ignoreCase = false, const char *wildcardExclusions = NULL) const {
return str().matchString(pat, ignoreCase, wildcardExclusions);
}
String substr(size_t pos = 0, size_t len = String::npos) const {
return str().substr(pos, len);
}
};
/**
* List of multiple file system nodes. For example, the contents of a given directory.
* This is a subclass instead of just a typedef so that forward declarations
@ -181,7 +206,7 @@ public:
*
* @return The file name.
*/
Common::Path getPathInArchive() const override;
Path getPathInArchive() const override;
/**
* Return a string representation of the name of the file, without any
@ -194,18 +219,14 @@ public:
virtual String getRealName() const;
/**
* Return a string representation of the file that is suitable for
* archiving (i.e. writing to the config file). This will usually be a
* 'path' (hence the name of the method), but can be anything that meets
* the above criteria. What a 'path' is differs greatly from system to
* Return a path representation of the file that is suitable for
* archiving (i.e. writing to the config file).
* What a 'path' is differs greatly from system to
* system.
*
* @note Do not assume that this string contains (back)slashes or any
* other kind of 'path separators'.
*
* @return The 'path' represented by this file system node.
*/
String getPath() const;
PathProxy getPath() const;
/**
* Get the parent node of this node. If this node has no parent node,