diff options
Diffstat (limited to 'common/macresman.cpp')
| -rw-r--r-- | common/macresman.cpp | 111 | 
1 files changed, 111 insertions, 0 deletions
| diff --git a/common/macresman.cpp b/common/macresman.cpp index d83bde8fd8..adca1ea10b 100644 --- a/common/macresman.cpp +++ b/common/macresman.cpp @@ -29,6 +29,7 @@  #include "common/md5.h"  #include "common/substream.h"  #include "common/textconsole.h" +#include "common/archive.h"  #ifdef MACOSX  #include "common/config-manager.h" @@ -261,6 +262,76 @@ bool MacResManager::exists(const String &fileName) {  	return false;  } +void MacResManager::listFiles(StringArray &files, const String &pattern) { +	// Base names discovered so far. +	typedef HashMap<String, bool, IgnoreCase_Hash, IgnoreCase_EqualTo> BaseNameSet; +	BaseNameSet baseNames; + +	// List files itself. +	ArchiveMemberList memberList; +	SearchMan.listMatchingMembers(memberList, pattern); +	SearchMan.listMatchingMembers(memberList, pattern + ".rsrc"); +	SearchMan.listMatchingMembers(memberList, pattern + ".bin"); +	SearchMan.listMatchingMembers(memberList, constructAppleDoubleName(pattern)); + +	for (ArchiveMemberList::const_iterator i = memberList.begin(), end = memberList.end(); i != end; ++i) { +		String filename = (*i)->getName(); + +		// For raw resource forks and MacBinary files we strip the extension +		// here to obtain a valid base name. +		int lastDotPos = filename.size() - 1; +		for (; lastDotPos >= 0; --lastDotPos) { +			if (filename[lastDotPos] == '.') { +				break; +			} +		} + +		if (lastDotPos != -1) { +			const char *extension = filename.c_str() + lastDotPos + 1; +			bool removeExtension = false; + +			// TODO: Should we really keep filenames suggesting raw resource +			// forks or MacBinary files but not being such around? This might +			// depend on the pattern the client requests... +			if (!scumm_stricmp(extension, "rsrc")) { +				SeekableReadStream *stream = (*i)->createReadStream(); +				removeExtension = stream && isRawFork(*stream); +				delete stream; +			} else if (!scumm_stricmp(extension, "bin")) { +				SeekableReadStream *stream = (*i)->createReadStream(); +				removeExtension = stream && isMacBinary(*stream); +				delete stream; +			} + +			if (removeExtension) { +				filename.erase(lastDotPos); +			} +		} + +		// Strip AppleDouble '._' prefix if applicable. +		bool isAppleDoubleName = false; +		const String filenameAppleDoubleStripped = disassembleAppleDoubleName(filename, &isAppleDoubleName); + +		if (isAppleDoubleName) { +			SeekableReadStream *stream = (*i)->createReadStream(); +			if (stream->readUint32BE() == 0x00051607) { +				filename = filenameAppleDoubleStripped; +			} +			// TODO: Should we really keep filenames suggesting AppleDouble +			// but not being AppleDouble around? This might depend on the +			// pattern the client requests... +			delete stream; +		} + +		baseNames[filename] = true; +	} + +	// Append resulting base names to list to indicate found files. +	for (BaseNameSet::const_iterator i = baseNames.begin(), end = baseNames.end(); i != end; ++i) { +		files.push_back(i->_key); +	} +} +  bool MacResManager::loadFromAppleDouble(SeekableReadStream &stream) {  	if (stream.readUint32BE() != 0x00051607) // tag  		return false; @@ -314,6 +385,18 @@ bool MacResManager::isMacBinary(SeekableReadStream &stream) {  	return true;  } +bool MacResManager::isRawFork(SeekableReadStream &stream) { +	// TODO: Is there a better way to detect whether this is a raw fork? +	const uint32 dataOffset = stream.readUint32BE(); +	const uint32 mapOffset = stream.readUint32BE(); +	const uint32 dataLength = stream.readUint32BE(); +	const uint32 mapLength = stream.readUint32BE(); + +	return    !stream.eos() && !stream.err() +	       && dataOffset < (uint32)stream.size() && dataOffset + dataLength <= (uint32)stream.size() +	       && mapOffset < (uint32)stream.size() && mapOffset + mapLength <= (uint32)stream.size(); +} +  bool MacResManager::loadFromMacBinary(SeekableReadStream &stream) {  	byte infoHeader[MBI_INFOHDR];  	stream.read(infoHeader, MBI_INFOHDR); @@ -592,4 +675,32 @@ String MacResManager::constructAppleDoubleName(String name) {  	return name;  } +String MacResManager::disassembleAppleDoubleName(String name, bool *isAppleDouble) { +	if (isAppleDouble) { +		*isAppleDouble = false; +	} + +	// Remove "._" before the last portion of a path name. +	for (int i = name.size() - 1; i >= 0; --i) { +		if (i == 0) { +			if (name.size() > 2 && name[0] == '.' && name[1] == '_') { +				name.erase(0, 2); +				if (isAppleDouble) { +					*isAppleDouble = true; +				} +			} +		} else if (name[i] == '/') { +			if ((uint)(i + 2) < name.size() && name[i + 1] == '.' && name[i + 2] == '_') { +				name.erase(i + 1, 2); +				if (isAppleDouble) { +					*isAppleDouble = true; +				} +			} +			break; +		} +	} + +	return name; +} +  } // End of namespace Common | 
