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

resource.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-0-11-1/engines/queen/resource.cpp $
 * $Id: resource.cpp 30944 2008-02-23 22:50:18Z sev $
 *
 */


#include "common/endian.h"
#include "common/config-manager.h"
#include "queen/resource.h"

namespace Queen {


const char *Resource::_tableFilename = "queen.tbl";

const RetailGameVersion Resource::_gameVersions[] = {
      { "PEM10", 1, 0x00000008,  22677657 },
      { "CEM10", 1, 0x0000584E, 190787021 },
      { "PFM10", 1, 0x0002CD93,  22157304 },
      { "CFM10", 1, 0x00032585, 186689095 },
      { "PGM10", 1, 0x00059ACA,  22240013 },
      { "CGM10", 1, 0x0005F2A7, 217648975 },
      { "PIM10", 1, 0x000866B1,  22461366 },
      { "CIM10", 1, 0x0008BEE2, 190795582 },
      { "CSM10", 1, 0x000B343C, 190730602 },
      { "CHM10", 1, 0x000DA981, 190705558 },
      { "PE100", 1, 0x00101EC6,   3724538 },
      { "PE100", 1, 0x00102B7F,   3732177 },
      { "PEint", 1, 0x00103838,   1915913 },
      { "aEM10", 2, 0x00103F1E,    351775 },
      { "CE101", 2, 0x00107D8D,    563335 },
      { "PE100", 2, 0x001086D4,    597032 }
};

static int compareResourceEntry(const void *a, const void *b) {
      const char *filename = (const char *)a;
      const ResourceEntry *entry = (const ResourceEntry *)b;
      return strcmp(filename, entry->filename);
}

Resource::Resource()
      : _resourceEntries(0), _resourceTable(NULL) {
      memset(&_version, 0, sizeof(_version));

      _currentResourceFileNum = 1;
      if (!_resourceFile.open("queen.1c")) {
            if (!_resourceFile.open("queen.1")) {
                  error("Could not open resource file 'queen.1[c]'");
            }
      }
      if (!detectVersion(&_version, &_resourceFile)) {
            error("Unable to detect game version");
      }

      if (_version.features & GF_REBUILT) {
            readTableEntries(&_resourceFile);
      } else {
            readTableFile(_version.queenTblVersion, _version.queenTblOffset);
      }

      checkJASVersion();
      debug(5, "Detected game version: %s, which has %d resource entries", _version.str, _resourceEntries);
}

Resource::~Resource() {
      _resourceFile.close();

      if (_resourceTable != _resourceTablePEM10)
            delete[] _resourceTable;
}

ResourceEntry *Resource::resourceEntry(const char *filename) const {
      assert(filename[0] && strlen(filename) < 14);

      Common::String entryName(filename);
      entryName.toUppercase();

      ResourceEntry *re = NULL;
#ifndef PALMOS_MODE
      re = (ResourceEntry *)bsearch(entryName.c_str(), _resourceTable, _resourceEntries, sizeof(ResourceEntry), compareResourceEntry);
#else
      // PALMOS FIXME (?) : still doesn't work for me (????) use this instead
      uint32 cur = 0;
      do {
            if (!strcmp(entryName.c_str(), _resourceTable[cur].filename)) {
                  re = &_resourceTable[cur];
                  break;
            }
      } while (cur++ < _resourceEntries);
#endif
      return re;
}

uint8 *Resource::loadFile(const char *filename, uint32 skipBytes, uint32 *size) {
      debug(7, "Resource::loadFile('%s')", filename);
      ResourceEntry *re = resourceEntry(filename);
      assert(re != NULL);
      uint32 sz = re->size - skipBytes;
      if (size != NULL) {
            *size = sz;
      }
      byte *dstBuf = new byte[sz];
      seekResourceFile(re->bundle, re->offset + skipBytes);
      _resourceFile.read(dstBuf, sz);
      return dstBuf;
}

void Resource::loadTextFile(const char *filename, Common::StringList &stringList) {
      debug(7, "Resource::loadTextFile('%s')", filename);
      ResourceEntry *re = resourceEntry(filename);
      assert(re != NULL);
      seekResourceFile(re->bundle, re->offset);
      char buf[512];
      Common::SeekableSubReadStream stream(&_resourceFile, re->offset, re->offset + re->size);
      while (stream.readLine(buf, 512)) {
            stringList.push_back(buf);
      }
}

bool Resource::detectVersion(DetectedGameVersion *ver, Common::File *f) {
      memset(ver, 0, sizeof(DetectedGameVersion));

      if (f->readUint32BE() == MKID_BE('QTBL')) {
            f->read(ver->str, 6);
            f->skip(2);
            ver->compression = f->readByte();
            ver->features = GF_REBUILT;
            ver->queenTblVersion = 0;
            ver->queenTblOffset = 0;
      } else {
            const RetailGameVersion *gameVersion = detectGameVersionFromSize(f->size());
            if (gameVersion == NULL) {
                  warning("Unknown/unsupported FOTAQ version");
                  return false;
            }
            strcpy(ver->str, gameVersion->str);
            ver->compression = COMPRESSION_NONE;
            ver->features = 0;
            ver->queenTblVersion = gameVersion->queenTblVersion;
            ver->queenTblOffset = gameVersion->queenTblOffset;
            strcpy(ver->str, gameVersion->str);

            // Handle game versions for which versionStr information is irrevelant
            if (gameVersion == &_gameVersions[VER_AMI_DEMO]) { // CE101
                  ver->language = Common::EN_ANY;
                  ver->features |= GF_FLOPPY | GF_DEMO;
                  ver->platform = Common::kPlatformAmiga;
                  return true;
            }
            if (gameVersion == &_gameVersions[VER_AMI_INTERVIEW]) { // PE100
                  ver->language = Common::EN_ANY;
                  ver->features |= GF_FLOPPY | GF_INTERVIEW;
                  ver->platform = Common::kPlatformAmiga;
                  return true;
            }
      }

      switch (ver->str[1]) {
      case 'E':
            if (Common::parseLanguage(ConfMan.get("language")) == Common::RU_RUS) {
                  ver->language = Common::RU_RUS;
            } else if (Common::parseLanguage(ConfMan.get("language")) == Common::GR_GRE) {
                  ver->language = Common::GR_GRE;
            } else {
                  ver->language = Common::EN_ANY;
            }
            break;
      case 'F':
            ver->language = Common::FR_FRA;
            break;
      case 'G':
            ver->language = Common::DE_DEU;
            break;
      case 'H':
            ver->language = Common::HB_ISR;
            break;
      case 'I':
            ver->language = Common::IT_ITA;
            break;
      case 'S':
            ver->language = Common::ES_ESP;
            break;
      case 'g':
            ver->language = Common::GR_GRE;
            break;
      case 'R':
            ver->language = Common::RU_RUS;
            break;
      default:
            error("Invalid language id '%c'", ver->str[1]);
            break;
      }

      switch (ver->str[0]) {
      case 'P':
            ver->features |= GF_FLOPPY;
            ver->platform = Common::kPlatformPC;
            break;
      case 'C':
            ver->features |= GF_TALKIE;
            ver->platform = Common::kPlatformPC;
            break;
      case 'a':
            ver->features |= GF_FLOPPY;
            ver->platform = Common::kPlatformAmiga;
            break;
      default:
            error("Invalid platform id '%c'", ver->str[0]);
            break;
      }

      if (strcmp(ver->str + 2, "100") == 0 || strcmp(ver->str + 2, "101") == 0) {
            ver->features |= GF_DEMO;
      } else if (strcmp(ver->str + 2, "int") == 0) {
            ver->features |= GF_INTERVIEW;
      }
      return true;
}

void Resource::checkJASVersion() {
      if (_version.platform == Common::kPlatformAmiga) {
            // don't bother verifying the JAS version string with these versions,
            // it will be done at the end of Logic::readQueenJas, anyway
            return;
      }
      ResourceEntry *re = resourceEntry("QUEEN.JAS");
      assert(re != NULL);
      uint32 offset = re->offset;
      if (isDemo())
            offset += JAS_VERSION_OFFSET_DEMO;
      else if (isInterview())
            offset += JAS_VERSION_OFFSET_INTV;
      else
            offset += JAS_VERSION_OFFSET_PC;
      seekResourceFile(re->bundle, offset);

      char versionStr[6];
      _resourceFile.read(versionStr, 6);
      if (strcmp(_version.str, versionStr))
            error("Verifying game version failed! (expected: '%s', found: '%s')", _version.str, versionStr);
}

void Resource::seekResourceFile(int num, uint32 offset) {
      if (_currentResourceFileNum != num) {
            debug(7, "Opening resource file %d, current %d", num, _currentResourceFileNum);
            _resourceFile.close();
            char name[20];
            sprintf(name, "queen.%d", num);
            if (!_resourceFile.open(name)) {
                  error("Could not open resource file '%s'", name);
            }
            _currentResourceFileNum = num;
      }
      _resourceFile.seek(offset);
}

void Resource::readTableFile(uint8 version, uint32 offset) {
      Common::File tableFile;
      tableFile.open(_tableFilename);
      if (tableFile.isOpen() && tableFile.readUint32BE() == MKID_BE('QTBL')) {
            uint32 tableVersion = tableFile.readUint32BE();
            if (version > tableVersion) {
                  error("The game you are trying to play requires version %d of queen.tbl, "
                        "you have version %d ; please update it", version, tableVersion);
            }
            tableFile.seek(offset);
            readTableEntries(&tableFile);
      } else {
            // check if it is the english floppy version, for which we have a hardcoded version of the table
            if (strcmp(_version.str, _gameVersions[VER_ENG_FLOPPY].str) == 0) {
                  _resourceEntries = 1076;
                  _resourceTable = _resourceTablePEM10;
            } else {
                  error("Could not find tablefile '%s'", _tableFilename);
            }
      }
}

void Resource::readTableEntries(Common::File *file) {
      _resourceEntries = file->readUint16BE();
      _resourceTable = new ResourceEntry[_resourceEntries];
      for (uint16 i = 0; i < _resourceEntries; ++i) {
            ResourceEntry *re = &_resourceTable[i];
            file->read(re->filename, 12);
            re->filename[12] = '\0';
            re->bundle = file->readByte();
            re->offset = file->readUint32BE();
            re->size = file->readUint32BE();
      }
}

const RetailGameVersion *Resource::detectGameVersionFromSize(uint32 size) {
      for (int i = 0; i < VER_COUNT; ++i) {
            if (_gameVersions[i].dataFileSize == size) {
                  return &_gameVersions[i];
            }
      }
      return NULL;
}

Common::File *Resource::findSound(const char *filename, uint32 *size) {
      assert(strstr(filename, ".SB") != NULL || strstr(filename, ".AMR") != NULL || strstr(filename, ".INS") != NULL);
      ResourceEntry *re = resourceEntry(filename);
      if (re) {
            *size = re->size;
            seekResourceFile(re->bundle, re->offset);
            return &_resourceFile;
      }
      return NULL;
}

} // End of namespace Queen

Generated by  Doxygen 1.6.0   Back to index