diff options
author | Eugene Sandulenko | 2010-05-09 18:27:56 +0000 |
---|---|---|
committer | Eugene Sandulenko | 2010-05-09 18:27:56 +0000 |
commit | 57f2425b28575a06ae483b57afe316dd80c46323 (patch) | |
tree | badbfa1b805e37ad2f27ef6a2475d45581706756 | |
parent | 99be18906835207af566264efac4b0242b2763d2 (diff) | |
download | scummvm-rg350-57f2425b28575a06ae483b57afe316dd80c46323.tar.gz scummvm-rg350-57f2425b28575a06ae483b57afe316dd80c46323.tar.bz2 scummvm-rg350-57f2425b28575a06ae483b57afe316dd80c46323.zip |
Patch #2901515: HE: Resource Forks on Mac OS X
svn-id: r48984
-rw-r--r-- | common/macresman.cpp | 280 | ||||
-rw-r--r-- | common/macresman.h | 84 | ||||
-rw-r--r-- | engines/scumm/he/resource_he.cpp | 57 |
3 files changed, 254 insertions, 167 deletions
diff --git a/common/macresman.cpp b/common/macresman.cpp index ca5fe0cfd8..d58bfcd81f 100644 --- a/common/macresman.cpp +++ b/common/macresman.cpp @@ -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" -namespace Common { +#ifdef MACOSX +#include "common/config-manager.h" +#include "backends/fs/stdiostream.h" +#endif -MacResManager::MacResManager(Common::String fileName) : _fileName(fileName), _resOffset(-1) { - _resFile.open(_fileName); - - if (!_resFile.isOpen()) { - error("Cannot open file %s", _fileName.c_str()); - } +namespace Common { - if (!init()) - error("Resource fork is missing in file '%s'", _fileName.c_str()); +MacResManager::MacResManager() { + memset(this, 0, sizeof(MacResManager)); + close(); } MacResManager::~MacResManager() { + close(); +} + +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,10 +59,86 @@ MacResManager::~MacResManager() { delete _resLists[i]; } - delete _resLists; - delete _resTypes; + delete _resLists; _resLists = 0; + delete _resTypes; _resTypes = 0; + delete _stream; _stream = 0; +} + +bool MacResManager::hasDataFork() { + return !_baseFileName.empty(); +} - _resFile.close(); +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 @@ -68,64 +150,92 @@ MacResManager::~MacResManager() { #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; - - filelen = _resFile.size(); - _resFile.read(infoHeader, MBI_INFOHDR); + stream.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); +} + +bool MacResManager::loadFromRawFork(Common::SeekableReadStream &stream) { + _mode = kResForkRaw; + _resForkOffset = 0; + return load(stream); +} + +bool MacResManager::load(Common::SeekableReadStream &stream) { + if (_mode == kResForkNone) + return false; - _dataOffset = _resFile.readUint32BE() + _resOffset; - _mapOffset = _resFile.readUint32BE() + _resOffset; - _dataLength = _resFile.readUint32BE(); - _mapLength = _resFile.readUint32BE(); + 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 @@ MacResIDArray MacResManager::getResIDArray(const char *typeID) { 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 @@ byte *MacResManager::getResource(const char *typeID, int16 resID, int *size) { 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 @@ byte *MacResManager::getResource(const char *typeID, int16 resID, int *size) { 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; - - _resFile.seek(_mapOffset + 22); + _stream->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; diff --git a/common/macresman.h b/common/macresman.h index fd4557f92c..2f47a67fa2 100644 --- a/common/macresman.h +++ b/common/macresman.h @@ -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 @@ typedef Common::Array<int16> MacResIDArray; 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 @@ public: * 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); - - Common::String getFileName() { return _fileName; } + MacResIDArray getResIDArray(uint32 typeID); private: - int extractResource(int id, byte **buf); - bool init(); - void readMap(); + Common::SeekableReadStream *_stream; + Common::String _baseFileName; + + 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 diff --git a/engines/scumm/he/resource_he.cpp b/engines/scumm/he/resource_he.cpp index 967acebc1e..886ee99e57 100644 --- a/engines/scumm/he/resource_he.cpp +++ b/engines/scumm/he/resource_he.cpp @@ -1144,59 +1144,34 @@ MacResExtractor::MacResExtractor(ScummEngine_v70he *scumm) : ResExtractor(scumm) } 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; |