Ticket #9112: mac_resfork_4-7-2010.diff

File mac_resfork_4-7-2010.diff, 17.4 KB (added by SF/mthreepwood, 10 years ago)

Patch against r48579

  • common/macresman.cpp

     
    2525
    2626#include "common/scummsys.h"
    2727#include "common/debug.h"
    28 #include "common/file.h"
    2928#include "common/util.h"
    3029
     30#include "common/file.h"
    3131#include "common/macresman.h"
    3232
     33#ifdef MACOSX
     34#include "common/config-manager.h"
     35#include "backends/fs/stdiostream.h"
     36#endif
     37
    3338namespace Common {
    3439
    35 MacResManager::MacResManager(Common::String fileName) : _fileName(fileName), _resOffset(-1) {
    36         _resFile.open(_fileName);
     40MacResManager::MacResManager() {
     41        memset(this, 0, sizeof(MacResManager));
     42        close();
     43}
    3744
    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());
     45MacResManager::~MacResManager() {
     46        close();
    4447}
    4548
    46 MacResManager::~MacResManager() {
     49void MacResManager::close() {
     50        _resForkOffset = -1;
     51        _mode = kResForkNone;
     52
    4753        for (int i = 0; i < _resMap.numTypes; i++) {
    4854                for (int j = 0; j < _resTypes[i].items; j++) {
    4955                        if (_resLists[i][j].nameOffset != -1) {
     
    5359                delete _resLists[i];
    5460        }
    5561
    56         delete _resLists;
    57         delete _resTypes;
     62        delete _resLists; _resLists = 0;
     63        delete _resTypes; _resTypes = 0;
     64        delete _stream; _stream = 0;
     65}
    5866
    59         _resFile.close();
     67bool MacResManager::hasDataFork() {
     68        return !_baseFileName.empty();
    6069}
    6170
     71bool MacResManager::hasResFork() {
     72        return !_baseFileName.empty() && _mode != kResForkNone;
     73}
     74
     75bool 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
     120bool 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
    62144#define MBI_INFOHDR 128
    63145#define MBI_ZERO1 0
    64146#define MBI_NAMELEN 1
     
    68150#define MBI_RFLEN 87
    69151#define MAXNAMELEN 63
    70152
    71 bool MacResManager::init() {
     153bool MacResManager::loadFromMacBinary(Common::SeekableReadStream &stream) {
    72154        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);
    76156
    77         filelen = _resFile.size();
    78         _resFile.read(infoHeader, MBI_INFOHDR);
    79 
    80157        // Maybe we have MacBinary?
    81158        if (infoHeader[MBI_ZERO1] == 0 && infoHeader[MBI_ZERO2] == 0 &&
    82159                infoHeader[MBI_ZERO3] == 0 && infoHeader[MBI_NAMELEN] <= MAXNAMELEN) {
    83160
    84161                // 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);
    87164
    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);
    90167
    91168                // 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;
    96171        }
    97172
    98         if (_resOffset == -1) // MacBinary check is failed
    99                 _resOffset = 0; // Maybe we have dumped fork?
     173        if (_resForkOffset < 0)
     174                return false;
    100175
    101         _resFile.seek(_resOffset);
     176        _mode = kResForkMacBinary;
     177        return load(stream);
     178}
    102179
    103         _dataOffset = _resFile.readUint32BE() + _resOffset;
    104         _mapOffset = _resFile.readUint32BE() + _resOffset;
    105         _dataLength = _resFile.readUint32BE();
    106         _mapLength = _resFile.readUint32BE();
     180bool MacResManager::loadFromRawFork(Common::SeekableReadStream &stream) {
     181        _mode = kResForkRaw;
     182        _resForkOffset = 0;
     183        return load(stream);
     184}
    107185
     186bool 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
    108197        // 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;
    112202                return false;
    113203        }
    114204
    115205        debug(7, "got header: data %d [%d] map %d [%d]",
    116206                _dataOffset, _dataLength, _mapOffset, _mapLength);
     207               
     208        _stream = &stream;
    117209
    118210        readMap();
    119 
    120211        return true;
    121212}
    122213
    123 MacResIDArray MacResManager::getResIDArray(const char *typeID) {
     214Common::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
     233MacResIDArray MacResManager::getResIDArray(uint32 typeID) {
    124234        int typeNum = -1;
    125235        MacResIDArray res;
    126236
    127237        for (int i = 0; i < _resMap.numTypes; i++)
    128                 if (strcmp(_resTypes[i].id, typeID) == 0) {
     238                if (_resTypes[i].id ==  typeID) {
    129239                        typeNum = i;
    130240                        break;
    131241                }
     
    141251        return res;
    142252}
    143253
    144 char *MacResManager::getResName(const char *typeID, int16 resID) {
    145         int i;
     254Common::String MacResManager::getResName(uint32 typeID, uint16 resID) {
    146255        int typeNum = -1;
    147256
    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) {
    150259                        typeNum = i;
    151260                        break;
    152261                }
    153262
    154263        if (typeNum == -1)
    155                 return NULL;
     264                return "";
    156265
    157         for (i = 0; i < _resTypes[typeNum].items; i++)
     266        for (int i = 0; i < _resTypes[typeNum].items; i++)
    158267                if (_resLists[typeNum][i].id == resID)
    159268                        return _resLists[typeNum][i].name;
    160269
    161         return NULL;
     270        return "";
    162271}
    163272
    164 byte *MacResManager::getResource(const char *typeID, int16 resID, int *size) {
    165         int i;
     273Common::SeekableReadStream *MacResManager::getResource(uint32 typeID, uint16 resID) {
    166274        int typeNum = -1;
    167275        int resNum = -1;
    168         byte *buf;
    169         int len;
    170276
    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) {
    173279                        typeNum = i;
    174280                        break;
    175281                }
     
    177283        if (typeNum == -1)
    178284                return NULL;
    179285
    180         for (i = 0; i < _resTypes[typeNum].items; i++)
     286        for (int i = 0; i < _resTypes[typeNum].items; i++)
    181287                if (_resLists[typeNum][i].id == resID) {
    182288                        resNum = i;
    183289                        break;
     
    186292        if (resNum == -1)
    187293                return NULL;
    188294
    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);
    199298}
    200299
    201300void MacResManager::readMap() {
    202         int     i, j, len;
     301        _stream->seek(_mapOffset + 22);
    203302
    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();
    210307        _resMap.numTypes++;
    211308
    212         _resFile.seek(_mapOffset + _resMap.typeOffset + 2);
     309        _stream->seek(_mapOffset + _resMap.typeOffset + 2);
    213310        _resTypes = new ResType[_resMap.numTypes];
    214311
    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();
    220316                _resTypes[i].items++;
    221317
    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);
    223319        }
    224320
    225321        _resLists = new ResPtr[_resMap.numTypes];
    226322
    227         for (i = 0; i < _resMap.numTypes; i++) {
     323        for (int i = 0; i < _resMap.numTypes; i++) {
    228324                _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);
    230326
    231                 for (j = 0; j < _resTypes[i].items; j++) {
     327                for (int j = 0; j < _resTypes[i].items; j++) {
    232328                        ResPtr resPtr = _resLists[i] + j;
    233329
    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();
    238334                        resPtr->name = 0;
    239335
    240336                        resPtr->attr = resPtr->dataOffset >> 24;
    241337                        resPtr->dataOffset &= 0xFFFFFF;
    242338                }
    243339
    244                 for (j = 0; j < _resTypes[i].items; j++) {
     340                for (int j = 0; j < _resTypes[i].items; j++) {
    245341                        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);
    247343
    248                                 len = _resFile.readByte();
     344                                byte len = _stream->readByte();
    249345                                _resLists[i][j].name = new char[len + 1];
    250346                                _resLists[i][j].name[len] = 0;
    251                                 _resFile.read(_resLists[i][j].name, len);
     347                                _stream->read(_resLists[i][j].name, len);
    252348                        }
    253349                }
    254350        }
    255351}
    256352
    257 void MacResManager::convertCursor(byte *data, int datasize, byte **cursor, int *w, int *h,
    258                                          int *hotspot_x, int *hotspot_y, int *keycolor, bool colored, byte **palette, int *palSize) {
     353void 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) {
    259355        Common::MemoryReadStream dis(data, datasize);
    260356        int i, b;
    261357        byte imageByte;
  • common/macresman.h

     
    3131
    3232namespace Common {
    3333
    34 typedef Common::Array<int16> MacResIDArray;
     34typedef Common::Array<uint16> MacResIDArray;
    3535
    3636/**
    3737 * Class for reading Mac Binary files.
     
    4040class MacResManager {
    4141
    4242public:
    43         MacResManager(Common::String fileName);
     43        MacResManager();
    4444        ~MacResManager();
     45       
     46        bool open(Common::String fileName);
     47        void close();
    4548
     49        bool hasDataFork();
     50        bool hasResFork();
     51
    4652        /**
    4753         * Read resource from the Mac Binary file
    4854         * @param typeID FourCC with type ID
    4955         * @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
    5257         */
    53         byte *getResource(const char *typeID, int16 resID, int *size);
     58        Common::SeekableReadStream *getResource(uint32 typeID, uint16 resID);
    5459
    55         char *getResName(const char *typeID, int16 resID);
     60        Common::SeekableReadStream *getDataFork();
     61        Common::String getResName(uint32 typeID, uint16 resID);
     62       
    5663        /**
    57          * Convert cursor from Mac format to format suitable for feeding to CursorMan
     64         * Convert cursor from crsr format to format suitable for feeding to CursorMan
    5865         * @param data Pointer to the cursor data
    5966         * @param datasize Size of the cursor data
    6067         * @param cursor Pointer to memory where result cursor will be stored. The memory
     
    7077         *                The memory will be malloc()'ed
    7178         * @param palSize Pointer to integer where the palette size will be stored.
    7279         */
    73         void convertCursor(byte *data, int datasize, byte **cursor, int *w, int *h,
     80        void convertCrsrCursor(byte *data, int datasize, byte **cursor, int *w, int *h,
    7481                                          int *hotspot_x, int *hotspot_y, int *keycolor, bool colored, byte **palette, int *palSize);
    7582
    7683        /**
    7784         * Return list of resource IDs with specified type ID
    7885         */
    79         MacResIDArray getResIDArray(const char *typeID);
     86        MacResIDArray getResIDArray(uint32 typeID);
    8087
    81         Common::String getFileName() { return _fileName; }
     88private:
     89        Common::SeekableReadStream *_stream;
     90        Common::String _baseFileName;
    8291
    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
    86105        void readMap();
    87 
     106       
    88107        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;
    93112        };
    94113
    95114        struct ResType {
    96                 char  id[5];
    97                 int16 items;
    98                 int16 offset;
     115                uint32 id;
     116                uint16 items;
     117                uint16 offset;
    99118        };
    100119
    101120        struct Resource {
    102                 int16 id;
     121                uint16 id;
    103122                int16 nameOffset;
    104                 byte  attr;
    105                 int32 dataOffset;
    106                 char  *name;
     123                byte attr;
     124                uint32 dataOffset;
     125                char *name;
    107126        };
    108127
    109128        typedef Resource *ResPtr;
     129       
     130        int32 _resForkOffset;
    110131
    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;
    117136        ResMap _resMap;
    118137        ResType *_resTypes;
    119138        ResPtr  *_resLists;
    120 
    121         Common::String _fileName;
    122         Common::File _resFile;
    123139};
    124140
    125141} // End of namespace Common
  • engines/scumm/he/resource_he.cpp

     
    11441144}
    11451145
    11461146int 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());
    11741152        }
    1175         in.close();
    11761153
    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)
    11841157                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;
    11851163
    11861164        return size;
    11871165}
    11881166
    11891167int MacResExtractor::convertIcons(byte *data, int datasize, byte **cursor, int *w, int *h,
    11901168                          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);
    11951172        return 1;
    11961173}
    11971174
    1198 
    1199 
    12001175void ScummEngine_v70he::readRoomsOffsets() {
    12011176        int num, i;
    12021177        byte *ptr;