[Scummvm-cvs-logs] SF.net SVN: scummvm:[48984] scummvm/trunk

sev at users.sourceforge.net sev at users.sourceforge.net
Sun May 9 20:27:57 CEST 2010


Revision: 48984
          http://scummvm.svn.sourceforge.net/scummvm/?rev=48984&view=rev
Author:   sev
Date:     2010-05-09 18:27:56 +0000 (Sun, 09 May 2010)

Log Message:
-----------
Patch #2901515: HE: Resource Forks on Mac OS X

Modified Paths:
--------------
    scummvm/trunk/common/macresman.cpp
    scummvm/trunk/common/macresman.h
    scummvm/trunk/engines/scumm/he/resource_he.cpp

Modified: scummvm/trunk/common/macresman.cpp
===================================================================
--- scummvm/trunk/common/macresman.cpp	2010-05-09 18:15:28 UTC (rev 48983)
+++ scummvm/trunk/common/macresman.cpp	2010-05-09 18:27:56 UTC (rev 48984)
@@ -25,25 +25,31 @@
 
 #include "common/scummsys.h"
 #include "common/debug.h"
-#include "common/file.h"
 #include "common/util.h"
 
+#include "common/file.h"
 #include "common/macresman.h"
 
+#ifdef MACOSX
+#include "common/config-manager.h"
+#include "backends/fs/stdiostream.h"
+#endif
+
 namespace Common {
 
-MacResManager::MacResManager(Common::String fileName) : _fileName(fileName), _resOffset(-1) {
-	_resFile.open(_fileName);
+MacResManager::MacResManager() {
+	memset(this, 0, sizeof(MacResManager));
+	close();
+}
 
-	if (!_resFile.isOpen()) {
-		error("Cannot open file %s", _fileName.c_str());
-	}
-
-	if (!init())
-		error("Resource fork is missing in file '%s'", _fileName.c_str());
+MacResManager::~MacResManager() {
+	close();
 }
 
-MacResManager::~MacResManager() {
+void MacResManager::close() {
+	_resForkOffset = -1;
+	_mode = kResForkNone;
+
 	for (int i = 0; i < _resMap.numTypes; i++) {
 		for (int j = 0; j < _resTypes[i].items; j++) {
 			if (_resLists[i][j].nameOffset != -1) {
@@ -53,12 +59,88 @@
 		delete _resLists[i];
 	}
 
-	delete _resLists;
-	delete _resTypes;
+	delete _resLists; _resLists = 0;
+	delete _resTypes; _resTypes = 0;
+	delete _stream; _stream = 0;
+}
 
-	_resFile.close();
+bool MacResManager::hasDataFork() {
+	return !_baseFileName.empty();
 }
 
+bool MacResManager::hasResFork() {
+	return !_baseFileName.empty() && _mode != kResForkNone;
+}
+
+bool MacResManager::open(Common::String filename) {
+	close();
+
+#ifdef MACOSX
+	// Check the actual fork on a Mac computer
+	Common::String fullPath = ConfMan.get("path") + "/" + filename + "/..namedfork/rsrc";
+
+	if (loadFromRawFork(*StdioStream::makeFromPath(fullPath, false))) {
+		_baseFileName = filename;
+		return true;
+	}
+#endif
+
+	Common::File *file = new Common::File();
+
+	// First, let's try to see if the Mac converted name exists
+	if (file->open("._" + filename) && loadFromAppleDouble(*file)) {
+		_baseFileName = filename;
+		return true;
+	}
+
+	// Check .bin too
+	if (file->open(filename + ".bin") && loadFromMacBinary(*file)) {
+		_baseFileName = filename;
+		return true;
+	}
+		
+	// Maybe we have a dumped fork?
+	if (file->open(filename + ".rsrc") && loadFromRawFork(*file)) {
+		_baseFileName = filename;
+		return true;
+	}
+
+	// Fine, what about just the data fork?
+	if (file->open(filename)) {
+		_baseFileName = filename;
+		return true;
+	}
+		
+	delete file;
+
+	// The file doesn't exist
+	return false;
+}
+
+bool MacResManager::loadFromAppleDouble(Common::SeekableReadStream &stream) {
+	if (stream.readUint32BE() != 0x00051607) // tag
+		return false;
+
+	stream.skip(20); // version + home file system
+
+	uint16 entryCount = stream.readUint16BE();
+
+	for (uint16 i = 0; i < entryCount; i++) {
+		uint32 id = stream.readUint32BE();
+		uint32 offset = stream.readUint32BE();
+		stream.readUint32BE(); // length
+
+		if (id == 1) {
+			// Found the data fork!
+			_resForkOffset = offset;
+			_mode = kResForkAppleDouble;
+			return load(stream);
+		}
+	}
+
+	return false;
+}
+
 #define MBI_INFOHDR 128
 #define MBI_ZERO1 0
 #define MBI_NAMELEN 1
@@ -68,64 +150,92 @@
 #define MBI_RFLEN 87
 #define MAXNAMELEN 63
 
-bool MacResManager::init() {
+bool MacResManager::loadFromMacBinary(Common::SeekableReadStream &stream) {
 	byte infoHeader[MBI_INFOHDR];
-	int32 data_size, rsrc_size;
-	int32 data_size_pad, rsrc_size_pad;
-	int filelen;
+	stream.read(infoHeader, MBI_INFOHDR);
 
-	filelen = _resFile.size();
-	_resFile.read(infoHeader, MBI_INFOHDR);
-
 	// Maybe we have MacBinary?
 	if (infoHeader[MBI_ZERO1] == 0 && infoHeader[MBI_ZERO2] == 0 &&
 		infoHeader[MBI_ZERO3] == 0 && infoHeader[MBI_NAMELEN] <= MAXNAMELEN) {
 
 		// Pull out fork lengths
-		data_size = READ_BE_UINT32(infoHeader + MBI_DFLEN);
-		rsrc_size = READ_BE_UINT32(infoHeader + MBI_RFLEN);
+		uint32 dataSize = READ_BE_UINT32(infoHeader + MBI_DFLEN);
+		uint32 rsrcSize = READ_BE_UINT32(infoHeader + MBI_RFLEN);
 
-		data_size_pad = (((data_size + 127) >> 7) << 7);
-		rsrc_size_pad = (((rsrc_size + 127) >> 7) << 7);
+		uint32 dataSizePad = (((dataSize + 127) >> 7) << 7);
+		uint32 rsrcSizePad = (((rsrcSize + 127) >> 7) << 7);
 
 		// Length check
-		int sumlen =  MBI_INFOHDR + data_size_pad + rsrc_size_pad;
-
-		if (sumlen == filelen)
-			_resOffset = MBI_INFOHDR + data_size_pad;
+		if (MBI_INFOHDR + dataSizePad + rsrcSizePad == (uint32)stream.size())
+			_resForkOffset = MBI_INFOHDR + dataSizePad;
 	}
 
-	if (_resOffset == -1) // MacBinary check is failed
-		_resOffset = 0; // Maybe we have dumped fork?
+	if (_resForkOffset < 0)
+		return false;
 
-	_resFile.seek(_resOffset);
+	_mode = kResForkMacBinary;
+	return load(stream);
+}
 
-	_dataOffset = _resFile.readUint32BE() + _resOffset;
-	_mapOffset = _resFile.readUint32BE() + _resOffset;
-	_dataLength = _resFile.readUint32BE();
-	_mapLength = _resFile.readUint32BE();
+bool MacResManager::loadFromRawFork(Common::SeekableReadStream &stream) {
+	_mode = kResForkRaw;
+	_resForkOffset = 0;
+	return load(stream);
+}
 
+bool MacResManager::load(Common::SeekableReadStream &stream) {
+	if (_mode == kResForkNone)
+		return false;
+
+	stream.seek(_resForkOffset);
+
+	_dataOffset = stream.readUint32BE() + _resForkOffset;
+	_mapOffset = stream.readUint32BE() + _resForkOffset;
+	_dataLength = stream.readUint32BE();
+	_mapLength = stream.readUint32BE();
+
 	// do sanity check
-	if (_dataOffset >= filelen || _mapOffset >= filelen ||
-		_dataLength + _mapLength  > filelen) {
-		_resOffset = -1;
+	if (_dataOffset >= (uint32)stream.size() || _mapOffset >= (uint32)stream.size() ||
+		_dataLength + _mapLength  > (uint32)stream.size()) {
+		_resForkOffset = -1;
+		_mode = kResForkNone;
 		return false;
 	}
 
 	debug(7, "got header: data %d [%d] map %d [%d]",
 		_dataOffset, _dataLength, _mapOffset, _mapLength);
+		
+	_stream = &stream;
 
 	readMap();
-
 	return true;
 }
 
-MacResIDArray MacResManager::getResIDArray(const char *typeID) {
+Common::SeekableReadStream *MacResManager::getDataFork() {
+	if (!_stream)
+		return NULL;
+
+	if (_mode == kResForkMacBinary) {
+		_stream->seek(MBI_DFLEN);
+		uint32 dataSize = _stream->readUint32BE();
+		_stream->seek(MBI_INFOHDR);
+		return _stream->readStream(dataSize);
+	}
+
+	Common::File *file = new Common::File();
+	if (file->open(_baseFileName))
+		return file;
+	delete file;
+
+	return NULL;
+}
+
+MacResIDArray MacResManager::getResIDArray(uint32 typeID) {
 	int typeNum = -1;
 	MacResIDArray res;
 
 	for (int i = 0; i < _resMap.numTypes; i++)
-		if (strcmp(_resTypes[i].id, typeID) == 0) {
+		if (_resTypes[i].id ==  typeID) {
 			typeNum = i;
 			break;
 		}
@@ -141,35 +251,31 @@
 	return res;
 }
 
-char *MacResManager::getResName(const char *typeID, int16 resID) {
-	int i;
+Common::String MacResManager::getResName(uint32 typeID, uint16 resID) {
 	int typeNum = -1;
 
-	for (i = 0; i < _resMap.numTypes; i++)
-		if (strcmp(_resTypes[i].id, typeID) == 0) {
+	for (int i = 0; i < _resMap.numTypes; i++)
+		if (_resTypes[i].id == typeID) {
 			typeNum = i;
 			break;
 		}
 
 	if (typeNum == -1)
-		return NULL;
+		return "";
 
-	for (i = 0; i < _resTypes[typeNum].items; i++)
+	for (int i = 0; i < _resTypes[typeNum].items; i++)
 		if (_resLists[typeNum][i].id == resID)
 			return _resLists[typeNum][i].name;
 
-	return NULL;
+	return "";
 }
 
-byte *MacResManager::getResource(const char *typeID, int16 resID, int *size) {
-	int i;
+Common::SeekableReadStream *MacResManager::getResource(uint32 typeID, uint16 resID) {
 	int typeNum = -1;
 	int resNum = -1;
-	byte *buf;
-	int len;
 
-	for (i = 0; i < _resMap.numTypes; i++)
-		if (strcmp(_resTypes[i].id, typeID) == 0) {
+	for (int i = 0; i < _resMap.numTypes; i++)
+		if (_resTypes[i].id == typeID) {
 			typeNum = i;
 			break;
 		}
@@ -177,7 +283,7 @@
 	if (typeNum == -1)
 		return NULL;
 
-	for (i = 0; i < _resTypes[typeNum].items; i++)
+	for (int i = 0; i < _resTypes[typeNum].items; i++)
 		if (_resLists[typeNum][i].id == resID) {
 			resNum = i;
 			break;
@@ -186,76 +292,66 @@
 	if (resNum == -1)
 		return NULL;
 
-	_resFile.seek(_dataOffset + _resLists[typeNum][resNum].dataOffset);
-
-	len = _resFile.readUint32BE();
-	buf = (byte *)malloc(len);
-
-	_resFile.read(buf, len);
-
-	*size = len;
-
-	return buf;
+	_stream->seek(_dataOffset + _resLists[typeNum][resNum].dataOffset);
+	uint32 len = _stream->readUint32BE();
+	return _stream->readStream(len);
 }
 
 void MacResManager::readMap() {
-	int	i, j, len;
+	_stream->seek(_mapOffset + 22);
 
-	_resFile.seek(_mapOffset + 22);
-
-	_resMap.resAttr = _resFile.readUint16BE();
-	_resMap.typeOffset = _resFile.readUint16BE();
-	_resMap.nameOffset = _resFile.readUint16BE();
-	_resMap.numTypes = _resFile.readUint16BE();
+	_resMap.resAttr = _stream->readUint16BE();
+	_resMap.typeOffset = _stream->readUint16BE();
+	_resMap.nameOffset = _stream->readUint16BE();
+	_resMap.numTypes = _stream->readUint16BE();
 	_resMap.numTypes++;
 
-	_resFile.seek(_mapOffset + _resMap.typeOffset + 2);
+	_stream->seek(_mapOffset + _resMap.typeOffset + 2);
 	_resTypes = new ResType[_resMap.numTypes];
 
-	for (i = 0; i < _resMap.numTypes; i++) {
-		_resFile.read(_resTypes[i].id, 4);
-		_resTypes[i].id[4] = 0;
-		_resTypes[i].items = _resFile.readUint16BE();
-		_resTypes[i].offset = _resFile.readUint16BE();
+	for (int i = 0; i < _resMap.numTypes; i++) {
+		_resTypes[i].id = _stream->readUint32BE();
+		_resTypes[i].items = _stream->readUint16BE();
+		_resTypes[i].offset = _stream->readUint16BE();
 		_resTypes[i].items++;
 
-		debug(8, "resType: <%s> items: %d offset: %d (0x%x)", _resTypes[i].id, _resTypes[i].items,  _resTypes[i].offset, _resTypes[i].offset);
+		debug(8, "resType: <%s> items: %d offset: %d (0x%x)", tag2str(_resTypes[i].id), _resTypes[i].items,  _resTypes[i].offset, _resTypes[i].offset);
 	}
 
 	_resLists = new ResPtr[_resMap.numTypes];
 
-	for (i = 0; i < _resMap.numTypes; i++) {
+	for (int i = 0; i < _resMap.numTypes; i++) {
 		_resLists[i] = new Resource[_resTypes[i].items];
-		_resFile.seek(_resTypes[i].offset + _mapOffset + _resMap.typeOffset);
+		_stream->seek(_resTypes[i].offset + _mapOffset + _resMap.typeOffset);
 
-		for (j = 0; j < _resTypes[i].items; j++) {
+		for (int j = 0; j < _resTypes[i].items; j++) {
 			ResPtr resPtr = _resLists[i] + j;
 
-			resPtr->id = _resFile.readUint16BE();
-			resPtr->nameOffset = _resFile.readUint16BE();
-			resPtr->dataOffset = _resFile.readUint32BE();
-			_resFile.readUint32BE();
+			resPtr->id = _stream->readUint16BE();
+			resPtr->nameOffset = _stream->readUint16BE();
+			resPtr->dataOffset = _stream->readUint32BE();
+			_stream->readUint32BE();
 			resPtr->name = 0;
 
 			resPtr->attr = resPtr->dataOffset >> 24;
 			resPtr->dataOffset &= 0xFFFFFF;
 		}
 
-		for (j = 0; j < _resTypes[i].items; j++) {
+		for (int j = 0; j < _resTypes[i].items; j++) {
 			if (_resLists[i][j].nameOffset != -1) {
-				_resFile.seek(_resLists[i][j].nameOffset + _mapOffset + _resMap.nameOffset);
+				_stream->seek(_resLists[i][j].nameOffset + _mapOffset + _resMap.nameOffset);
 
-				len = _resFile.readByte();
+				byte len = _stream->readByte();
 				_resLists[i][j].name = new char[len + 1];
 				_resLists[i][j].name[len] = 0;
-				_resFile.read(_resLists[i][j].name, len);
+				_stream->read(_resLists[i][j].name, len);
 			}
 		}
 	}
 }
 
-void MacResManager::convertCursor(byte *data, int datasize, byte **cursor, int *w, int *h,
-					 int *hotspot_x, int *hotspot_y, int *keycolor, bool colored, byte **palette, int *palSize) {
+void MacResManager::convertCrsrCursor(byte *data, int datasize, byte **cursor, int *w, int *h,
+				int *hotspot_x, int *hotspot_y, int *keycolor, bool colored, byte **palette, int *palSize) {
 	Common::MemoryReadStream dis(data, datasize);
 	int i, b;
 	byte imageByte;

Modified: scummvm/trunk/common/macresman.h
===================================================================
--- scummvm/trunk/common/macresman.h	2010-05-09 18:15:28 UTC (rev 48983)
+++ scummvm/trunk/common/macresman.h	2010-05-09 18:27:56 UTC (rev 48984)
@@ -31,7 +31,7 @@
 
 namespace Common {
 
-typedef Common::Array<int16> MacResIDArray;
+typedef Common::Array<uint16> MacResIDArray;
 
 /**
  * Class for reading Mac Binary files.
@@ -40,21 +40,28 @@
 class MacResManager {
 
 public:
-	MacResManager(Common::String fileName);
+	MacResManager();
 	~MacResManager();
+	
+	bool open(Common::String fileName);
+	void close();
 
+	bool hasDataFork();
+	bool hasResFork();
+
 	/**
 	 * Read resource from the Mac Binary file
 	 * @param typeID FourCC with type ID
 	 * @param resID Resource ID to fetch
-	 * @param size Pointer to int where loaded data size will be stored
-	 * @return Pointer to memory with loaded resource. Malloc()'ed
+	 * @return Pointer to a SeekableReadStream with loaded resource
 	 */
-	byte *getResource(const char *typeID, int16 resID, int *size);
+	Common::SeekableReadStream *getResource(uint32 typeID, uint16 resID);
 
-	char *getResName(const char *typeID, int16 resID);
+	Common::SeekableReadStream *getDataFork();
+	Common::String getResName(uint32 typeID, uint16 resID);
+	
 	/**
-	 * Convert cursor from Mac format to format suitable for feeding to CursorMan
+	 * Convert cursor from crsr format to format suitable for feeding to CursorMan
 	 * @param data Pointer to the cursor data
 	 * @param datasize Size of the cursor data
 	 * @param cursor Pointer to memory where result cursor will be stored. The memory
@@ -70,56 +77,65 @@
 	 *                The memory will be malloc()'ed
 	 * @param palSize Pointer to integer where the palette size will be stored.
 	 */
-	void convertCursor(byte *data, int datasize, byte **cursor, int *w, int *h,
+	void convertCrsrCursor(byte *data, int datasize, byte **cursor, int *w, int *h,
 					  int *hotspot_x, int *hotspot_y, int *keycolor, bool colored, byte **palette, int *palSize);
 
 	/**
 	 * Return list of resource IDs with specified type ID
 	 */
-	MacResIDArray getResIDArray(const char *typeID);
+	MacResIDArray getResIDArray(uint32 typeID);
 
-	Common::String getFileName() { return _fileName; }
+private:
+	Common::SeekableReadStream *_stream;
+	Common::String _baseFileName;
 
-private:
-	int extractResource(int id, byte **buf);
-	bool init();
+	bool load(Common::SeekableReadStream &stream);
+
+	bool loadFromRawFork(Common::SeekableReadStream &stream);
+	bool loadFromMacBinary(Common::SeekableReadStream &stream);
+	bool loadFromAppleDouble(Common::SeekableReadStream &stream);
+
+	enum {
+		kResForkNone = 0,
+		kResForkRaw,
+		kResForkMacBinary,
+		kResForkAppleDouble
+	} _mode;
+
 	void readMap();
-
+	
 	struct ResMap {
-		int16 resAttr;
-		int16 typeOffset;
-		int16 nameOffset;
-		int16 numTypes;
+		uint16 resAttr;
+		uint16 typeOffset;
+		uint16 nameOffset;
+		uint16 numTypes;
 	};
 
 	struct ResType {
-		char  id[5];
-		int16 items;
-		int16 offset;
+		uint32 id;
+		uint16 items;
+		uint16 offset;
 	};
 
 	struct Resource {
-		int16 id;
+		uint16 id;
 		int16 nameOffset;
-		byte  attr;
-		int32 dataOffset;
-		char  *name;
+		byte attr;
+		uint32 dataOffset;
+		char *name;
 	};
 
 	typedef Resource *ResPtr;
+	
+	int32 _resForkOffset;
 
-private:
-	int _resOffset;
-	int32 _dataOffset;
-	int32 _dataLength;
-	int32 _mapOffset;
-	int32 _mapLength;
+	uint32 _dataOffset;
+	uint32 _dataLength;
+	uint32 _mapOffset;
+	uint32 _mapLength;
 	ResMap _resMap;
 	ResType *_resTypes;
 	ResPtr  *_resLists;
-
-	Common::String _fileName;
-	Common::File _resFile;
 };
 
 } // End of namespace Common

Modified: scummvm/trunk/engines/scumm/he/resource_he.cpp
===================================================================
--- scummvm/trunk/engines/scumm/he/resource_he.cpp	2010-05-09 18:15:28 UTC (rev 48983)
+++ scummvm/trunk/engines/scumm/he/resource_he.cpp	2010-05-09 18:27:56 UTC (rev 48984)
@@ -1144,59 +1144,34 @@
 }
 
 int MacResExtractor::extractResource(int id, byte **buf) {
-	Common::File in;
-	int size;
-
-	if (_fileName.empty()) { // We are running for the first time
-		_fileName = _vm->generateFilename(-3);
-
-		// Some programs write it as .bin. Try that too
-		if (!in.open(_fileName)) {
-			Common::String tmp(_fileName);
-
-			_fileName += ".bin";
-
-			if (!in.open(_fileName)) {
-				// And finally check if we have dumped resource fork
-				_fileName = tmp;
-				_fileName += ".bin";
-				if (!in.open(_fileName)) {
-					error("Cannot open file any of files '%s', '%s.bin', '%s.rsrc",
-						  tmp.c_str(), tmp.c_str(), tmp.c_str());
-				}
-			}
-		}
-	} else
-		in.open(_fileName);
-
-	if (!in.isOpen()) {
-		error("Cannot open file %s", _fileName.c_str());
+	// Create the MacResManager if not created already
+	if (_resMgr == NULL) {
+		_resMgr = new Common::MacResManager();
+		if (!_resMgr->open(_vm->generateFilename(-3)))
+			error("Cannot open file %s", _fileName.c_str());
 	}
-	in.close();
 
-	if (_resMgr == NULL)
-		_resMgr = new Common::MacResManager(_fileName);
-
-
-	*buf = _resMgr->getResource("crsr", 1000 + id, &size);
-
-	if (*buf == NULL)
+	Common::SeekableReadStream *dataStream = _resMgr->getResource('crsr', 1000 + id);
+	
+	if (!dataStream)
 		error("There is no cursor ID #%d", 1000 + id);
+	
+	uint32 size = dataStream->size();
+	*buf = (byte *)malloc(size);
+	dataStream->read(*buf, size);
+	delete dataStream;
 
 	return size;
 }
 
 int MacResExtractor::convertIcons(byte *data, int datasize, byte **cursor, int *w, int *h,
 			  int *hotspot_x, int *hotspot_y, int *keycolor, byte **palette, int *palSize) {
-
-	_resMgr->convertCursor(data, datasize, cursor, w, h, hotspot_x, hotspot_y, keycolor,
-						   _vm->_system->hasFeature(OSystem::kFeatureCursorHasPalette), palette, palSize);
-
+			  
+	_resMgr->convertCrsrCursor(data, datasize, cursor, w, h, hotspot_x, hotspot_y, keycolor,
+						_vm->_system->hasFeature(OSystem::kFeatureCursorHasPalette), palette, palSize);
 	return 1;
 }
 
-
-
 void ScummEngine_v70he::readRoomsOffsets() {
 	int num, i;
 	byte *ptr;


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.




More information about the Scummvm-git-logs mailing list