aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugene Sandulenko2010-05-09 18:27:56 +0000
committerEugene Sandulenko2010-05-09 18:27:56 +0000
commit57f2425b28575a06ae483b57afe316dd80c46323 (patch)
treebadbfa1b805e37ad2f27ef6a2475d45581706756
parent99be18906835207af566264efac4b0242b2763d2 (diff)
downloadscummvm-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.cpp280
-rw-r--r--common/macresman.h84
-rw-r--r--engines/scumm/he/resource_he.cpp57
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;