mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-16 06:39:17 +00:00
d4f61e6ee9
svn-id: r24782
301 lines
7.9 KiB
C++
301 lines
7.9 KiB
C++
/* ScummVM - Scumm Interpreter
|
|
* Copyright (C) 2003-2006 The ScummVM project
|
|
*
|
|
* 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$
|
|
* $Id$
|
|
*
|
|
*/
|
|
|
|
#include "common/stdafx.h"
|
|
#include "common/endian.h"
|
|
#include "common/config-manager.h"
|
|
#include "queen/resource.h"
|
|
|
|
namespace Queen {
|
|
|
|
#ifdef PALMOS_68K
|
|
static ResourceEntry *_resourceTablePEM10;
|
|
#endif
|
|
|
|
const char *Resource::_tableFilename = "queen.tbl";
|
|
|
|
const RetailGameVersion Resource::_gameVersions[] = {
|
|
{ "PEM10", 0x00000008, 22677657 },
|
|
{ "CEM10", 0x0000584E, 190787021 },
|
|
{ "PFM10", 0x0002CD93, 22157304 },
|
|
{ "CFM10", 0x00032585, 186689095 },
|
|
{ "PGM10", 0x00059ACA, 22240013 },
|
|
{ "CGM10", 0x0005F2A7, 217648975 },
|
|
{ "PIM10", 0x000866B1, 22461366 },
|
|
{ "CIM10", 0x0008BEE2, 190795582 },
|
|
{ "CSM10", 0x000B343C, 190730602 },
|
|
{ "CHM10", 0x000DA981, 190705558 },
|
|
{ "PE100", 0x00101EC6, 3724538 },
|
|
{ "PE100", 0x00102B7F, 3732177 },
|
|
{ "PEint", 0x00103838, 1915913 }
|
|
};
|
|
|
|
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));
|
|
|
|
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.tableOffset);
|
|
}
|
|
|
|
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) {
|
|
ResourceEntry *re = resourceEntry(filename);
|
|
assert(re != NULL);
|
|
uint32 sz = re->size - skipBytes;
|
|
if (size != NULL) {
|
|
*size = sz;
|
|
}
|
|
|
|
byte *dstBuf = new byte[sz];
|
|
_resourceFile.seek(re->offset + skipBytes);
|
|
_resourceFile.read(dstBuf, sz);
|
|
return dstBuf;
|
|
}
|
|
|
|
bool Resource::detectVersion(DetectedGameVersion *ver, Common::File *f) {
|
|
memset(ver, 0, sizeof(DetectedGameVersion));
|
|
|
|
char versionStr[6];
|
|
if (f->readUint32BE() == MKID_BE('QTBL')) {
|
|
f->read(versionStr, 6);
|
|
f->skip(2);
|
|
ver->compression = f->readByte();
|
|
ver->features = GF_REBUILT;
|
|
ver->tableOffset = 0;
|
|
} else {
|
|
const RetailGameVersion *gameVersion = detectGameVersionFromSize(f->size());
|
|
if (gameVersion == NULL) {
|
|
warning("Unknown/unsupported FOTAQ version");
|
|
return false;
|
|
}
|
|
strcpy(versionStr, gameVersion->str);
|
|
ver->compression = COMPRESSION_NONE;
|
|
ver->features = 0;
|
|
ver->tableOffset = gameVersion->tableOffset;
|
|
}
|
|
|
|
switch (versionStr[1]) {
|
|
case 'E':
|
|
if (Common::parseLanguage(ConfMan.get("language")) == Common::RU_RUS) {
|
|
ver->language = Common::RU_RUS;
|
|
} else {
|
|
ver->language = Common::EN_ANY;
|
|
}
|
|
break;
|
|
case 'G':
|
|
ver->language = Common::DE_DEU;
|
|
break;
|
|
case 'F':
|
|
ver->language = Common::FR_FRA;
|
|
break;
|
|
case 'I':
|
|
ver->language = Common::IT_ITA;
|
|
break;
|
|
case 'S':
|
|
ver->language = Common::ES_ESP;
|
|
break;
|
|
case 'H':
|
|
ver->language = Common::HB_ISR;
|
|
break;
|
|
default:
|
|
warning("Unknown language id '%c', defaulting to English", versionStr[1]);
|
|
ver->language = Common::EN_ANY;
|
|
break;
|
|
}
|
|
|
|
switch (versionStr[0]) {
|
|
case 'P':
|
|
ver->features |= GF_FLOPPY;
|
|
break;
|
|
case 'C':
|
|
ver->features |= GF_TALKIE;
|
|
break;
|
|
}
|
|
|
|
if (strcmp(versionStr, "PE100") == 0) {
|
|
ver->features |= GF_DEMO;
|
|
} else if (strcmp(versionStr, "PEint") == 0) {
|
|
ver->features |= GF_INTERVIEW;
|
|
}
|
|
|
|
strcpy(ver->str, versionStr);
|
|
return true;
|
|
}
|
|
|
|
void Resource::checkJASVersion() {
|
|
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;
|
|
_resourceFile.seek(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::readTableFile(uint32 offset) {
|
|
Common::File tableFile;
|
|
tableFile.open(_tableFilename);
|
|
if (tableFile.isOpen() && tableFile.readUint32BE() == MKID_BE('QTBL')) {
|
|
if (tableFile.readUint32BE() != CURRENT_TBL_VERSION) {
|
|
warning("Incorrect version of queen.tbl, please update it");
|
|
}
|
|
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::giveSound(const char *filename, uint32 *size) {
|
|
assert(strstr(filename, ".SB"));
|
|
Common::File *f = NULL;
|
|
ResourceEntry *re = resourceEntry(filename);
|
|
if (re) {
|
|
if (size != NULL) {
|
|
*size = re->size;
|
|
}
|
|
_resourceFile.seek(re->offset);
|
|
f = &_resourceFile;
|
|
}
|
|
return f;
|
|
}
|
|
|
|
LineReader::LineReader(char *buffer, uint32 bufsize) : _buffer(buffer), _bufSize(bufsize), _current(0) {
|
|
}
|
|
|
|
LineReader::~LineReader() {
|
|
delete[] _buffer;
|
|
}
|
|
|
|
char *LineReader::nextLine() {
|
|
char *startOfLine = _buffer + _current;
|
|
char *curPos = startOfLine;
|
|
while (curPos < _buffer + _bufSize && *curPos++ != 0xd) ;
|
|
*(curPos - 1) = '\0'; // '\r'
|
|
if (curPos < _buffer + _bufSize) {
|
|
*curPos = '\0'; // '\n'
|
|
_current = (curPos - _buffer) + 1;
|
|
}
|
|
return startOfLine;
|
|
}
|
|
|
|
} // End of namespace Queen
|
|
|
|
#ifdef PALMOS_68K
|
|
#include "scumm_globals.h"
|
|
|
|
_GINIT(Queen_Restables)
|
|
_GSETPTR(Queen::_resourceTablePEM10, GBVARS_RESOURCETABLEPM10_INDEX, Queen::ResourceEntry, GBVARS_QUEEN)
|
|
_GEND
|
|
|
|
_GRELEASE(Queen_Restables)
|
|
_GRELEASEPTR(GBVARS_RESOURCETABLEPM10_INDEX, GBVARS_QUEEN)
|
|
_GEND
|
|
|
|
#endif
|