[Scummvm-git-logs] scummvm master -> 6ed3c946ffc8f371bce691a5b30b6bf9c2b2de53

sev- noreply at scummvm.org
Sat Dec 16 18:30:26 UTC 2023


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

Summary:
6ed3c946ff COMMON: Add a way to check if an archive member is in a Mac archive so we can avoid decompressing the data fork to check


Commit: 6ed3c946ffc8f371bce691a5b30b6bf9c2b2de53
    https://github.com/scummvm/scummvm/commit/6ed3c946ffc8f371bce691a5b30b6bf9c2b2de53
Author: elasota (1137273+elasota at users.noreply.github.com)
Date: 2023-12-16T19:30:23+01:00

Commit Message:
COMMON: Add a way to check if an archive member is in a Mac archive so we can avoid decompressing the data fork to check for MacBinary when the resource data is always in the alt stream.

Changed paths:
    common/archive.cpp
    common/archive.h
    common/compression/stuffit.cpp
    common/compression/vise.cpp
    common/macresman.cpp
    engines/mtropolis/vfs.cpp
    engines/mtropolis/vfs.h


diff --git a/common/archive.cpp b/common/archive.cpp
index db189daf2a6..56f243b17e0 100644
--- a/common/archive.cpp
+++ b/common/archive.cpp
@@ -37,6 +37,10 @@ U32String ArchiveMember::getDisplayName() const {
 	return getName();
 }
 
+bool ArchiveMember::isInMacArchive() const {
+	return false;
+}
+
 bool ArchiveMember::isDirectory() const {
 	return false;
 }
diff --git a/common/archive.h b/common/archive.h
index aeae4e98265..7cc0f4901f0 100644
--- a/common/archive.h
+++ b/common/archive.h
@@ -82,6 +82,7 @@ public:
 	virtual bool isDirectory() const; /*!< Checks if the ArchiveMember is a directory. */
 	virtual void listChildren(ArchiveMemberList &childList, const char *pattern = nullptr) const; /*!< Adds the immediate children of this archive member to childList, optionally matching a pattern. */
 	virtual U32String getDisplayName() const; /*!< Get the display name of the archive member. */
+	virtual bool isInMacArchive() const; /*!< Checks if the ArchiveMember is in a Mac archive, in which case resource forks and Finder info can only be loaded via alt streams. */
 };
 
 struct ArchiveMemberDetails {
diff --git a/common/compression/stuffit.cpp b/common/compression/stuffit.cpp
index 4d3449f38f6..704b1882d5c 100644
--- a/common/compression/stuffit.cpp
+++ b/common/compression/stuffit.cpp
@@ -73,6 +73,13 @@ private:
 		FileEntryFork resFork;
 	};
 
+	class StuffItArchiveMember : public Common::GenericArchiveMember {
+	public:
+		StuffItArchiveMember(const Common::Path &path, const Common::Archive &archive);
+
+		bool isInMacArchive() const override;
+	};
+
 	Common::SeekableReadStream *_stream;
 
 	typedef Common::HashMap<Common::String, FileEntry, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> FileMap;
@@ -284,7 +291,7 @@ int StuffItArchive::listMembers(Common::ArchiveMemberList &list) const {
 }
 
 const Common::ArchiveMemberPtr StuffItArchive::getMember(const Common::Path &path) const {
-	return Common::ArchiveMemberPtr(new Common::GenericArchiveMember(path, *this));
+	return Common::ArchiveMemberPtr(new StuffItArchiveMember(path, *this));
 }
 
 Common::SharedArchiveContents StuffItArchive::readContentsForPath(const Common::String &name) const {
@@ -1118,6 +1125,14 @@ void StuffItArchive::decompress14(Common::SeekableReadStream *src, byte *dst, ui
 StuffItArchive::FileEntryFork::FileEntryFork() : uncompressedSize(0), compressedSize(0), offset(0), crc(0), compression(0) {
 }
 
+StuffItArchive::StuffItArchiveMember::StuffItArchiveMember(const Common::Path &path, const Common::Archive &archive)
+	: Common::GenericArchiveMember(path, archive) {
+}
+
+bool StuffItArchive::StuffItArchiveMember::isInMacArchive() const {
+	return true;
+}
+
 Common::Archive *createStuffItArchive(const Common::String &fileName, bool flattenTree) {
 	StuffItArchive *archive = new StuffItArchive();
 
diff --git a/common/compression/vise.cpp b/common/compression/vise.cpp
index f21631c56f6..e03f33d1dd4 100644
--- a/common/compression/vise.cpp
+++ b/common/compression/vise.cpp
@@ -73,6 +73,7 @@ private:
 		Common::String getName() const override;
 		Common::Path getPathInArchive() const override;
 		Common::String getFileName() const override;
+		bool isInMacArchive() const override;
 
 	private:
 		Common::SeekableReadStream *createReadStreamForDataStream(bool isResFork) const;
@@ -219,6 +220,10 @@ Common::String MacVISEArchive::ArchiveMember::getFileName() const {
 	return _fileDesc->name;
 }
 
+bool MacVISEArchive::ArchiveMember::isInMacArchive() const {
+	return true;
+}
+
 MacVISEArchive::FileDesc::FileDesc() : type{0, 0, 0, 0}, creator{0, 0, 0, 0}, compressedDataSize(0), uncompressedDataSize(0), compressedResSize(0), uncompressedResSize(0), positionInArchive(0) {
 }
 
diff --git a/common/macresman.cpp b/common/macresman.cpp
index f8d741ab85d..23d4603dc9d 100644
--- a/common/macresman.cpp
+++ b/common/macresman.cpp
@@ -217,12 +217,28 @@ SeekableReadStream *MacResManager::openAppleDoubleWithAppleOrOSXNaming(Archive&
 bool MacResManager::open(const Path &fileName, Archive &archive) {
 	close();
 
+	SeekableReadStream *stream = nullptr;
+
 	// Our preference is as following:
 	// AppleDouble in .rsrc -> Raw .rsrc -> MacBinary with .bin -> MacBinary without .bin -> AppleDouble in ._
 	// -> AppleDouble in __MACOSX -> Actual resource fork -> No resource fork
 
+	Common::ArchiveMemberPtr archiveMember = archive.getMember(fileName);
+
+	// If this is in a Mac archive, then the resource fork will always be in the alt stream
+	if (archiveMember && archiveMember->isInMacArchive()) {
+		_baseFileName = fileName;
+
+		stream = archive.createReadStreamForMemberAltStream(fileName, AltStreamType::MacResourceFork);
+		if (stream && !loadFromRawFork(stream))
+			_stream = nullptr;
+
+		// If the archive member exists, then the file exists, but has no res fork, so we should return true
+		return true;
+	}
+
 	// Prefer standalone files first, starting with raw forks
-	SeekableReadStream *stream = archive.createReadStreamForMember(fileName.append(".rsrc"));
+	stream = archive.createReadStreamForMember(fileName.append(".rsrc"));
 
 	if (stream) {
 		// Some programs actually store AppleDouble there. Check it
@@ -251,14 +267,17 @@ bool MacResManager::open(const Path &fileName, Archive &archive) {
 
 	// Maybe file is in MacBinary but without .bin extension?
 	// Check it here
-	stream = archive.createReadStreamForMember(fileName);
-	if (stream && isMacBinary(*stream)) {
-		stream->seek(0);
-		if (loadFromMacBinary(stream)) {
-			_baseFileName = fileName;
-			return true;
+	if (archiveMember) {
+		stream = archiveMember->createReadStream();
+		if (stream && isMacBinary(*stream)) {
+			stream->seek(0);
+			if (loadFromMacBinary(stream)) {
+				_baseFileName = fileName;
+				return true;
+			}
 		}
-	}
+	} else
+		stream = nullptr;
 
 	bool fileExists = (stream != nullptr);
 
@@ -285,7 +304,6 @@ bool MacResManager::open(const Path &fileName, Archive &archive) {
 #ifdef MACOSX
 	// Check the actual fork on a Mac computer. It's even worse than __MACOSX as
 	// it's present on any HFS(+) and appears even after copying macbin on HFS(+).
-	const ArchiveMemberPtr archiveMember = archive.getMember(fileName);
 	if (archiveMember.get()) {
 		// This could be a MacBinary file that still has a
 		// resource fork; if it is, it needs to get opened as MacBinary
@@ -332,7 +350,12 @@ SeekableReadStream * MacResManager::openDataForkFromMacBinary(SeekableReadStream
 }
 
 SeekableReadStream * MacResManager::openFileOrDataFork(const Path &fileName, Archive &archive) {
-	SeekableReadStream *stream = archive.createReadStreamForMember(fileName);
+	SeekableReadStream *stream = nullptr;
+
+	Common::ArchiveMemberPtr archiveMember = archive.getMember(fileName);
+
+	bool mayBeMacBinary = true;
+
 	// Our preference is as following:
 	// File itself as macbinary -> File itself as raw -> .bin as macbinary
 	// Compared to open:
@@ -346,27 +369,37 @@ SeekableReadStream * MacResManager::openFileOrDataFork(const Path &fileName, Arc
 	//    right levels of onion. Fortunately no game so far does it. But someday...
 	//    Hopefully not.
 
-	// Check the basename for Macbinary
-	if (stream && isMacBinary(*stream)) {
-		stream->seek(MBI_DFLEN);
-		uint32 dataSize = stream->readUint32BE();
-		return new SeekableSubReadStream(stream, MBI_INFOHDR, MBI_INFOHDR + dataSize, DisposeAfterUse::YES);
-	}
-	// All formats other than Macbinary and AppleSingle (not supported) use
-	// basename-named file as data fork holder.
-	if (stream) {
-		stream->seek(0);
-		return stream;
+	if (archiveMember && archiveMember->isInMacArchive())
+		mayBeMacBinary = false;
+
+	if (archiveMember) {
+		stream = archiveMember->createReadStream();
+
+		// Check the basename for Macbinary
+		if (mayBeMacBinary && stream && isMacBinary(*stream)) {
+			stream->seek(MBI_DFLEN);
+			uint32 dataSize = stream->readUint32BE();
+			return new SeekableSubReadStream(stream, MBI_INFOHDR, MBI_INFOHDR + dataSize, DisposeAfterUse::YES);
+		}
+
+		// All formats other than Macbinary and AppleSingle (not supported) use
+		// basename-named file as data fork holder.
+		if (stream) {
+			stream->seek(0);
+			return stream;
+		}
 	}
 
-	// Check .bin for MacBinary next
-	stream = archive.createReadStreamForMember(fileName.append(".bin"));
-	if (stream && isMacBinary(*stream)) {
-		stream->seek(MBI_DFLEN);
-		uint32 dataSize = stream->readUint32BE();
-		return new SeekableSubReadStream(stream, MBI_INFOHDR, MBI_INFOHDR + dataSize, DisposeAfterUse::YES);
+	if (mayBeMacBinary) {
+		// Check .bin for MacBinary next
+		stream = archive.createReadStreamForMember(fileName.append(".bin"));
+		if (stream && isMacBinary(*stream)) {
+			stream->seek(MBI_DFLEN);
+			uint32 dataSize = stream->readUint32BE();
+			return new SeekableSubReadStream(stream, MBI_INFOHDR, MBI_INFOHDR + dataSize, DisposeAfterUse::YES);
+		}
+		delete stream;
 	}
-	delete stream;
 
 	// The file doesn't exist
 	return nullptr;
diff --git a/engines/mtropolis/vfs.cpp b/engines/mtropolis/vfs.cpp
index c2659183e02..f33e1005bc2 100644
--- a/engines/mtropolis/vfs.cpp
+++ b/engines/mtropolis/vfs.cpp
@@ -235,4 +235,8 @@ Common::U32String VirtualFileSystem::VFSArchiveMember::getDisplayName() const {
 	return _virtualFile->_archiveMember->getDisplayName();
 }
 
+bool VirtualFileSystem::VFSArchiveMember::isInMacArchive() const {
+	return _virtualFile->_archiveMember->isInMacArchive();
+}
+
 } // End of namespace MTropolis
diff --git a/engines/mtropolis/vfs.h b/engines/mtropolis/vfs.h
index c64ab56ce3b..43d4f27e756 100644
--- a/engines/mtropolis/vfs.h
+++ b/engines/mtropolis/vfs.h
@@ -92,6 +92,7 @@ private:
 		bool isDirectory() const override;
 		void listChildren(Common::ArchiveMemberList &childList, const char *pattern) const override;
 		Common::U32String getDisplayName() const override;
+		bool isInMacArchive() const override;
 
 	private:
 		const VirtualFile *_virtualFile;




More information about the Scummvm-git-logs mailing list