[Scummvm-git-logs] scummvm master -> 78d26927a850144e4ccfcb669f5c4cfcd578be4a

sev- noreply at scummvm.org
Mon Nov 28 23:25:53 UTC 2022


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:
78d26927a8 COMMON: Add functions to get Mac Finder metadata such as type/creator codes.


Commit: 78d26927a850144e4ccfcb669f5c4cfcd578be4a
    https://github.com/scummvm/scummvm/commit/78d26927a850144e4ccfcb669f5c4cfcd578be4a
Author: elasota (ejlasota at gmail.com)
Date: 2022-11-29T00:25:50+01:00

Commit Message:
COMMON: Add functions to get Mac Finder metadata such as type/creator codes.

Changed paths:
    common/macresman.cpp
    common/macresman.h


diff --git a/common/macresman.cpp b/common/macresman.cpp
index 5f48120b2f6..1eb222464c4 100644
--- a/common/macresman.cpp
+++ b/common/macresman.cpp
@@ -82,10 +82,17 @@ MacFinderExtendedInfoData MacFinderExtendedInfo::toData() const {
 
 #define MBI_ZERO1 0
 #define MBI_NAMELEN 1
+#define MBI_TYPE 65
+#define MBI_CREATOR 69
+#define MBI_FLAGSHIGH 73
 #define MBI_ZERO2 74
+#define MBI_POSY 75
+#define MBI_POSX 77
+#define MBI_FOLDERID 79
 #define MBI_ZERO3 82
 #define MBI_DFLEN 83
 #define MBI_RFLEN 87
+#define MBI_FLAGSLOW 101
 #define MAXNAMELEN 63
 
 MacResManager::MacResManager() {
@@ -305,6 +312,81 @@ bool MacResManager::exists(const Path &fileName) {
 	return false;
 }
 
+bool MacResManager::getFileFinderInfo(const Path &fileName, Archive &archive, MacFinderInfo &outFinderInfo) {
+	MacFinderExtendedInfo fxinfo;
+	return getFileFinderInfo(fileName, archive, outFinderInfo, fxinfo);
+}
+
+bool MacResManager::getFileFinderInfo(const Path &fileName, Archive &archive, MacFinderInfo &outFinderInfo, MacFinderExtendedInfo &outFinderExtendedInfo) {
+	// Prefer standalone .finf files first (especially since this can avoid decompressing entire files from slow archive formats like StuffIt Installer)
+	Common::ScopedPtr<SeekableReadStream> stream(archive.createReadStreamForMember(fileName.append(".finf")));
+	if (stream) {
+		MacFinderInfoData finfoData;
+		MacFinderExtendedInfoData fxinfoData;
+
+		uint32 finfoSize = stream->read(&finfoData, sizeof(finfoData));
+		uint32 fxinfoSize = stream->read(&fxinfoData, sizeof(fxinfoData));
+
+		if (finfoSize == sizeof(MacFinderInfoData)) {
+			outFinderInfo = MacFinderInfo(finfoData);
+
+			if (fxinfoSize == sizeof(MacFinderExtendedInfoData)) {
+				outFinderExtendedInfo = MacFinderExtendedInfo(fxinfoData);
+			} else {
+				outFinderExtendedInfo = MacFinderExtendedInfo();
+				if (fxinfoSize != 0)
+					warning("Finder extended info metadata file was too small");
+			}
+
+			return true;
+		} else if (finfoSize != 0) {
+			warning("Finder info metadata file was too small");
+		}
+	}
+
+	// Might have AppleDouble in the resource file
+	stream.reset();
+	stream.reset(archive.createReadStreamForMember(fileName.append(".rsrc")));
+
+	if (stream) {
+		bool appleDouble = (stream->readUint32BE() == 0x00051607);
+		stream->seek(0);
+
+		if (appleDouble && getFinderInfoFromAppleDouble(stream.get(), outFinderInfo, outFinderExtendedInfo))
+			return true;
+	}
+
+	// Try for AppleDouble using Apple's naming
+	stream.reset();
+	stream.reset(archive.createReadStreamForMember(constructAppleDoubleName(fileName)));
+	if (stream && getFinderInfoFromAppleDouble(stream.get(), outFinderInfo, outFinderExtendedInfo))
+		return true;
+
+	// Check .bin for MacBinary next
+	stream.reset();
+	stream.reset(archive.createReadStreamForMember(fileName.append(".bin")));
+	if (stream && getFinderInfoFromMacBinary(stream.get(), outFinderInfo, outFinderExtendedInfo))
+		return true;
+
+	// Check if the file is in MacBinary format
+	stream.reset();
+	stream.reset(archive.createReadStreamForMember(fileName));
+	if (stream && getFinderInfoFromMacBinary(stream.get(), outFinderInfo, outFinderExtendedInfo))
+		return true;
+
+	// No metadata
+	return false;
+}
+
+bool MacResManager::getFileFinderInfo(const Path &fileName, MacFinderInfo &outFinderInfo) {
+	MacFinderExtendedInfo fxinfo;
+	return getFileFinderInfo(fileName, outFinderInfo, fxinfo);
+}
+
+bool MacResManager::getFileFinderInfo(const Path &fileName, MacFinderInfo &outFinderInfo, MacFinderExtendedInfo &outFinderExtendedInfo) {
+	return getFileFinderInfo(fileName, SearchMan, outFinderInfo, outFinderExtendedInfo);
+}
+
 void MacResManager::listFiles(StringArray &files, const String &pattern) {
 	// Base names discovered so far.
 	typedef HashMap<String, bool, IgnoreCase_Hash, IgnoreCase_EqualTo> BaseNameSet;
@@ -403,8 +485,71 @@ bool MacResManager::loadFromAppleDouble(SeekableReadStream *stream) {
 	return false;
 }
 
-bool MacResManager::isMacBinary(SeekableReadStream &stream) {
+bool MacResManager::getFinderInfoFromMacBinary(SeekableReadStream *stream, MacFinderInfo &outFinderInfo, MacFinderExtendedInfo &outFinderExtendedInfo) {
 	byte infoHeader[MBI_INFOHDR];
+	if (!readAndValidateMacBinaryHeader(*stream, infoHeader))
+		return false;
+
+	MacFinderInfo finfo;
+
+	// Parse fields
+	memcpy(finfo.type, infoHeader + MBI_TYPE, 4);
+	memcpy(finfo.creator, infoHeader + MBI_CREATOR, 4);
+	finfo.flags = (infoHeader[MBI_FLAGSHIGH] << 8) + infoHeader[MBI_FLAGSLOW];
+	finfo.position.x = READ_BE_INT16(infoHeader + MBI_POSX);
+	finfo.position.y = READ_BE_INT16(infoHeader + MBI_POSY);
+	finfo.windowID = READ_BE_INT16(infoHeader + MBI_FOLDERID);
+
+	outFinderInfo = finfo;
+	outFinderExtendedInfo = MacFinderExtendedInfo();
+
+	return true;
+}
+
+bool MacResManager::getFinderInfoFromAppleDouble(SeekableReadStream *stream, MacFinderInfo &outFinderInfo, MacFinderExtendedInfo &outFinderExtendedInfo) {
+	if (!stream)
+		return false;
+
+	if (stream->readUint32BE() != 0x00051607) // tag
+		return false;
+
+	stream->skip(20); // version + home file system
+
+	uint16 entryCount = stream->readUint16BE();
+
+	uint32 finderInfoPos = 0;
+	uint32 finderInfoLength = 0;
+
+	for (uint16 i = 0; i < entryCount; i++) {
+		uint32 id = stream->readUint32BE();
+		uint32 offset = stream->readUint32BE();
+		uint32 length = stream->readUint32BE(); // length
+
+		if (id == 9) {
+			finderInfoPos = offset;
+			finderInfoLength = length;
+			break;
+		}
+	}
+
+	if (finderInfoLength < sizeof(MacFinderInfoData) + sizeof(MacFinderExtendedInfoData))
+		return false;
+
+	if (!stream->seek(finderInfoPos))
+		return false;
+
+	MacFinderInfoData finfo;
+	MacFinderExtendedInfoData fxinfo;
+	if (stream->read(&finfo, sizeof(finfo)) != sizeof(finfo) || stream->read(&fxinfo, sizeof(fxinfo)) != sizeof(fxinfo))
+		return false;
+
+	outFinderInfo = MacFinderInfo(finfo);
+	outFinderExtendedInfo = MacFinderExtendedInfo(fxinfo);
+
+	return true;
+}
+
+bool MacResManager::readAndValidateMacBinaryHeader(SeekableReadStream &stream, byte (&infoHeader)[MBI_INFOHDR]) {
 	int resForkOffset = -1;
 
 	if (stream.read(infoHeader, MBI_INFOHDR) != MBI_INFOHDR)
@@ -427,7 +572,7 @@ bool MacResManager::isMacBinary(SeekableReadStream &stream) {
 
 		uint32 dataSizePad = (((dataSize + 127) >> 7) << 7);
 		// Files produced by ISOBuster are not padded, thus, compare with the actual size
-		//uint32 rsrcSizePad = (((rsrcSize + 127) >> 7) << 7);
+		// uint32 rsrcSizePad = (((rsrcSize + 127) >> 7) << 7);
 
 		// Length check
 		if (MBI_INFOHDR + dataSizePad + rsrcSize <= (uint32)stream.size()) {
@@ -441,6 +586,11 @@ bool MacResManager::isMacBinary(SeekableReadStream &stream) {
 	return true;
 }
 
+bool MacResManager::isMacBinary(SeekableReadStream &stream) {
+	byte infoHeader[MBI_INFOHDR];
+	return readAndValidateMacBinaryHeader(stream, infoHeader);
+}
+
 bool MacResManager::isRawFork(SeekableReadStream &stream) {
 	// TODO: Is there a better way to detect whether this is a raw fork?
 	const uint32 dataOffset = stream.readUint32BE();
diff --git a/common/macresman.h b/common/macresman.h
index 34f785a9bd4..58aa93b3cc1 100644
--- a/common/macresman.h
+++ b/common/macresman.h
@@ -166,6 +166,19 @@ public:
 	 */
 	static bool exists(const Path &fileName);
 
+	/**
+	 * Attempt to read the Mac Finder info metadata for a file path.
+	 * @param fileName The base file name of the file
+	 * @param archive The archive to search in
+	 * @param outFinderInfo The loaded and parsed Finder info
+	 * @param outFinderExtendedInfo The loaded and parsed Finder extended info
+	 * @return True if finder info was available for a path, false if not
+	 */
+	static bool getFileFinderInfo(const Path &fileName, Archive &archive, MacFinderInfo &outFinderInfo);
+	static bool getFileFinderInfo(const Path &fileName, Archive &archive, MacFinderInfo &outFinderInfo, MacFinderExtendedInfo &outFinderExtendedInfo);
+	static bool getFileFinderInfo(const Path &fileName, MacFinderInfo &outFinderInfo);
+	static bool getFileFinderInfo(const Path &fileName, MacFinderInfo &outFinderInfo, MacFinderExtendedInfo &outFinderExtendedInfo);
+
 	/**
 	 * List all filenames matching pattern for opening with open().
 	 *
@@ -302,6 +315,18 @@ private:
 	bool loadFromRawFork(SeekableReadStream *stream);
 	bool loadFromAppleDouble(SeekableReadStream *stream);
 
+	/**
+	 * Get Finder info from a file in MacBinary format
+	 */
+	static bool getFinderInfoFromMacBinary(SeekableReadStream *stream, MacFinderInfo &outFinderInfo, MacFinderExtendedInfo &outFinderExtendedInfo);
+
+	/**
+	 * Get Finder info from a file in AppleDouble format
+	 */
+	static bool getFinderInfoFromAppleDouble(SeekableReadStream *stream, MacFinderInfo &outFinderInfo, MacFinderExtendedInfo &outFinderExtendedInfo);
+
+	static bool readAndValidateMacBinaryHeader(SeekableReadStream &stream, byte (&outMacBinaryHeader)[MBI_INFOHDR]);
+
 	static Path constructAppleDoubleName(Path name);
 	static Path disassembleAppleDoubleName(Path name, bool *isAppleDouble);
 




More information about the Scummvm-git-logs mailing list