Logo Search packages:      
Sourcecode: scummvm version File versions  Download package

macresman.cpp

/* ScummVM - Graphic Adventure Engine
 *
 * ScummVM is the legal property of its developers, whose names
 * are too numerous to list here. Please refer to the COPYRIGHT
 * file distributed with this source distribution.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/tags/release-1-1-1/common/macresman.cpp $
 * $Id: macresman.cpp 47541 2010-01-25 01:39:44Z lordhoto $
 *
 */

#include "common/scummsys.h"
#include "common/debug.h"
#include "common/file.h"
#include "common/util.h"

#include "common/macresman.h"

namespace Common {

MacResManager::MacResManager(Common::String fileName) : _fileName(fileName), _resOffset(-1) {
      _resFile.open(_fileName);

      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() {
      for (int i = 0; i < _resMap.numTypes; i++) {
            for (int j = 0; j < _resTypes[i].items; j++) {
                  if (_resLists[i][j].nameOffset != -1) {
                        delete _resLists[i][j].name;
                  }
            }
            delete _resLists[i];
      }

      delete _resLists;
      delete _resTypes;

      _resFile.close();
}

#define MBI_INFOHDR 128
#define MBI_ZERO1 0
#define MBI_NAMELEN 1
#define MBI_ZERO2 74
#define MBI_ZERO3 82
#define MBI_DFLEN 83
#define MBI_RFLEN 87
#define MAXNAMELEN 63

bool MacResManager::init() {
      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);

      // 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);

            data_size_pad = (((data_size + 127) >> 7) << 7);
            rsrc_size_pad = (((rsrc_size + 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 (_resOffset == -1) // MacBinary check is failed
            _resOffset = 0; // Maybe we have dumped fork?

      _resFile.seek(_resOffset);

      _dataOffset = _resFile.readUint32BE() + _resOffset;
      _mapOffset = _resFile.readUint32BE() + _resOffset;
      _dataLength = _resFile.readUint32BE();
      _mapLength = _resFile.readUint32BE();

      // do sanity check
      if (_dataOffset >= filelen || _mapOffset >= filelen ||
            _dataLength + _mapLength  > filelen) {
            _resOffset = -1;
            return false;
      }

      debug(7, "got header: data %d [%d] map %d [%d]",
            _dataOffset, _dataLength, _mapOffset, _mapLength);

      readMap();

      return true;
}

00123 MacResIDArray MacResManager::getResIDArray(const char *typeID) {
      int typeNum = -1;
      MacResIDArray res;

      for (int i = 0; i < _resMap.numTypes; i++)
            if (strcmp(_resTypes[i].id, typeID) == 0) {
                  typeNum = i;
                  break;
            }

      if (typeNum == -1)
            return res;

      res.resize(_resTypes[typeNum].items);

      for (int i = 0; i < _resTypes[typeNum].items; i++)
            res[i] = _resLists[typeNum][i].id;

      return res;
}

char *MacResManager::getResName(const char *typeID, int16 resID) {
      int i;
      int typeNum = -1;

      for (i = 0; i < _resMap.numTypes; i++)
            if (strcmp(_resTypes[i].id, typeID) == 0) {
                  typeNum = i;
                  break;
            }

      if (typeNum == -1)
            return NULL;

      for (i = 0; i < _resTypes[typeNum].items; i++)
            if (_resLists[typeNum][i].id == resID)
                  return _resLists[typeNum][i].name;

      return NULL;
}

00164 byte *MacResManager::getResource(const char *typeID, int16 resID, int *size) {
      int i;
      int typeNum = -1;
      int resNum = -1;
      byte *buf;
      int len;

      for (i = 0; i < _resMap.numTypes; i++)
            if (strcmp(_resTypes[i].id, typeID) == 0) {
                  typeNum = i;
                  break;
            }

      if (typeNum == -1)
            return NULL;

      for (i = 0; i < _resTypes[typeNum].items; i++)
            if (_resLists[typeNum][i].id == resID) {
                  resNum = i;
                  break;
            }

      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;
}

void MacResManager::readMap() {
      int   i, j, len;

      _resFile.seek(_mapOffset + 22);

      _resMap.resAttr = _resFile.readUint16BE();
      _resMap.typeOffset = _resFile.readUint16BE();
      _resMap.nameOffset = _resFile.readUint16BE();
      _resMap.numTypes = _resFile.readUint16BE();
      _resMap.numTypes++;

      _resFile.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();
            _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);
      }

      _resLists = new ResPtr[_resMap.numTypes];

      for (i = 0; i < _resMap.numTypes; i++) {
            _resLists[i] = new Resource[_resTypes[i].items];
            _resFile.seek(_resTypes[i].offset + _mapOffset + _resMap.typeOffset);

            for (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->name = 0;

                  resPtr->attr = resPtr->dataOffset >> 24;
                  resPtr->dataOffset &= 0xFFFFFF;
            }

            for (j = 0; j < _resTypes[i].items; j++) {
                  if (_resLists[i][j].nameOffset != -1) {
                        _resFile.seek(_resLists[i][j].nameOffset + _mapOffset + _resMap.nameOffset);

                        len = _resFile.readByte();
                        _resLists[i][j].name = new char[len + 1];
                        _resLists[i][j].name[len] = 0;
                        _resFile.read(_resLists[i][j].name, len);
                  }
            }
      }
}

00257 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) {
      Common::MemoryReadStream dis(data, datasize);
      int i, b;
      byte imageByte;
      byte *iconData;
      int numBytes;
      int pixelsPerByte, bpp;
      int ctSize;
      byte bitmask;
      int iconRowBytes, iconBounds[4];
      int ignored;
      int iconDataSize;

      dis.readUint16BE(); // type
      dis.readUint32BE(); // offset to pixel map
      dis.readUint32BE(); // offset to pixel data
      dis.readUint32BE(); // expanded cursor data
      dis.readUint16BE(); // expanded data depth
      dis.readUint32BE(); // reserved

      // Grab B/W icon data
      *cursor = (byte *)malloc(16 * 16);
      for (i = 0; i < 32; i++) {
            imageByte = dis.readByte();
            for (b = 0; b < 8; b++)
                  cursor[0][i*8+b] = (byte)((imageByte & (0x80 >> b)) > 0? 0x0F: 0x00);
      }

      // Apply mask data
      for (i = 0; i < 32; i++) {
            imageByte = dis.readByte();
            for (b = 0; b < 8; b++)
                  if ((imageByte & (0x80 >> b)) == 0)
                        cursor[0][i*8+b] = 0xff;
      }

      *hotspot_y = dis.readUint16BE();
      *hotspot_x = dis.readUint16BE();
      *w = *h = 16;

      // Use b/w cursor on backends which don't support cursor palettes
      if (!colored)
            return;

      dis.readUint32BE(); // reserved
      dis.readUint32BE(); // cursorID

      // Color version of cursor
      dis.readUint32BE(); // baseAddr

      // Keep only lowbyte for now
      dis.readByte();
      iconRowBytes = dis.readByte();

      if (!iconRowBytes)
            return;

      iconBounds[0] = dis.readUint16BE();
      iconBounds[1] = dis.readUint16BE();
      iconBounds[2] = dis.readUint16BE();
      iconBounds[3] = dis.readUint16BE();

      dis.readUint16BE(); // pmVersion
      dis.readUint16BE(); // packType
      dis.readUint32BE(); // packSize

      dis.readUint32BE(); // hRes
      dis.readUint32BE(); // vRes

      dis.readUint16BE(); // pixelType
      dis.readUint16BE(); // pixelSize
      dis.readUint16BE(); // cmpCount
      dis.readUint16BE(); // cmpSize

      dis.readUint32BE(); // planeByte
      dis.readUint32BE(); // pmTable
      dis.readUint32BE(); // reserved

      // Pixel data for cursor
      iconDataSize =  iconRowBytes * (iconBounds[3] - iconBounds[1]);
      iconData = (byte *)malloc(iconDataSize);
      dis.read(iconData, iconDataSize);

      // Color table
      dis.readUint32BE(); // ctSeed
      dis.readUint16BE(); // ctFlag
      ctSize = dis.readUint16BE() + 1;

      *palette = (byte *)malloc(ctSize * 4);

      // Read just high byte of 16-bit color
      for (int c = 0; c < ctSize; c++) {
            // We just use indices 0..ctSize, so ignore color ID
            dis.readUint16BE(); // colorID[c]

            palette[0][c * 4 + 0] = dis.readByte();
            ignored = dis.readByte();

            palette[0][c * 4 + 1] = dis.readByte();
            ignored = dis.readByte();

            palette[0][c * 4 + 2] = dis.readByte();
            ignored = dis.readByte();

            palette[0][c * 4 + 3] = 0;
      }

      *palSize = ctSize;

      numBytes = (iconBounds[2] - iconBounds[0]) * (iconBounds[3] - iconBounds[1]);

      pixelsPerByte = (iconBounds[2] - iconBounds[0]) / iconRowBytes;
      bpp           = 8 / pixelsPerByte;

      // build a mask to make sure the pixels are properly shifted out
      bitmask = 0;
      for (int m = 0; m < bpp; m++) {
            bitmask <<= 1;
            bitmask  |= 1;
      }

      // Extract pixels from bytes
      for (int j = 0; j < iconDataSize; j++)
            for (b = 0; b < pixelsPerByte; b++) {
                  int idx = j * pixelsPerByte + (pixelsPerByte - 1 - b);

                  if (cursor[0][idx] != 0xff) // if mask is not there
                        cursor[0][idx] = (byte)((iconData[j] >> (b * bpp)) & bitmask);
            }

      free(iconData);

      assert(datasize - dis.pos() == 0);
}

} // End of namespace Common

Generated by  Doxygen 1.6.0   Back to index