Ticket #9112: mac_resfork_4-7-2010.diff
File mac_resfork_4-7-2010.diff, 17.4 KB (added by , 14 years ago) |
---|
-
common/macresman.cpp
25 25 26 26 #include "common/scummsys.h" 27 27 #include "common/debug.h" 28 #include "common/file.h"29 28 #include "common/util.h" 30 29 30 #include "common/file.h" 31 31 #include "common/macresman.h" 32 32 33 #ifdef MACOSX 34 #include "common/config-manager.h" 35 #include "backends/fs/stdiostream.h" 36 #endif 37 33 38 namespace Common { 34 39 35 MacResManager::MacResManager(Common::String fileName) : _fileName(fileName), _resOffset(-1) { 36 _resFile.open(_fileName); 40 MacResManager::MacResManager() { 41 memset(this, 0, sizeof(MacResManager)); 42 close(); 43 } 37 44 38 if (!_resFile.isOpen()) { 39 error("Cannot open file %s", _fileName.c_str()); 40 } 41 42 if (!init()) 43 error("Resource fork is missing in file '%s'", _fileName.c_str()); 45 MacResManager::~MacResManager() { 46 close(); 44 47 } 45 48 46 MacResManager::~MacResManager() { 49 void MacResManager::close() { 50 _resForkOffset = -1; 51 _mode = kResForkNone; 52 47 53 for (int i = 0; i < _resMap.numTypes; i++) { 48 54 for (int j = 0; j < _resTypes[i].items; j++) { 49 55 if (_resLists[i][j].nameOffset != -1) { … … 53 59 delete _resLists[i]; 54 60 } 55 61 56 delete _resLists; 57 delete _resTypes; 62 delete _resLists; _resLists = 0; 63 delete _resTypes; _resTypes = 0; 64 delete _stream; _stream = 0; 65 } 58 66 59 _resFile.close(); 67 bool MacResManager::hasDataFork() { 68 return !_baseFileName.empty(); 60 69 } 61 70 71 bool MacResManager::hasResFork() { 72 return !_baseFileName.empty() && _mode != kResForkNone; 73 } 74 75 bool MacResManager::open(Common::String filename) { 76 close(); 77 78 #ifdef MACOSX 79 // Check the actual fork on a Mac computer 80 Common::String fullPath = ConfMan.get("path") + "/" + filename + "/..namedfork/rsrc"; 81 82 if (loadFromRawFork(*StdioStream::makeFromPath(fullPath, false))) { 83 _baseFileName = filename; 84 return true; 85 } 86 #endif 87 88 Common::File *file = new Common::File(); 89 90 // First, let's try to see if the Mac converted name exists 91 if (file->open("._" + filename) && loadFromAppleDouble(*file)) { 92 _baseFileName = filename; 93 return true; 94 } 95 96 // Check .bin too 97 if (file->open(filename + ".bin") && loadFromMacBinary(*file)) { 98 _baseFileName = filename; 99 return true; 100 } 101 102 // Maybe we have a dumped fork? 103 if (file->open(filename + ".rsrc") && loadFromRawFork(*file)) { 104 _baseFileName = filename; 105 return true; 106 } 107 108 // Fine, what about just the data fork? 109 if (file->open(filename)) { 110 _baseFileName = filename; 111 return true; 112 } 113 114 delete file; 115 116 // The file doesn't exist 117 return false; 118 } 119 120 bool MacResManager::loadFromAppleDouble(Common::SeekableReadStream &stream) { 121 if (stream.readUint32BE() != 0x00051607) // tag 122 return false; 123 124 stream.skip(20); // version + home file system 125 126 uint16 entryCount = stream.readUint16BE(); 127 128 for (uint16 i = 0; i < entryCount; i++) { 129 uint32 id = stream.readUint32BE(); 130 uint32 offset = stream.readUint32BE(); 131 stream.readUint32BE(); // length 132 133 if (id == 1) { 134 // Found the data fork! 135 _resForkOffset = offset; 136 _mode = kResForkAppleDouble; 137 return load(stream); 138 } 139 } 140 141 return false; 142 } 143 62 144 #define MBI_INFOHDR 128 63 145 #define MBI_ZERO1 0 64 146 #define MBI_NAMELEN 1 … … 68 150 #define MBI_RFLEN 87 69 151 #define MAXNAMELEN 63 70 152 71 bool MacResManager:: init() {153 bool MacResManager::loadFromMacBinary(Common::SeekableReadStream &stream) { 72 154 byte infoHeader[MBI_INFOHDR]; 73 int32 data_size, rsrc_size; 74 int32 data_size_pad, rsrc_size_pad; 75 int filelen; 155 stream.read(infoHeader, MBI_INFOHDR); 76 156 77 filelen = _resFile.size();78 _resFile.read(infoHeader, MBI_INFOHDR);79 80 157 // Maybe we have MacBinary? 81 158 if (infoHeader[MBI_ZERO1] == 0 && infoHeader[MBI_ZERO2] == 0 && 82 159 infoHeader[MBI_ZERO3] == 0 && infoHeader[MBI_NAMELEN] <= MAXNAMELEN) { 83 160 84 161 // Pull out fork lengths 85 data_size = READ_BE_UINT32(infoHeader + MBI_DFLEN);86 rsrc_size = READ_BE_UINT32(infoHeader + MBI_RFLEN);162 uint32 dataSize = READ_BE_UINT32(infoHeader + MBI_DFLEN); 163 uint32 rsrcSize = READ_BE_UINT32(infoHeader + MBI_RFLEN); 87 164 88 data_size_pad = (((data_size + 127) >> 7) << 7);89 rsrc_size_pad = (((rsrc_size + 127) >> 7) << 7);165 uint32 dataSizePad = (((dataSize + 127) >> 7) << 7); 166 uint32 rsrcSizePad = (((rsrcSize + 127) >> 7) << 7); 90 167 91 168 // Length check 92 int sumlen = MBI_INFOHDR + data_size_pad + rsrc_size_pad; 93 94 if (sumlen == filelen) 95 _resOffset = MBI_INFOHDR + data_size_pad; 169 if (MBI_INFOHDR + dataSizePad + rsrcSizePad == (uint32)stream.size()) 170 _resForkOffset = MBI_INFOHDR + dataSizePad; 96 171 } 97 172 98 if (_res Offset == -1) // MacBinary check is failed99 _resOffset = 0; // Maybe we have dumped fork?173 if (_resForkOffset < 0) 174 return false; 100 175 101 _resFile.seek(_resOffset); 176 _mode = kResForkMacBinary; 177 return load(stream); 178 } 102 179 103 _dataOffset = _resFile.readUint32BE() + _resOffset; 104 _mapOffset = _resFile.readUint32BE() + _resOffset; 105 _dataLength = _resFile.readUint32BE(); 106 _mapLength = _resFile.readUint32BE(); 180 bool MacResManager::loadFromRawFork(Common::SeekableReadStream &stream) { 181 _mode = kResForkRaw; 182 _resForkOffset = 0; 183 return load(stream); 184 } 107 185 186 bool MacResManager::load(Common::SeekableReadStream &stream) { 187 if (_mode == kResForkNone) 188 return false; 189 190 stream.seek(_resForkOffset); 191 192 _dataOffset = stream.readUint32BE() + _resForkOffset; 193 _mapOffset = stream.readUint32BE() + _resForkOffset; 194 _dataLength = stream.readUint32BE(); 195 _mapLength = stream.readUint32BE(); 196 108 197 // do sanity check 109 if (_dataOffset >= filelen || _mapOffset >= filelen || 110 _dataLength + _mapLength > filelen) { 111 _resOffset = -1; 198 if (_dataOffset >= (uint32)stream.size() || _mapOffset >= (uint32)stream.size() || 199 _dataLength + _mapLength > (uint32)stream.size()) { 200 _resForkOffset = -1; 201 _mode = kResForkNone; 112 202 return false; 113 203 } 114 204 115 205 debug(7, "got header: data %d [%d] map %d [%d]", 116 206 _dataOffset, _dataLength, _mapOffset, _mapLength); 207 208 _stream = &stream; 117 209 118 210 readMap(); 119 120 211 return true; 121 212 } 122 213 123 MacResIDArray MacResManager::getResIDArray(const char *typeID) { 214 Common::SeekableReadStream *MacResManager::getDataFork() { 215 if (!_stream) 216 return NULL; 217 218 if (_mode == kResForkMacBinary) { 219 _stream->seek(MBI_DFLEN); 220 uint32 dataSize = _stream->readUint32BE(); 221 _stream->seek(MBI_INFOHDR); 222 return _stream->readStream(dataSize); 223 } 224 225 Common::File *file = new Common::File(); 226 if (file->open(_baseFileName)) 227 return file; 228 delete file; 229 230 return NULL; 231 } 232 233 MacResIDArray MacResManager::getResIDArray(uint32 typeID) { 124 234 int typeNum = -1; 125 235 MacResIDArray res; 126 236 127 237 for (int i = 0; i < _resMap.numTypes; i++) 128 if ( strcmp(_resTypes[i].id, typeID) == 0) {238 if (_resTypes[i].id == typeID) { 129 239 typeNum = i; 130 240 break; 131 241 } … … 141 251 return res; 142 252 } 143 253 144 char *MacResManager::getResName(const char *typeID, int16 resID) { 145 int i; 254 Common::String MacResManager::getResName(uint32 typeID, uint16 resID) { 146 255 int typeNum = -1; 147 256 148 for (i = 0; i < _resMap.numTypes; i++)149 if ( strcmp(_resTypes[i].id, typeID) == 0) {257 for (int i = 0; i < _resMap.numTypes; i++) 258 if (_resTypes[i].id == typeID) { 150 259 typeNum = i; 151 260 break; 152 261 } 153 262 154 263 if (typeNum == -1) 155 return NULL;264 return ""; 156 265 157 for (i = 0; i < _resTypes[typeNum].items; i++)266 for (int i = 0; i < _resTypes[typeNum].items; i++) 158 267 if (_resLists[typeNum][i].id == resID) 159 268 return _resLists[typeNum][i].name; 160 269 161 return NULL;270 return ""; 162 271 } 163 272 164 byte *MacResManager::getResource(const char *typeID, int16 resID, int *size) { 165 int i; 273 Common::SeekableReadStream *MacResManager::getResource(uint32 typeID, uint16 resID) { 166 274 int typeNum = -1; 167 275 int resNum = -1; 168 byte *buf;169 int len;170 276 171 for (i = 0; i < _resMap.numTypes; i++)172 if ( strcmp(_resTypes[i].id, typeID) == 0) {277 for (int i = 0; i < _resMap.numTypes; i++) 278 if (_resTypes[i].id == typeID) { 173 279 typeNum = i; 174 280 break; 175 281 } … … 177 283 if (typeNum == -1) 178 284 return NULL; 179 285 180 for (i = 0; i < _resTypes[typeNum].items; i++)286 for (int i = 0; i < _resTypes[typeNum].items; i++) 181 287 if (_resLists[typeNum][i].id == resID) { 182 288 resNum = i; 183 289 break; … … 186 292 if (resNum == -1) 187 293 return NULL; 188 294 189 _resFile.seek(_dataOffset + _resLists[typeNum][resNum].dataOffset); 190 191 len = _resFile.readUint32BE(); 192 buf = (byte *)malloc(len); 193 194 _resFile.read(buf, len); 195 196 *size = len; 197 198 return buf; 295 _stream->seek(_dataOffset + _resLists[typeNum][resNum].dataOffset); 296 uint32 len = _stream->readUint32BE(); 297 return _stream->readStream(len); 199 298 } 200 299 201 300 void MacResManager::readMap() { 202 int i, j, len;301 _stream->seek(_mapOffset + 22); 203 302 204 _resFile.seek(_mapOffset + 22); 205 206 _resMap.resAttr = _resFile.readUint16BE(); 207 _resMap.typeOffset = _resFile.readUint16BE(); 208 _resMap.nameOffset = _resFile.readUint16BE(); 209 _resMap.numTypes = _resFile.readUint16BE(); 303 _resMap.resAttr = _stream->readUint16BE(); 304 _resMap.typeOffset = _stream->readUint16BE(); 305 _resMap.nameOffset = _stream->readUint16BE(); 306 _resMap.numTypes = _stream->readUint16BE(); 210 307 _resMap.numTypes++; 211 308 212 _ resFile.seek(_mapOffset + _resMap.typeOffset + 2);309 _stream->seek(_mapOffset + _resMap.typeOffset + 2); 213 310 _resTypes = new ResType[_resMap.numTypes]; 214 311 215 for (i = 0; i < _resMap.numTypes; i++) { 216 _resFile.read(_resTypes[i].id, 4); 217 _resTypes[i].id[4] = 0; 218 _resTypes[i].items = _resFile.readUint16BE(); 219 _resTypes[i].offset = _resFile.readUint16BE(); 312 for (int i = 0; i < _resMap.numTypes; i++) { 313 _resTypes[i].id = _stream->readUint32BE(); 314 _resTypes[i].items = _stream->readUint16BE(); 315 _resTypes[i].offset = _stream->readUint16BE(); 220 316 _resTypes[i].items++; 221 317 222 debug(8, "resType: <%s> items: %d offset: %d (0x%x)", _resTypes[i].id, _resTypes[i].items, _resTypes[i].offset, _resTypes[i].offset);318 debug(8, "resType: <%s> items: %d offset: %d (0x%x)", tag2str(_resTypes[i].id), _resTypes[i].items, _resTypes[i].offset, _resTypes[i].offset); 223 319 } 224 320 225 321 _resLists = new ResPtr[_resMap.numTypes]; 226 322 227 for (i = 0; i < _resMap.numTypes; i++) {323 for (int i = 0; i < _resMap.numTypes; i++) { 228 324 _resLists[i] = new Resource[_resTypes[i].items]; 229 _ resFile.seek(_resTypes[i].offset + _mapOffset + _resMap.typeOffset);325 _stream->seek(_resTypes[i].offset + _mapOffset + _resMap.typeOffset); 230 326 231 for ( j = 0; j < _resTypes[i].items; j++) {327 for (int j = 0; j < _resTypes[i].items; j++) { 232 328 ResPtr resPtr = _resLists[i] + j; 233 329 234 resPtr->id = _ resFile.readUint16BE();235 resPtr->nameOffset = _ resFile.readUint16BE();236 resPtr->dataOffset = _ resFile.readUint32BE();237 _ resFile.readUint32BE();330 resPtr->id = _stream->readUint16BE(); 331 resPtr->nameOffset = _stream->readUint16BE(); 332 resPtr->dataOffset = _stream->readUint32BE(); 333 _stream->readUint32BE(); 238 334 resPtr->name = 0; 239 335 240 336 resPtr->attr = resPtr->dataOffset >> 24; 241 337 resPtr->dataOffset &= 0xFFFFFF; 242 338 } 243 339 244 for ( j = 0; j < _resTypes[i].items; j++) {340 for (int j = 0; j < _resTypes[i].items; j++) { 245 341 if (_resLists[i][j].nameOffset != -1) { 246 _ resFile.seek(_resLists[i][j].nameOffset + _mapOffset + _resMap.nameOffset);342 _stream->seek(_resLists[i][j].nameOffset + _mapOffset + _resMap.nameOffset); 247 343 248 len = _resFile.readByte();344 byte len = _stream->readByte(); 249 345 _resLists[i][j].name = new char[len + 1]; 250 346 _resLists[i][j].name[len] = 0; 251 _ resFile.read(_resLists[i][j].name, len);347 _stream->read(_resLists[i][j].name, len); 252 348 } 253 349 } 254 350 } 255 351 } 256 352 257 void MacResManager::convertC ursor(byte *data, int datasize, byte **cursor, int *w, int *h,258 353 void MacResManager::convertCrsrCursor(byte *data, int datasize, byte **cursor, int *w, int *h, 354 int *hotspot_x, int *hotspot_y, int *keycolor, bool colored, byte **palette, int *palSize) { 259 355 Common::MemoryReadStream dis(data, datasize); 260 356 int i, b; 261 357 byte imageByte; -
common/macresman.h
31 31 32 32 namespace Common { 33 33 34 typedef Common::Array< int16> MacResIDArray;34 typedef Common::Array<uint16> MacResIDArray; 35 35 36 36 /** 37 37 * Class for reading Mac Binary files. … … 40 40 class MacResManager { 41 41 42 42 public: 43 MacResManager( Common::String fileName);43 MacResManager(); 44 44 ~MacResManager(); 45 46 bool open(Common::String fileName); 47 void close(); 45 48 49 bool hasDataFork(); 50 bool hasResFork(); 51 46 52 /** 47 53 * Read resource from the Mac Binary file 48 54 * @param typeID FourCC with type ID 49 55 * @param resID Resource ID to fetch 50 * @param size Pointer to int where loaded data size will be stored 51 * @return Pointer to memory with loaded resource. Malloc()'ed 56 * @return Pointer to a SeekableReadStream with loaded resource 52 57 */ 53 byte *getResource(const char *typeID, int16 resID, int *size);58 Common::SeekableReadStream *getResource(uint32 typeID, uint16 resID); 54 59 55 char *getResName(const char *typeID, int16 resID); 60 Common::SeekableReadStream *getDataFork(); 61 Common::String getResName(uint32 typeID, uint16 resID); 62 56 63 /** 57 * Convert cursor from Macformat to format suitable for feeding to CursorMan64 * Convert cursor from crsr format to format suitable for feeding to CursorMan 58 65 * @param data Pointer to the cursor data 59 66 * @param datasize Size of the cursor data 60 67 * @param cursor Pointer to memory where result cursor will be stored. The memory … … 70 77 * The memory will be malloc()'ed 71 78 * @param palSize Pointer to integer where the palette size will be stored. 72 79 */ 73 void convertC ursor(byte *data, int datasize, byte **cursor, int *w, int *h,80 void convertCrsrCursor(byte *data, int datasize, byte **cursor, int *w, int *h, 74 81 int *hotspot_x, int *hotspot_y, int *keycolor, bool colored, byte **palette, int *palSize); 75 82 76 83 /** 77 84 * Return list of resource IDs with specified type ID 78 85 */ 79 MacResIDArray getResIDArray( const char *typeID);86 MacResIDArray getResIDArray(uint32 typeID); 80 87 81 Common::String getFileName() { return _fileName; } 88 private: 89 Common::SeekableReadStream *_stream; 90 Common::String _baseFileName; 82 91 83 private: 84 int extractResource(int id, byte **buf); 85 bool init(); 92 bool load(Common::SeekableReadStream &stream); 93 94 bool loadFromRawFork(Common::SeekableReadStream &stream); 95 bool loadFromMacBinary(Common::SeekableReadStream &stream); 96 bool loadFromAppleDouble(Common::SeekableReadStream &stream); 97 98 enum { 99 kResForkNone = 0, 100 kResForkRaw, 101 kResForkMacBinary, 102 kResForkAppleDouble 103 } _mode; 104 86 105 void readMap(); 87 106 88 107 struct ResMap { 89 int16 resAttr;90 int16 typeOffset;91 int16 nameOffset;92 int16 numTypes;108 uint16 resAttr; 109 uint16 typeOffset; 110 uint16 nameOffset; 111 uint16 numTypes; 93 112 }; 94 113 95 114 struct ResType { 96 char id[5];97 int16 items;98 int16 offset;115 uint32 id; 116 uint16 items; 117 uint16 offset; 99 118 }; 100 119 101 120 struct Resource { 102 int16 id;121 uint16 id; 103 122 int16 nameOffset; 104 byte 105 int32 dataOffset;106 char 123 byte attr; 124 uint32 dataOffset; 125 char *name; 107 126 }; 108 127 109 128 typedef Resource *ResPtr; 129 130 int32 _resForkOffset; 110 131 111 private: 112 int _resOffset; 113 int32 _dataOffset; 114 int32 _dataLength; 115 int32 _mapOffset; 116 int32 _mapLength; 132 uint32 _dataOffset; 133 uint32 _dataLength; 134 uint32 _mapOffset; 135 uint32 _mapLength; 117 136 ResMap _resMap; 118 137 ResType *_resTypes; 119 138 ResPtr *_resLists; 120 121 Common::String _fileName;122 Common::File _resFile;123 139 }; 124 140 125 141 } // End of namespace Common -
engines/scumm/he/resource_he.cpp
1144 1144 } 1145 1145 1146 1146 int MacResExtractor::extractResource(int id, byte **buf) { 1147 Common::File in; 1148 int size; 1149 1150 if (_fileName.empty()) { // We are running for the first time 1151 _fileName = _vm->generateFilename(-3); 1152 1153 // Some programs write it as .bin. Try that too 1154 if (!in.open(_fileName)) { 1155 Common::String tmp(_fileName); 1156 1157 _fileName += ".bin"; 1158 1159 if (!in.open(_fileName)) { 1160 // And finally check if we have dumped resource fork 1161 _fileName = tmp; 1162 _fileName += ".bin"; 1163 if (!in.open(_fileName)) { 1164 error("Cannot open file any of files '%s', '%s.bin', '%s.rsrc", 1165 tmp.c_str(), tmp.c_str(), tmp.c_str()); 1166 } 1167 } 1168 } 1169 } else 1170 in.open(_fileName); 1171 1172 if (!in.isOpen()) { 1173 error("Cannot open file %s", _fileName.c_str()); 1147 // Create the MacResManager if not created already 1148 if (_resMgr == NULL) { 1149 _resMgr = new Common::MacResManager(); 1150 if (!_resMgr->open(_vm->generateFilename(-3))) 1151 error("Cannot open file %s", _fileName.c_str()); 1174 1152 } 1175 in.close();1176 1153 1177 if (_resMgr == NULL) 1178 _resMgr = new Common::MacResManager(_fileName); 1179 1180 1181 *buf = _resMgr->getResource("crsr", 1000 + id, &size); 1182 1183 if (*buf == NULL) 1154 Common::SeekableReadStream *dataStream = _resMgr->getResource('crsr', 1000 + id); 1155 1156 if (!dataStream) 1184 1157 error("There is no cursor ID #%d", 1000 + id); 1158 1159 uint32 size = dataStream->size(); 1160 *buf = (byte *)malloc(size); 1161 dataStream->read(*buf, size); 1162 delete dataStream; 1185 1163 1186 1164 return size; 1187 1165 } 1188 1166 1189 1167 int MacResExtractor::convertIcons(byte *data, int datasize, byte **cursor, int *w, int *h, 1190 1168 int *hotspot_x, int *hotspot_y, int *keycolor, byte **palette, int *palSize) { 1191 1192 _resMgr->convertCursor(data, datasize, cursor, w, h, hotspot_x, hotspot_y, keycolor, 1193 _vm->_system->hasFeature(OSystem::kFeatureCursorHasPalette), palette, palSize); 1194 1169 1170 _resMgr->convertCrsrCursor(data, datasize, cursor, w, h, hotspot_x, hotspot_y, keycolor, 1171 _vm->_system->hasFeature(OSystem::kFeatureCursorHasPalette), palette, palSize); 1195 1172 return 1; 1196 1173 } 1197 1174 1198 1199 1200 1175 void ScummEngine_v70he::readRoomsOffsets() { 1201 1176 int num, i; 1202 1177 byte *ptr;