[Scummvm-git-logs] scummvm master -> a690a034cf105bd16d5c74f208b5496a77997a68
phcoder
noreply at scummvm.org
Wed Dec 14 04:08:54 UTC 2022
This automated email contains information about 12 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
af7d9cb850 COMMON: Move punycode_*codepath to path.cpp
d02a25230d COMMON: Add appendComponent to Common::Path for convenience
ce55430f1c COMMON: Don't access DIR_SEPARATOR in macresman
43d7259ff9 COMMON: Add matchPattern method for Common::Path
ab517cc577 COMMON: Add case-insensitive comparator and hash for Common::Path
78b6e60057 COMMON: Change common/fs to use Common::Path as key
4a2e69f990 COMMON: conflate : and / in mac names.
7ded5c2de0 COMMON: Move DIR_SEPARATOR into path.cpp
97bc2d843a SCI: Don't use rawString
f3daf65116 GOB: Don't use rawString.
673e5e025b COMMON: Remove rawString member for Common::Path
a690a034cf COMMON: Remove reliance that \x1f is never part of filename
Commit: af7d9cb850b67194351a53468619ead3fa632023
https://github.com/scummvm/scummvm/commit/af7d9cb850b67194351a53468619ead3fa632023
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2022-12-14T05:08:46+01:00
Commit Message:
COMMON: Move punycode_*codepath to path.cpp
This allows to reduce access to DIR_SEPARATOR from outside of Common::Path
Changed paths:
common/path.cpp
common/path.h
common/punycode.cpp
common/punycode.h
engines/director/director.cpp
engines/director/util.cpp
engines/wage/wage.cpp
diff --git a/common/path.cpp b/common/path.cpp
index e152fa3f80b..459fea5389b 100644
--- a/common/path.cpp
+++ b/common/path.cpp
@@ -20,6 +20,8 @@
*/
#include "common/path.h"
+#include "common/tokenizer.h"
+#include "common/punycode.h"
namespace Common {
@@ -53,7 +55,7 @@ Path Path::getParent() const {
if (_str.size() < 2)
return Path();
size_t separatorPos = _str.findLastOf(DIR_SEPARATOR, _str.size() - 2);
- if (separatorPos == Common::String::npos)
+ if (separatorPos == String::npos)
return Path();
return Path(_str.substr(0, separatorPos + 1), DIR_SEPARATOR);
}
@@ -62,7 +64,7 @@ Path Path::getLastComponent() const {
if (_str.size() < 2)
return *this;
size_t separatorPos = _str.findLastOf(DIR_SEPARATOR, _str.size() - 2);
- if (separatorPos == Common::String::npos)
+ if (separatorPos == String::npos)
return *this;
return Path(_str.substr(separatorPos + 1), DIR_SEPARATOR);
}
@@ -182,4 +184,35 @@ Path Path::join(const char *str, char separator) const {
return temp;
}
+Path Path::punycodeDecode() const {
+ StringTokenizer tok(rawString(), String(DIR_SEPARATOR));
+ String res;
+
+ while (!tok.empty()) {
+ res += punycode_decodefilename(tok.nextToken());
+ if (!tok.empty())
+ res += DIR_SEPARATOR;
+ }
+
+ return Path(res, DIR_SEPARATOR);
+}
+
+Path Path::punycodeEncode() const {
+ StringTokenizer tok(rawString(), String(DIR_SEPARATOR));
+ String res;
+
+ while (!tok.empty()) {
+ String part = tok.nextToken();
+ if (punycode_needEncode(part))
+ res += punycode_encodefilename(part);
+ else
+ res += part;
+
+ if (!tok.empty())
+ res += DIR_SEPARATOR;
+ }
+
+ return Path(res, DIR_SEPARATOR);
+}
+
} // End of namespace Common
diff --git a/common/path.h b/common/path.h
index cc5b214d394..1c9c2941c09 100644
--- a/common/path.h
+++ b/common/path.h
@@ -175,6 +175,16 @@ public:
/** @overload */
Path join(const char *str, char separator = '/') const;
+
+ /**
+ * Convert path from Punycode
+ */
+ Path punycodeDecode() const;
+
+ /**
+ * Convert path to Punycode
+ */
+ Path punycodeEncode() const;
};
/** @} */
diff --git a/common/punycode.cpp b/common/punycode.cpp
index 76ff100b0fa..c894db4c002 100644
--- a/common/punycode.cpp
+++ b/common/punycode.cpp
@@ -43,7 +43,6 @@
#include "common/punycode.h"
#include "common/debug.h"
-#include "common/tokenizer.h"
#include "common/util.h"
namespace Common {
@@ -412,35 +411,4 @@ U32String punycode_decodefilename(const String &src1) {
return dst;
}
-Path punycode_decodepath(const Path &src) {
- StringTokenizer tok(src.rawString(), Common::String(DIR_SEPARATOR));
- String res;
-
- while (!tok.empty()) {
- res += punycode_decodefilename(tok.nextToken());
- if (!tok.empty())
- res += DIR_SEPARATOR;
- }
-
- return Path(res, DIR_SEPARATOR);
-}
-
-Path punycode_encodepath(const Path &src) {
- StringTokenizer tok(src.rawString(), Common::String(DIR_SEPARATOR));
- String res;
-
- while (!tok.empty()) {
- String part = tok.nextToken();
- if (punycode_needEncode(part))
- res += punycode_encodefilename(part);
- else
- res += part;
-
- if (!tok.empty())
- res += DIR_SEPARATOR;
- }
-
- return Path(res, DIR_SEPARATOR);
-}
-
} // end of namespace Common
diff --git a/common/punycode.h b/common/punycode.h
index 822a11b5a54..cad4f32408b 100644
--- a/common/punycode.h
+++ b/common/punycode.h
@@ -65,16 +65,6 @@ String punycode_encodefilename(const U32String &src1);
*/
U32String punycode_decodefilename(const String &src1);
-/**
- * Convert path from Punycode
- */
-Path punycode_decodepath(const Path &src);
-
-/**
- * Convert path to Punycode
- */
-Path punycode_encodepath(const Path &src);
-
bool punycode_hasprefix(const String &src);
bool punycode_needEncode(const String &src);
diff --git a/engines/director/director.cpp b/engines/director/director.cpp
index 2f4f74a6caa..9c3c7ce8273 100644
--- a/engines/director/director.cpp
+++ b/engines/director/director.cpp
@@ -323,7 +323,7 @@ void DirectorEngine::parseOptions() {
_options.startMovie.startFrame = atoi(tail.c_str());
}
- _options.startMovie.startMovie = Common::punycode_decodepath(_options.startMovie.startMovie).toString(_dirSeparator);
+ _options.startMovie.startMovie = Common::Path(_options.startMovie.startMovie).punycodeDecode().toString(_dirSeparator);
debug(2, "parseOptions(): Movie is: %s, frame is: %d", _options.startMovie.startMovie.c_str(), _options.startMovie.startFrame);
} else if (key == "startup") {
diff --git a/engines/director/util.cpp b/engines/director/util.cpp
index 464b963681a..acb4d0376f6 100644
--- a/engines/director/util.cpp
+++ b/engines/director/util.cpp
@@ -1015,7 +1015,7 @@ Common::u32char_type_t numToChar(int num) {
}
Common::String encodePathForDump(const Common::String &path) {
- return punycode_encodepath(Common::Path(path, g_director->_dirSeparator)).toString();
+ return Common::Path(path, g_director->_dirSeparator).punycodeEncode().toString();
}
Common::String utf8ToPrintable(const Common::String &str) {
diff --git a/engines/wage/wage.cpp b/engines/wage/wage.cpp
index 13837a1f53e..5fec12182c8 100644
--- a/engines/wage/wage.cpp
+++ b/engines/wage/wage.cpp
@@ -124,7 +124,7 @@ Common::Error WageEngine::run() {
// Your main event loop should be (invoked from) here.
_resManager = new Common::MacResManager();
- if (!_resManager->open(Common::punycode_decodepath(getGameFile()).toString('/')))
+ if (!_resManager->open(Common::Path(getGameFile()).punycodeDecode().toString('/')))
error("Could not open %s as a resource fork", getGameFile());
_world = new World(this);
Commit: d02a25230d5c98afa2a24b4bada1b2796c030d18
https://github.com/scummvm/scummvm/commit/d02a25230d5c98afa2a24b4bada1b2796c030d18
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2022-12-14T05:08:46+01:00
Commit Message:
COMMON: Add appendComponent to Common::Path for convenience
Changed paths:
common/path.cpp
common/path.h
diff --git a/common/path.cpp b/common/path.cpp
index 459fea5389b..736a8972fb8 100644
--- a/common/path.cpp
+++ b/common/path.cpp
@@ -69,6 +69,16 @@ Path Path::getLastComponent() const {
return Path(_str.substr(separatorPos + 1), DIR_SEPARATOR);
}
+Path Path::appendComponent(const String &x) const {
+ if (x.empty())
+ return *this;
+ String str = _str;
+ if (!str.empty() && str.lastChar() != DIR_SEPARATOR)
+ str += DIR_SEPARATOR;
+ str += x;
+ return Path(str, DIR_SEPARATOR);
+}
+
bool Path::operator==(const Path &x) const {
return _str == x.rawString();
}
diff --git a/common/path.h b/common/path.h
index 1c9c2941c09..6ce0418b3bb 100644
--- a/common/path.h
+++ b/common/path.h
@@ -151,6 +151,11 @@ public:
/** @overload */
Path append(const char *str, char separator = '/') const;
+ /**
+ * Appends exactly one component, without any separators
+ * and prepends a separator if necessarry
+ */
+ Path appendComponent(const String &x) const;
/**
* Joins the given path to this path (in-place).
Commit: ce55430f1c2d68dedb7ca1cfb99eeebe54ee427e
https://github.com/scummvm/scummvm/commit/ce55430f1c2d68dedb7ca1cfb99eeebe54ee427e
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2022-12-14T05:08:46+01:00
Commit Message:
COMMON: Don't access DIR_SEPARATOR in macresman
DIR_SEPARATOR is an implementation detail of Common::Path, it should not
be accessed outside of it. Use public functions that do the same instead
Changed paths:
common/macresman.cpp
diff --git a/common/macresman.cpp b/common/macresman.cpp
index b4556dd02f3..4cf244d9d8e 100644
--- a/common/macresman.cpp
+++ b/common/macresman.cpp
@@ -875,19 +875,9 @@ void MacResManager::readMap() {
Path MacResManager::constructAppleDoubleName(Path name) {
// Insert "._" before the last portion of a path name
- String rawName = name.rawString();
- for (int i = rawName.size() - 1; i >= 0; i--) {
- if (i == 0) {
- rawName.insertChar('_', 0);
- rawName.insertChar('.', 0);
- } else if (rawName[i] == DIR_SEPARATOR) {
- rawName.insertChar('_', i + 1);
- rawName.insertChar('.', i + 1);
- break;
- }
- }
-
- return Path(rawName, DIR_SEPARATOR);
+ Path parent = name.getParent();
+ Path lastComponent = name.getLastComponent();
+ return parent.append("._").append(lastComponent);
}
Path MacResManager::disassembleAppleDoubleName(Path name, bool *isAppleDouble) {
@@ -896,27 +886,12 @@ Path MacResManager::disassembleAppleDoubleName(Path name, bool *isAppleDouble) {
}
// Remove "._" before the last portion of a path name.
- String rawName = name.rawString();
- for (int i = rawName.size() - 1; i >= 0; --i) {
- if (i == 0) {
- if (rawName.size() > 2 && rawName[0] == '.' && rawName[1] == '_') {
- rawName.erase(0, 2);
- if (isAppleDouble) {
- *isAppleDouble = true;
- }
- }
- } else if (rawName[i] == DIR_SEPARATOR) {
- if ((uint)(i + 2) < rawName.size() && rawName[i + 1] == '.' && rawName[i + 2] == '_') {
- rawName.erase(i + 1, 2);
- if (isAppleDouble) {
- *isAppleDouble = true;
- }
- }
- break;
- }
- }
-
- return Path(rawName, DIR_SEPARATOR);
+ Path parent = name.getParent();
+ Path lastComponent = name.getLastComponent();
+ String lastComponentString = lastComponent.toString();
+ if (!lastComponentString.hasPrefix("._"))
+ return name;
+ return parent.appendComponent(lastComponentString.substr(2));
}
void MacResManager::dumpRaw() {
Commit: 43d7259ff9456b812980f303809997975caef2fb
https://github.com/scummvm/scummvm/commit/43d7259ff9456b812980f303809997975caef2fb
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2022-12-14T05:08:46+01:00
Commit Message:
COMMON: Add matchPattern method for Common::Path
Changed paths:
common/path.cpp
common/path.h
diff --git a/common/path.cpp b/common/path.cpp
index 736a8972fb8..97c72e74441 100644
--- a/common/path.cpp
+++ b/common/path.cpp
@@ -225,4 +225,11 @@ Path Path::punycodeEncode() const {
return Path(res, DIR_SEPARATOR);
}
+bool Path::matchPattern(const Path& pattern) const {
+ // Prevent wildcards from matching the directory separator.
+ const char wildcardExclusions[] = { DIR_SEPARATOR, '\0' };
+
+ return punycodeDecode()._str.matchString(pattern.punycodeDecode()._str, true, wildcardExclusions);
+}
+
} // End of namespace Common
diff --git a/common/path.h b/common/path.h
index 6ce0418b3bb..6d333285b12 100644
--- a/common/path.h
+++ b/common/path.h
@@ -190,6 +190,11 @@ public:
* Convert path to Punycode
*/
Path punycodeEncode() const;
+
+ /**
+ * Check pattern match similar matchString
+ */
+ bool matchPattern(const Path& pattern) const;
};
/** @} */
Commit: ab517cc577d4eba17d5b79d29132924800cc11a3
https://github.com/scummvm/scummvm/commit/ab517cc577d4eba17d5b79d29132924800cc11a3
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2022-12-14T05:08:46+01:00
Commit Message:
COMMON: Add case-insensitive comparator and hash for Common::Path
Changed paths:
common/path.cpp
common/path.h
diff --git a/common/path.cpp b/common/path.cpp
index 97c72e74441..82a596f6eb5 100644
--- a/common/path.cpp
+++ b/common/path.cpp
@@ -22,6 +22,7 @@
#include "common/path.h"
#include "common/tokenizer.h"
#include "common/punycode.h"
+#include "common/hash-str.h"
namespace Common {
@@ -232,4 +233,12 @@ bool Path::matchPattern(const Path& pattern) const {
return punycodeDecode()._str.matchString(pattern.punycodeDecode()._str, true, wildcardExclusions);
}
+bool Path::IgnoreCaseAndMac_EqualsTo::operator()(const Path& x, const Path& y) const {
+ return x.punycodeDecode()._str.equalsIgnoreCase(y.punycodeDecode()._str);
+}
+
+uint Path::IgnoreCaseAndMac_Hash::operator()(const Path& x) const {
+ return hashit_lower(x.punycodeDecode()._str.c_str());
+}
+
} // End of namespace Common
diff --git a/common/path.h b/common/path.h
index 6d333285b12..1e0f1a6addf 100644
--- a/common/path.h
+++ b/common/path.h
@@ -52,6 +52,23 @@ private:
String _str;
public:
+ /**
+ * Hash and comparator for Path with following changes:
+ * * case-insensitive
+ * * decoding of punycode
+ * * Matching ':' and '/' inside path components to
+ * This allows a path "Sound Manager 3.1 / SoundLib<separator>Sound"
+ * to match both "xn--Sound Manager 3.1 SoundLib-lba84k/Sound"
+ * and "Sound Manager 3.1 : SoundLib/Sound"
+ */
+ struct IgnoreCaseAndMac_EqualsTo {
+ bool operator()(const Path& x, const Path& y) const;
+ };
+
+ struct IgnoreCaseAndMac_Hash {
+ uint operator()(const Path& x) const;
+ };
+
/** Construct a new empty path. */
Path() {}
Commit: 78b6e60057ad5ac7043d7710286fe5428de278e5
https://github.com/scummvm/scummvm/commit/78b6e60057ad5ac7043d7710286fe5428de278e5
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2022-12-14T05:08:46+01:00
Commit Message:
COMMON: Change common/fs to use Common::Path as key
Changed paths:
common/fs.cpp
common/fs.h
diff --git a/common/fs.cpp b/common/fs.cpp
index cb67c45b12f..74a7c53cf1f 100644
--- a/common/fs.cpp
+++ b/common/fs.cpp
@@ -97,6 +97,11 @@ String FSNode::getName() const {
return punycode_decodefilename(_realNode->getName());
}
+String FSNode::getRealName() const {
+ assert(_realNode);
+ return _realNode->getName();
+}
+
FSNode FSNode::getParent() const {
if (_realNode == nullptr)
return *this;
@@ -179,7 +184,7 @@ FSDirectory::FSDirectory(const Path &prefix, const FSNode &node, int depth, bool
: _node(node), _cached(false), _depth(depth), _flat(flat), _ignoreClashes(ignoreClashes),
_includeDirectories(includeDirectories) {
- setPrefix(prefix.rawString());
+ setPrefix(prefix);
}
FSDirectory::FSDirectory(const Path &name, int depth, bool flat, bool ignoreClashes, bool includeDirectories)
@@ -192,24 +197,21 @@ FSDirectory::FSDirectory(const Path &prefix, const Path &name, int depth, bool f
: _node(name), _cached(false), _depth(depth), _flat(flat), _ignoreClashes(ignoreClashes),
_includeDirectories(includeDirectories) {
- setPrefix(prefix.rawString());
+ setPrefix(prefix);
}
FSDirectory::~FSDirectory() {
}
-void FSDirectory::setPrefix(const String &prefix) {
+void FSDirectory::setPrefix(const Path &prefix) {
_prefix = prefix;
-
- if (!_prefix.empty() && _prefix.lastChar() != DIR_SEPARATOR)
- _prefix += DIR_SEPARATOR;
}
FSNode FSDirectory::getFSNode() const {
return _node;
}
-FSNode *FSDirectory::lookupCache(NodeCache &cache, const String &name) const {
+FSNode *FSDirectory::lookupCache(NodeCache &cache, const Path &name) const {
// make caching as lazy as possible
if (!name.empty()) {
ensureCached();
@@ -222,26 +224,24 @@ FSNode *FSDirectory::lookupCache(NodeCache &cache, const String &name) const {
}
bool FSDirectory::hasFile(const Path &path) const {
- String name = path.rawString();
- if (name.empty() || !_node.isDirectory())
+ if (path.toString().empty() || !_node.isDirectory())
return false;
- FSNode *node = lookupCache(_fileCache, name);
+ FSNode *node = lookupCache(_fileCache, path);
return node && node->exists();
}
const ArchiveMemberPtr FSDirectory::getMember(const Path &path) const {
- String name = path.rawString();
- if (name.empty() || !_node.isDirectory())
+ if (path.toString().empty() || !_node.isDirectory())
return ArchiveMemberPtr();
- FSNode *node = lookupCache(_fileCache, name);
+ FSNode *node = lookupCache(_fileCache, path);
if (!node || !node->exists()) {
- warning("FSDirectory::getMember: '%s' does not exist", Common::toPrintable(name).c_str());
+ warning("FSDirectory::getMember: '%s' does not exist", Common::toPrintable(path.toString()).c_str());
return ArchiveMemberPtr();
} else if (node->isDirectory()) {
- warning("FSDirectory::getMember: '%s' is a directory", Common::toPrintable(name).c_str());
+ warning("FSDirectory::getMember: '%s' is a directory", Common::toPrintable(path.toString()).c_str());
return ArchiveMemberPtr();
}
@@ -249,16 +249,15 @@ const ArchiveMemberPtr FSDirectory::getMember(const Path &path) const {
}
SeekableReadStream *FSDirectory::createReadStreamForMember(const Path &path) const {
- String name = path.rawString();
- if (name.empty() || !_node.isDirectory())
+ if (path.toString().empty() || !_node.isDirectory())
return nullptr;
- FSNode *node = lookupCache(_fileCache, name);
+ FSNode *node = lookupCache(_fileCache, path);
if (!node)
return nullptr;
SeekableReadStream *stream = node->createReadStream();
if (!stream)
- warning("FSDirectory::createReadStreamForMember: Can't create stream for file '%s'", Common::toPrintable(name).c_str());
+ warning("FSDirectory::createReadStreamForMember: Can't create stream for file '%s'", Common::toPrintable(path.toString()).c_str());
return stream;
}
@@ -269,11 +268,10 @@ 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) {
- String rawName = name.rawString();
- if (rawName.empty() || !_node.isDirectory())
+ if (name.toString().empty() || !_node.isDirectory())
return nullptr;
- FSNode *node = lookupCache(_subDirCache, rawName);
+ FSNode *node = lookupCache(_subDirCache, name);
if (!node)
return nullptr;
@@ -289,37 +287,33 @@ void FSDirectory::cacheDirectoryRecursive(FSNode node, int depth, const Path& pr
FSList::iterator it = list.begin();
for ( ; it != list.end(); ++it) {
- String name = prefix.rawString() + it->getName();
-
- // don't touch name as it might be used for warning messages
- String lowercaseName = name;
- lowercaseName.toLowercase();
+ Path name = prefix.appendComponent(it->getRealName());
// since the hashmap is case insensitive, we need to check for clashes when caching
if (it->isDirectory()) {
- if (!_flat && _subDirCache.contains(lowercaseName)) {
+ if (!_flat && _subDirCache.contains(name)) {
// 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).c_str());
+ Common::toPrintable(name.toString('/')).c_str());
} else {
- if (_subDirCache.contains(lowercaseName)) {
+ if (_subDirCache.contains(name)) {
if (!_ignoreClashes) {
warning("FSDirectory::cacheDirectory: name clash when building subDirCache with subdirectory '%s'",
- Common::toPrintable(name).c_str());
+ Common::toPrintable(name.toString('/')).c_str());
}
}
- cacheDirectoryRecursive(*it, depth - 1, _flat ? prefix : Common::Path(lowercaseName + DIR_SEPARATOR, DIR_SEPARATOR));
- _subDirCache[lowercaseName] = *it;
+ cacheDirectoryRecursive(*it, depth - 1, _flat ? prefix : name);
+ _subDirCache[name] = *it;
}
} else {
- if (_fileCache.contains(lowercaseName)) {
+ if (_fileCache.contains(name)) {
if (!_ignoreClashes) {
warning("FSDirectory::cacheDirectory: name clash when building cache, ignoring file '%s'",
- Common::toPrintable(name).c_str());
+ Common::toPrintable(name.toString('/')).c_str());
}
} else {
- _fileCache[lowercaseName] = *it;
+ _fileCache[name] = *it;
}
}
}
@@ -340,24 +334,16 @@ int FSDirectory::listMatchingMembers(ArchiveMemberList &list, const Path &patter
// Cache dir data
ensureCached();
- // need to match lowercase key, since all entries in our file cache are
- // stored as lowercase.
- String lowercasePattern(pattern.rawString());
- lowercasePattern.toLowercase();
-
- // Prevent wildcards from matching the directory separator.
- const char wildcardExclusions[] = { DIR_SEPARATOR, '\0' };
-
int matches = 0;
for (NodeCache::const_iterator it = _fileCache.begin(); it != _fileCache.end(); ++it) {
- if (it->_key.matchString(lowercasePattern, false, wildcardExclusions)) {
+ if (it->_key.matchPattern(pattern)) {
list.push_back(ArchiveMemberPtr(new FSNode(it->_value)));
matches++;
}
}
if (_includeDirectories) {
for (NodeCache::const_iterator it = _subDirCache.begin(); it != _subDirCache.end(); ++it) {
- if (it->_key.matchString(lowercasePattern, false, wildcardExclusions)) {
+ if (it->_key.matchPattern(pattern)) {
list.push_back(ArchiveMemberPtr(new FSNode(it->_value)));
matches++;
}
diff --git a/common/fs.h b/common/fs.h
index 57521cbb53f..384a84a106e 100644
--- a/common/fs.h
+++ b/common/fs.h
@@ -44,6 +44,7 @@ namespace Common {
*/
class FSNode;
+class FSDirectory;
class SeekableReadStream;
class WriteStream;
class SeekableWriteStream;
@@ -68,6 +69,7 @@ class FSList : public Array<FSNode> {};
class FSNode : public ArchiveMember {
private:
friend class ::AbstractFSNode;
+ friend class FSDirectory;
SharedPtr<AbstractFSNode> _realNode;
/**
* Construct an FSNode from a backend's AbstractFSNode implementation.
@@ -77,6 +79,7 @@ private:
*/
FSNode(AbstractFSNode *realNode);
+ String getRealName() const;
public:
/**
* Flag to tell listDir() which kind of files to list.
@@ -301,17 +304,17 @@ class FSDirectory : public Archive {
bool _ignoreClashes;
bool _includeDirectories;
- String _prefix; // string that is prepended to each cache item key
- void setPrefix(const String &prefix);
+ Path _prefix; // string that is prepended to each cache item key
+ void setPrefix(const Path &prefix);
// Caches are case insensitive, clashes are dealt with when creating
// Key is stored in lowercase.
- typedef HashMap<String, FSNode, IgnoreCase_Hash, IgnoreCase_EqualTo> NodeCache;
+ typedef HashMap<Path, FSNode, Path::IgnoreCaseAndMac_Hash, Path::IgnoreCaseAndMac_EqualsTo> NodeCache;
mutable NodeCache _fileCache, _subDirCache;
mutable bool _cached;
// look for a match
- FSNode *lookupCache(NodeCache &cache, const String &name) const;
+ FSNode *lookupCache(NodeCache &cache, const Path &name) const;
// cache management
void cacheDirectoryRecursive(FSNode node, int depth, const Path& prefix) const;
Commit: 4a2e69f99094f5c95c827ce65cfa07fe6c161c0c
https://github.com/scummvm/scummvm/commit/4a2e69f99094f5c95c827ce65cfa07fe6c161c0c
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2022-12-14T05:08:46+01:00
Commit Message:
COMMON: conflate : and / in mac names.
When using mounted images on OSX or with fusehfs : and / are swapped.
When using dumper-companion it encodes / in punycode and preserves it.
Changed paths:
common/path.cpp
common/path.h
diff --git a/common/path.cpp b/common/path.cpp
index 82a596f6eb5..2c2e7b2a646 100644
--- a/common/path.cpp
+++ b/common/path.cpp
@@ -208,6 +208,24 @@ Path Path::punycodeDecode() const {
return Path(res, DIR_SEPARATOR);
}
+String Path::getIdentifierString() const {
+ StringTokenizer tok(rawString(), String(DIR_SEPARATOR));
+ String res;
+
+ while (!tok.empty()) {
+ String part = punycode_decodefilename(tok.nextToken());
+ for (uint i = 0; i < part.size(); i++)
+ if (part[i] == '/')
+ res += ':';
+ else
+ res += part[i];
+ if (!tok.empty())
+ res += DIR_SEPARATOR;
+ }
+
+ return res;
+}
+
Path Path::punycodeEncode() const {
StringTokenizer tok(rawString(), String(DIR_SEPARATOR));
String res;
@@ -230,15 +248,15 @@ bool Path::matchPattern(const Path& pattern) const {
// Prevent wildcards from matching the directory separator.
const char wildcardExclusions[] = { DIR_SEPARATOR, '\0' };
- return punycodeDecode()._str.matchString(pattern.punycodeDecode()._str, true, wildcardExclusions);
+ return getIdentifierString().matchString(pattern.getIdentifierString(), true, wildcardExclusions);
}
bool Path::IgnoreCaseAndMac_EqualsTo::operator()(const Path& x, const Path& y) const {
- return x.punycodeDecode()._str.equalsIgnoreCase(y.punycodeDecode()._str);
+ return x.getIdentifierString().equalsIgnoreCase(y.getIdentifierString());
}
uint Path::IgnoreCaseAndMac_Hash::operator()(const Path& x) const {
- return hashit_lower(x.punycodeDecode()._str.c_str());
+ return hashit_lower(x.getIdentifierString().c_str());
}
} // End of namespace Common
diff --git a/common/path.h b/common/path.h
index 1e0f1a6addf..db98ba6a10e 100644
--- a/common/path.h
+++ b/common/path.h
@@ -51,6 +51,7 @@ class Path {
private:
String _str;
+ String getIdentifierString() const;
public:
/**
* Hash and comparator for Path with following changes:
Commit: 7ded5c2de0f3808487016c70568bdff60495bc44
https://github.com/scummvm/scummvm/commit/7ded5c2de0f3808487016c70568bdff60495bc44
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2022-12-14T05:08:46+01:00
Commit Message:
COMMON: Move DIR_SEPARATOR into path.cpp
Changed paths:
common/path.cpp
common/path.h
diff --git a/common/path.cpp b/common/path.cpp
index 2c2e7b2a646..1fbf09d4b8d 100644
--- a/common/path.cpp
+++ b/common/path.cpp
@@ -24,6 +24,8 @@
#include "common/punycode.h"
#include "common/hash-str.h"
+const char DIR_SEPARATOR = '\x1f'; // unit separator
+
namespace Common {
Path::Path(const Path &path) {
diff --git a/common/path.h b/common/path.h
index db98ba6a10e..1123cf41e59 100644
--- a/common/path.h
+++ b/common/path.h
@@ -36,8 +36,6 @@ namespace Common {
* @{
*/
-const char DIR_SEPARATOR = '\x1f'; // unit separator
-
/**
* Simple path class. Allows simple conversion to/from path strings with
* arbitrary directory separators, providing a common representation.
Commit: 97bc2d843a5fe73174695094bad132abe78c8e5c
https://github.com/scummvm/scummvm/commit/97bc2d843a5fe73174695094bad132abe78c8e5c
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2022-12-14T05:08:46+01:00
Commit Message:
SCI: Don't use rawString
Changed paths:
engines/sci/graphics/macfont.cpp
diff --git a/engines/sci/graphics/macfont.cpp b/engines/sci/graphics/macfont.cpp
index 12da36e83e9..206aeb95207 100644
--- a/engines/sci/graphics/macfont.cpp
+++ b/engines/sci/graphics/macfont.cpp
@@ -81,7 +81,7 @@ GfxMacFontManager::~GfxMacFontManager() {
bool GfxMacFontManager::initFromFontTable(Common::MacResManager *macExecutable) {
Common::SeekableReadStream *table = macExecutable->getResource(MKTAG('f', 't', 'b', 'l'), 128);
if (table == nullptr) {
- warning("Mac font table not found in \"%s\"", macExecutable->getBaseFileName().rawString().c_str());
+ warning("Mac font table not found in \"%s\"", macExecutable->getBaseFileName().toString(':').c_str());
return false;
}
@@ -89,14 +89,14 @@ bool GfxMacFontManager::initFromFontTable(Common::MacResManager *macExecutable)
uint16 defaultFontIndex = table->readUint16BE();
uint16 numberOfFonts = table->readUint16BE();
if (table->eos() || table->size() < 4 + numberOfFonts * 10) {
- warning("Invalid mac font table in \"%s\"", macExecutable->getBaseFileName().rawString().c_str());
+ warning("Invalid mac font table in \"%s\"", macExecutable->getBaseFileName().toString(':').c_str());
return false;
}
for (uint16 i = 0; i < numberOfFonts; ++i) {
uint16 sciFontId = table->readUint16BE();
if (_macFonts.contains(sciFontId)) {
- warning("Duplicate Mac font table entry for %d in \"%s\"", sciFontId, macExecutable->getBaseFileName().rawString().c_str());
+ warning("Duplicate Mac font table entry for %d in \"%s\"", sciFontId, macExecutable->getBaseFileName().toString(':').c_str());
return false;
}
uint16 macFontId = table->readUint16BE();
@@ -107,7 +107,7 @@ bool GfxMacFontManager::initFromFontTable(Common::MacResManager *macExecutable)
const Graphics::Font *smallFont = getMacFont(macFontId, smallFontSize);
const Graphics::Font *largeFont = getMacFont(macFontId, MAX(mediumFontSize, largeFontSize));
if (smallFont == nullptr || largeFont == nullptr) {
- warning("Mac font %d not found in \"%s\"", macFontId, macExecutable->getBaseFileName().rawString().c_str());
+ warning("Mac font %d not found in \"%s\"", macFontId, macExecutable->getBaseFileName().toString(':').c_str());
return false;
}
Commit: f3daf651169dc0d479600b62d114e17e2aaa8b6b
https://github.com/scummvm/scummvm/commit/f3daf651169dc0d479600b62d114e17e2aaa8b6b
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2022-12-14T05:08:46+01:00
Commit Message:
GOB: Don't use rawString.
The result is being fed to File::open so \x1f and / get conflated later anyway,
so toString('/') has exactly the same effect.
Changed paths:
engines/gob/inter_v1.cpp
diff --git a/engines/gob/inter_v1.cpp b/engines/gob/inter_v1.cpp
index 9d89998e734..5151581e709 100644
--- a/engines/gob/inter_v1.cpp
+++ b/engines/gob/inter_v1.cpp
@@ -1835,7 +1835,7 @@ void Inter_v1::o1_manageDataFile(OpFuncParams ¶ms) {
Common::String file = _vm->_game->_script->evalString();
if (!file.empty()) {
- _vm->_dataIO->openArchive(Common::Path(file, '\\').rawString(), true);
+ _vm->_dataIO->openArchive(Common::Path(file, '\\').toString('/'), true);
} else {
_vm->_dataIO->closeArchive(true);
Commit: 673e5e025b707fc7259fc35d1442e605f5fb9366
https://github.com/scummvm/scummvm/commit/673e5e025b707fc7259fc35d1442e605f5fb9366
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2022-12-14T05:08:46+01:00
Commit Message:
COMMON: Remove rawString member for Common::Path
Changed paths:
common/path.cpp
common/path.h
diff --git a/common/path.cpp b/common/path.cpp
index 1fbf09d4b8d..98432c0ab22 100644
--- a/common/path.cpp
+++ b/common/path.cpp
@@ -29,7 +29,7 @@ const char DIR_SEPARATOR = '\x1f'; // unit separator
namespace Common {
Path::Path(const Path &path) {
- _str = path.rawString();
+ _str = path._str;
}
Path::Path(const char *str, char separator) {
@@ -83,11 +83,11 @@ Path Path::appendComponent(const String &x) const {
}
bool Path::operator==(const Path &x) const {
- return _str == x.rawString();
+ return _str == x._str;
}
bool Path::operator!=(const Path &x) const {
- return _str != x.rawString();
+ return _str != x._str;
}
bool Path::empty() const {
@@ -95,7 +95,7 @@ bool Path::empty() const {
}
Path &Path::operator=(const Path &path) {
- _str = path.rawString();
+ _str = path._str;
return *this;
}
@@ -115,7 +115,7 @@ void Path::set(const char *str, char separator) {
}
Path &Path::appendInPlace(const Path &x) {
- _str += x.rawString();
+ _str += x._str;
return *this;
}
@@ -157,10 +157,10 @@ Path &Path::joinInPlace(const Path &x) {
if (x.empty())
return *this;
- if (!_str.empty() && _str.lastChar() != DIR_SEPARATOR && x.rawString().firstChar() != DIR_SEPARATOR)
+ if (!_str.empty() && _str.lastChar() != DIR_SEPARATOR && x._str.firstChar() != DIR_SEPARATOR)
_str += DIR_SEPARATOR;
- _str += x.rawString();
+ _str += x._str;
return *this;
}
@@ -198,7 +198,7 @@ Path Path::join(const char *str, char separator) const {
}
Path Path::punycodeDecode() const {
- StringTokenizer tok(rawString(), String(DIR_SEPARATOR));
+ StringTokenizer tok(_str, String(DIR_SEPARATOR));
String res;
while (!tok.empty()) {
@@ -211,7 +211,7 @@ Path Path::punycodeDecode() const {
}
String Path::getIdentifierString() const {
- StringTokenizer tok(rawString(), String(DIR_SEPARATOR));
+ StringTokenizer tok(_str, String(DIR_SEPARATOR));
String res;
while (!tok.empty()) {
@@ -229,7 +229,7 @@ String Path::getIdentifierString() const {
}
Path Path::punycodeEncode() const {
- StringTokenizer tok(rawString(), String(DIR_SEPARATOR));
+ StringTokenizer tok(_str, String(DIR_SEPARATOR));
String res;
while (!tok.empty()) {
diff --git a/common/path.h b/common/path.h
index 1123cf41e59..bbae406ee51 100644
--- a/common/path.h
+++ b/common/path.h
@@ -93,12 +93,6 @@ public:
*/
Path(const String &str, char separator = '/');
- /**
- * Returns the unmodified, internal representation of the path,
- * using '\x1f' as a directory separator.
- */
- const String &rawString() const { return _str; }
-
/**
* Converts a path to a string using the given directory separator.
*
Commit: a690a034cf105bd16d5c74f208b5496a77997a68
https://github.com/scummvm/scummvm/commit/a690a034cf105bd16d5c74f208b5496a77997a68
Author: Vladimir Serbinenko (phcoder at gmail.com)
Date: 2022-12-14T05:08:46+01:00
Commit Message:
COMMON: Remove reliance that \x1f is never part of filename
So far we never encountered such a case but mac disks are notorious for
having non-printable characters in names
Changed paths:
common/path.cpp
common/path.h
diff --git a/common/path.cpp b/common/path.cpp
index 98432c0ab22..daaac85f3c6 100644
--- a/common/path.cpp
+++ b/common/path.cpp
@@ -20,11 +20,14 @@
*/
#include "common/path.h"
-#include "common/tokenizer.h"
#include "common/punycode.h"
#include "common/hash-str.h"
-const char DIR_SEPARATOR = '\x1f'; // unit separator
+const char ESCAPER = '/';
+const char ESCAPE_SLASH = '+';
+const char ESCAPE_SEPARATOR = '/';
+const char *DIR_SEPARATOR = "//";
+const char *SLASH_ESCAPED = "/+";
namespace Common {
@@ -37,49 +40,86 @@ Path::Path(const char *str, char separator) {
}
Path::Path(const String &str, char separator) {
- if (separator == DIR_SEPARATOR)
- _str = str;
- else
- set(str.c_str(), separator);
+ set(str.c_str(), separator);
}
String Path::toString(char separator) const {
String res;
- for (const char *ptr = _str.c_str(); *ptr; ptr++) {
- if (*ptr == DIR_SEPARATOR)
- res += separator;
- else
- res += *ptr;
+ for (uint i = 0; i < _str.size(); i++) {
+ if (_str[i] == ESCAPER) {
+ i++;
+ if (_str[i] == ESCAPE_SLASH)
+ res += '/';
+ else if (_str[i] == ESCAPE_SEPARATOR)
+ res += separator;
+ else
+ error("Path::toString(): Malformed Common::Path. '%c' unexpected after '/'", _str[i]);
+ } else {
+ res += _str[i];
+ }
+ }
+ return res;
+}
+
+size_t Path::findLastSeparator() const {
+ size_t res = String::npos;
+ for (uint i = 0; i + 2 < _str.size(); i++) {
+ if (_str[i] == ESCAPER) {
+ i++;
+ if (_str[i] == ESCAPE_SEPARATOR)
+ res = i - 1;
+ }
}
+
return res;
}
Path Path::getParent() const {
if (_str.size() < 2)
return Path();
- size_t separatorPos = _str.findLastOf(DIR_SEPARATOR, _str.size() - 2);
+ size_t separatorPos = findLastSeparator();
if (separatorPos == String::npos)
return Path();
- return Path(_str.substr(0, separatorPos + 1), DIR_SEPARATOR);
+ Path ret;
+ ret._str = _str.substr(0, separatorPos + 2);
+ return ret;
}
Path Path::getLastComponent() const {
if (_str.size() < 2)
return *this;
- size_t separatorPos = _str.findLastOf(DIR_SEPARATOR, _str.size() - 2);
+ size_t separatorPos = findLastSeparator();
if (separatorPos == String::npos)
return *this;
- return Path(_str.substr(separatorPos + 1), DIR_SEPARATOR);
+ Path ret;
+ ret._str = _str.substr(separatorPos + 2);
+ return ret;
+}
+
+static String escapePath(const String& in) {
+ String ret;
+ for (uint i = 0; i < in.size(); i++) {
+ if (in[i] == '/')
+ ret += SLASH_ESCAPED;
+ else
+ ret += in[i];
+ }
+ return ret;
}
Path Path::appendComponent(const String &x) const {
if (x.empty())
return *this;
String str = _str;
- if (!str.empty() && str.lastChar() != DIR_SEPARATOR)
+ size_t lastSep = findLastSeparator();
+ if (!str.empty() && (lastSep == String::npos || lastSep != str.size() - 2))
str += DIR_SEPARATOR;
- str += x;
- return Path(str, DIR_SEPARATOR);
+
+ str += escapePath(x);
+
+ Path ret;
+ ret._str = str;
+ return ret;
}
bool Path::operator==(const Path &x) const {
@@ -120,10 +160,7 @@ Path &Path::appendInPlace(const Path &x) {
}
Path &Path::appendInPlace(const String &str, char separator) {
- if (separator == DIR_SEPARATOR)
- _str += str;
- else
- appendInPlace(str.c_str(), separator);
+ appendInPlace(str.c_str(), separator);
return *this;
}
@@ -131,6 +168,8 @@ Path &Path::appendInPlace(const char *str, char separator) {
for (; *str; str++) {
if (*str == separator)
_str += DIR_SEPARATOR;
+ else if (*str == '/') // Order matters as / may be the separator and often is.
+ _str += SLASH_ESCAPED;
else
_str += *str;
}
@@ -157,7 +196,8 @@ Path &Path::joinInPlace(const Path &x) {
if (x.empty())
return *this;
- if (!_str.empty() && _str.lastChar() != DIR_SEPARATOR && x._str.firstChar() != DIR_SEPARATOR)
+ size_t lastSep = findLastSeparator();
+ if (!_str.empty() && (lastSep == String::npos || lastSep != _str.size() - 2) && x._str.hasPrefix(DIR_SEPARATOR))
_str += DIR_SEPARATOR;
_str += x._str;
@@ -173,7 +213,8 @@ Path &Path::joinInPlace(const char *str, char separator) {
if (*str == '\0')
return *this;
- if (!_str.empty() && _str.lastChar() != DIR_SEPARATOR && *str != separator)
+ size_t lastSep = findLastSeparator();
+ if (!_str.empty() && (lastSep == String::npos || lastSep != _str.size() - 2) && *str != separator)
_str += DIR_SEPARATOR;
appendInPlace(str, separator);
@@ -193,35 +234,78 @@ Path Path::join(const String &str, char separator) const {
Path Path::join(const char *str, char separator) const {
Path temp(*this);
- temp.joinInPlace(str, DIR_SEPARATOR);
+ temp.joinInPlace(str, separator);
return temp;
}
+StringArray Path::splitComponents() const {
+ StringArray res;
+ String cur;
+ for (uint i = 0; i < _str.size(); i++) {
+ if (_str[i] == ESCAPER) {
+ i++;
+ if (_str[i] == ESCAPE_SLASH)
+ cur += '/';
+ else if (_str[i] == ESCAPE_SEPARATOR) {
+ res.push_back(cur);
+ cur = "";
+ } else {
+ error("Path::splitComponents(): Malformed Common::Path. '%c' unexpected after '/'", _str[i]);
+ }
+ } else
+ cur += _str[i];
+ }
+
+ res.push_back(cur);
+
+ return res;
+}
+
Path Path::punycodeDecode() const {
- StringTokenizer tok(_str, String(DIR_SEPARATOR));
+ StringArray c = splitComponents();
String res;
- while (!tok.empty()) {
- res += punycode_decodefilename(tok.nextToken());
- if (!tok.empty())
+ for (uint i = 0; i < c.size(); i++) {
+ res += escapePath(punycode_decodefilename(c[i]));
+ if (i + 1 < c.size())
res += DIR_SEPARATOR;
}
- return Path(res, DIR_SEPARATOR);
+ Path ret;
+ ret._str = res;
+ return ret;
+}
+
+// See getIdentifierString() for more details.
+// This does the same but for a single path component and is used by
+// getIdentifierString().
+static String getIdentifierComponent(const String& in) {
+ String part = punycode_decodefilename(in);
+ String res = "";
+ for (uint j = 0; j < part.size(); j++)
+ if (part[j] == '/')
+ res += ':';
+ else
+ res += part[j];
+ return res;
}
+// For a path creates a string with following property:
+// if 2 files have the same case-insensitive
+// identifier string then and only then we treat them as
+// effectively the same file. For this there are 2
+// transformations we need to do:
+// * decode punycode
+// * Replace / with : in path components so a path from
+// HFS(+) image will end up with : independently of how
+// it was dumped or copied from
String Path::getIdentifierString() const {
- StringTokenizer tok(_str, String(DIR_SEPARATOR));
+ StringArray c = splitComponents();
String res;
- while (!tok.empty()) {
- String part = punycode_decodefilename(tok.nextToken());
- for (uint i = 0; i < part.size(); i++)
- if (part[i] == '/')
- res += ':';
- else
- res += part[i];
- if (!tok.empty())
+ for (uint i = 0; i < c.size(); i++) {
+ res += getIdentifierComponent(c[i]);
+ if (i + 1 < c.size())
res += DIR_SEPARATOR;
}
@@ -229,28 +313,34 @@ String Path::getIdentifierString() const {
}
Path Path::punycodeEncode() const {
- StringTokenizer tok(_str, String(DIR_SEPARATOR));
+ StringArray c = splitComponents();
String res;
- while (!tok.empty()) {
- String part = tok.nextToken();
- if (punycode_needEncode(part))
- res += punycode_encodefilename(part);
- else
- res += part;
-
- if (!tok.empty())
+ for (uint i = 0; i < c.size(); i++) {
+ res += escapePath(punycode_encodefilename(c[i]));
+ if (i + 1 < c.size())
res += DIR_SEPARATOR;
}
- return Path(res, DIR_SEPARATOR);
+ Path ret;
+ ret._str = res;
+ return ret;
}
bool Path::matchPattern(const Path& pattern) const {
+ StringArray c = splitComponents();
+ StringArray cpat = pattern.splitComponents();
+
// Prevent wildcards from matching the directory separator.
- const char wildcardExclusions[] = { DIR_SEPARATOR, '\0' };
+ if (c.size() != cpat.size())
+ return false;
+
+ for (uint i = 0; i < c.size(); i++) {
+ if (!getIdentifierComponent(c[i]).matchString(getIdentifierComponent(cpat[i]), true))
+ return false;
+ }
- return getIdentifierString().matchString(pattern.getIdentifierString(), true, wildcardExclusions);
+ return true;
}
bool Path::IgnoreCaseAndMac_EqualsTo::operator()(const Path& x, const Path& y) const {
diff --git a/common/path.h b/common/path.h
index bbae406ee51..8145bd2d6ac 100644
--- a/common/path.h
+++ b/common/path.h
@@ -24,6 +24,7 @@
#include "common/scummsys.h"
#include "common/str.h"
+#include "common/str-array.h"
namespace Common {
@@ -41,15 +42,15 @@ namespace Common {
* arbitrary directory separators, providing a common representation.
*
* Internally, this is just a simple wrapper around a String, using
- * '\x1f' (unit separator) as a directory separator. As this is not
- * a printable character, it should not appear in file names, unlike
- * '/', '\', or ':', which are allowed on certain platforms.
+ * "//" (unit separator) as a directory separator and "/+" as "/".
*/
class Path {
private:
String _str;
String getIdentifierString() const;
+ size_t findLastSeparator() const;
+
public:
/**
* Hash and comparator for Path with following changes:
@@ -205,6 +206,15 @@ public:
* Check pattern match similar matchString
*/
bool matchPattern(const Path& pattern) const;
+
+ /**
+ * Splits into path components. After every component except
+ * last there is an implied separator. First component is empty
+ * if path starts with a separator. Last component is empty if
+ * the path ends with a separator. Other components may be empty if
+ * 2 separots follow each other
+ */
+ StringArray splitComponents() const;
};
/** @} */
More information about the Scummvm-git-logs
mailing list