[Scummvm-git-logs] scummvm master -> ace9a26180ccc4f73b918420a004d5da92bf5e2e

sev- noreply at scummvm.org
Mon Jun 23 23:07:39 UTC 2025


This automated email contains information about 2 new commits which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .

Summary:
9b6414e94f COMMON: Implement Path::removeExtension() and relevant tests
ace9a26180 GUI: INTEGRITY: Boilerplate code for macfile-format-agnostic checksums


Commit: 9b6414e94f9e3ee9f15e28dd503d519193a4b2f1
    https://github.com/scummvm/scummvm/commit/9b6414e94f9e3ee9f15e28dd503d519193a4b2f1
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2025-06-24T01:07:26+02:00

Commit Message:
COMMON: Implement Path::removeExtension() and relevant tests

Changed paths:
    common/path.cpp
    common/path.h
    test/common/path.h


diff --git a/common/path.cpp b/common/path.cpp
index 07e3bafa368..4fb1446a1df 100644
--- a/common/path.cpp
+++ b/common/path.cpp
@@ -610,6 +610,53 @@ Path &Path::removeTrailingSeparators() {
 	return *this;
 }
 
+Path &Path::removeExtension(const char *ext) {
+	if (_str.empty()) {
+		return *this;
+	}
+
+	// Find the last separator
+	size_t last = _str.size() - 1;
+	if (isSeparatorTerminated()) {
+		last--;
+	}
+
+	size_t sepPos = findLastSeparator(last);
+	const char *begin;
+	if (sepPos == String::npos) {
+		// No separator found, we are a single component
+		begin = _str.c_str();
+	} else {
+		// We have a separator, so we can find the last component
+		begin = _str.c_str() + sepPos + 1;
+	}
+
+	const char *end = _str.c_str() + _str.size();
+	String component(begin, end);
+
+	// If the last component is shorter than the extension,
+	// or it is punycode encoded, we do not change the path
+	if ((ext && component.size() < strlen(ext)) || punycode_hasprefix(component))
+		return *this;
+
+	if (!ext) {
+		// Remove the last extension, if any
+		size_t dotPos = component.findLastOf('.');
+		if (dotPos == String::npos) {
+			return *this; // No change
+		}
+
+		_str.chop(end - begin - dotPos);
+
+		return *this;
+	} else if (component.hasSuffix(ext)) {
+		// Remove the given extension, if it matches
+		_str.chop(strlen(ext));
+	}
+
+	return *this;
+}
+
 const char *Path::getSuffix(const Common::Path &other) const {
 	if (other.empty()) {
 		// Other is empty, return full string
diff --git a/common/path.h b/common/path.h
index 0f17e0b18c1..0579646d642 100644
--- a/common/path.h
+++ b/common/path.h
@@ -469,6 +469,19 @@ public:
 	 */
 	Path &removeTrailingSeparators();
 
+	/**
+	 * Removes extension from the last component of this path (in-place).
+	 * If the last component has no extension, this does nothing.
+	 *
+	 * Punycode encoded paths are not supported.
+	 *
+	 * If nullptr is passed as @p ext, it will remove the last extension,
+	 * otherwise it will remove the extension only if it matches @p ext.
+	 *
+	 * The extension must have a leading dot, e.g. ".txt".
+	 */
+	Path &removeExtension(const char *ext = nullptr);
+
 	/**
 	 * Returns whether this path ends with a separator
 	 */
diff --git a/test/common/path.h b/test/common/path.h
index c14cfcd4f2e..bbf2607f551 100644
--- a/test/common/path.h
+++ b/test/common/path.h
@@ -538,4 +538,66 @@ class PathTestSuite : public CxxTest::TestSuite
 	void test_canUnescape() {
 		TS_ASSERT(Common::Path::canUnescape(true, true, ""));
 	}
+
+	void test_removeExtension() {
+		Common::Path p(TEST_PATH);
+		p.removeExtension();
+		TS_ASSERT_EQUALS(p.toString(), "parent/dir/file");
+
+		Common::Path p2("parent/dir/file.txt.gz");
+		p2.removeExtension();
+		TS_ASSERT_EQUALS(p2.toString(), "parent/dir/file.txt");
+
+		Common::Path p3("parent/dir/file.");
+		p3.removeExtension();
+		TS_ASSERT_EQUALS(p3.toString(), "parent/dir/file");
+
+		Common::Path p4("parent/dir/file.txt.txt");
+		p4.removeExtension(".txt");
+		TS_ASSERT_EQUALS(p4.toString(), "parent/dir/file.txt");
+
+		Common::Path p5("parent/dir/file.txt");
+		p5.removeExtension(".txt");
+		TS_ASSERT_EQUALS(p5.toString(), "parent/dir/file");
+
+		Common::Path p6("parent/dir.txt/file.gz");
+		p6.removeExtension(".txt");
+		TS_ASSERT_EQUALS(p6.toString(), "parent/dir.txt/file.gz");
+
+		Common::Path p7("parent/dir/xn--Sound Manager 3.1  SoundLib-lba84k/Sound.txt");
+		p7.removeExtension(".txt");
+		TS_ASSERT_EQUALS(p7.toString(), "parent/dir/xn--Sound Manager 3.1  SoundLib-lba84k/Sound");
+
+		Common::Path p8("parent/dir/Sound/xn--dialred.dir-qa21d");
+		p8.removeExtension(".dir");
+		TS_ASSERT_EQUALS(p8.toString(), "parent/dir/Sound/xn--dialred.dir-qa21d");
+
+		Common::Path p9("parent/dir/.ab");
+		p9.removeExtension();
+		TS_ASSERT_EQUALS(p9.toString(), "parent/dir/");
+
+		Common::Path p10("parent/dir/.ab");
+		p10.removeExtension(".abc");
+		TS_ASSERT_EQUALS(p10.toString(), "parent/dir/.ab");
+
+		Common::Path p11(".ab");
+		p11.removeExtension(".abc");
+		TS_ASSERT_EQUALS(p11.toString(), ".ab");
+
+		Common::Path p12("test.dir");
+		p12.removeExtension(".dir");
+		TS_ASSERT_EQUALS(p12.toString(), "test");
+
+		Common::Path p13("test.dir");
+		p13.removeExtension(".txt");
+		TS_ASSERT_EQUALS(p13.toString(), "test.dir");
+
+		Common::Path p14("test.dir.txt");
+		p14.removeExtension(".dir");
+		TS_ASSERT_EQUALS(p14.toString(), "test.dir.txt");
+
+		Common::Path p15(".dir");
+		p15.removeExtension(".dir");
+		TS_ASSERT_EQUALS(p15.toString(), "");
+	}
 };


Commit: ace9a26180ccc4f73b918420a004d5da92bf5e2e
    https://github.com/scummvm/scummvm/commit/ace9a26180ccc4f73b918420a004d5da92bf5e2e
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2025-06-24T01:07:26+02:00

Commit Message:
GUI: INTEGRITY: Boilerplate code for macfile-format-agnostic checksums

Changed paths:
    gui/integrity-dialog.cpp


diff --git a/gui/integrity-dialog.cpp b/gui/integrity-dialog.cpp
index aec7fef451c..14d818553d3 100644
--- a/gui/integrity-dialog.cpp
+++ b/gui/integrity-dialog.cpp
@@ -351,6 +351,39 @@ Common::Array<Common::StringArray> IntegrityDialog::generateChecksums(Common::Pa
 	if (fileList.empty())
 		return {};
 
+	// First, we go through the list and check any Mac files
+	Common::HashMap<Common::Path, bool, Common::Path::IgnoreCase_Hash, Common::Path::IgnoreCase_EqualTo> macFiles;
+	Common::HashMap<Common::Path, bool, Common::Path::IgnoreCase_Hash, Common::Path::IgnoreCase_EqualTo> toRemove;
+	Common::List<Common::Path> filteredFileList;
+	Common::List<Common::Path> tmpFileList;
+
+	for (const auto &entry : fileList) {
+		if (entry.isDirectory())
+			continue;
+
+		Common::Path filename(entry.getPath().relativeTo(gamePath));
+		const Common::Path originalFileName = filename;
+		filename.removeExtension(".bin");
+		filename.removeExtension(".rsrc");
+
+		auto macFile = Common::MacResManager();
+
+		if (macFile.open(filename) && macFile.isMacFile()) {
+			macFiles[filename] = true;
+
+			tmpFileList.push_back(filename);
+		} else {
+			if (!toRemove.contains(originalFileName))
+				tmpFileList.push_back(originalFileName);
+		}
+	}
+
+	for (const auto &entry : tmpFileList) {
+		if (!toRemove.contains(entry)) {
+			filteredFileList.push_back(entry);
+		}
+	}
+
 	// Process the files and subdirectories in the current directory recursively
 	for (const auto &entry : fileList) {
 		if (entry.isDirectory()) {




More information about the Scummvm-git-logs mailing list