mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-15 06:08:35 +00:00
73869dca9f
- nicer error messages when no font files are found - implements nicer way to load fonts svn-id: r23531
507 lines
11 KiB
C++
507 lines
11 KiB
C++
/* ScummVM - Scumm Interpreter
|
|
* Copyright (C) 2004-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/config-manager.h"
|
|
#include "common/endian.h"
|
|
#include "common/file.h"
|
|
#include "common/fs.h"
|
|
|
|
#include "gui/message.h"
|
|
|
|
#include "kyra/resource.h"
|
|
#include "kyra/script.h"
|
|
#include "kyra/wsamovie.h"
|
|
#include "kyra/screen.h"
|
|
|
|
namespace Kyra {
|
|
Resource::Resource(KyraEngine *engine) {
|
|
_engine = engine;
|
|
|
|
if (_engine->game() == GI_KYRA1) {
|
|
// we're loading KYRA.DAT here too (but just for Kyrandia 1)
|
|
if (!loadPakFile("KYRA.DAT") || !StaticResource::checkKyraDat()) {
|
|
GUI::MessageDialog errorMsg("You're missing the 'KYRA.DAT' file or it got corrupted, (re)get it from the ScummVM website");
|
|
errorMsg.runModal();
|
|
error("You're missing the 'KYRA.DAT' file or it got corrupted, (re)get it from the ScummVM website");
|
|
}
|
|
|
|
// We only need kyra.dat for the demo.
|
|
if (_engine->features() & GF_DEMO)
|
|
return;
|
|
|
|
// only VRM file we need in the *whole* game for kyra1
|
|
if (_engine->features() & GF_TALKIE) {
|
|
loadPakFile("CHAPTER1.VRM");
|
|
}
|
|
} else if (_engine->game() == GI_KYRA3) {
|
|
// load the installation package file for kyra3
|
|
INSFile *insFile = new INSFile("WESTWOOD.001");
|
|
assert(insFile);
|
|
if (!insFile->isValid())
|
|
return;
|
|
_pakfiles.push_back(insFile);
|
|
}
|
|
|
|
FSList fslist;
|
|
FilesystemNode dir(ConfMan.get("path"));
|
|
|
|
if (!dir.listDir(fslist, FilesystemNode::kListFilesOnly)) {
|
|
error("invalid game path '%s'", dir.path().c_str());
|
|
}
|
|
|
|
for (FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) {
|
|
Common::String filename = file->displayName();
|
|
filename.toUppercase();
|
|
if (filename.hasSuffix("PAK") || filename.hasSuffix("APK")) {
|
|
if (!loadPakFile(file->displayName())) {
|
|
error("couldn't open pakfile '%s'", file->displayName().c_str());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Resource::~Resource() {
|
|
Common::List<ResourceFile*>::iterator start = _pakfiles.begin();
|
|
|
|
for (;start != _pakfiles.end(); ++start) {
|
|
delete *start;
|
|
*start = 0;
|
|
}
|
|
}
|
|
|
|
bool Resource::loadPakFile(const Common::String &filename) {
|
|
if (isInPakList(filename))
|
|
return true;
|
|
|
|
uint32 size = 0;
|
|
Common::File handle;
|
|
if (!fileHandle(filename.c_str(), &size, handle)) {
|
|
warning("couldn't load file: '%s'", filename.c_str());
|
|
return false;
|
|
}
|
|
|
|
PAKFile *file = 0;
|
|
|
|
if (handle.name() == filename) {
|
|
file = new PAKFile(filename.c_str(), (_engine->features() & GF_AMIGA) != 0);
|
|
} else {
|
|
uint32 offset = handle.pos();
|
|
uint8 *buf = new uint8[size];
|
|
handle.read(buf, size);
|
|
file = new PAKFile(filename.c_str(), handle.name(), offset, buf, size, (_engine->features() & GF_AMIGA) != 0);
|
|
delete [] buf;
|
|
}
|
|
handle.close();
|
|
|
|
if (!file)
|
|
return false;
|
|
if (!file->isValid()) {
|
|
warning("'%s' is no valid pak file!", filename.c_str());
|
|
delete file;
|
|
return false;
|
|
}
|
|
|
|
_pakfiles.push_back(file);
|
|
return true;
|
|
}
|
|
|
|
void Resource::unloadPakFile(const Common::String &filename) {
|
|
Common::List<ResourceFile*>::iterator start = _pakfiles.begin();
|
|
for (;start != _pakfiles.end(); ++start) {
|
|
if (scumm_stricmp((*start)->filename().c_str(), filename.c_str()) == 0) {
|
|
delete *start;
|
|
_pakfiles.erase(start);
|
|
break;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
bool Resource::isInPakList(const Common::String &filename) {
|
|
Common::List<ResourceFile*>::iterator start = _pakfiles.begin();
|
|
for (;start != _pakfiles.end(); ++start) {
|
|
if (scumm_stricmp((*start)->filename().c_str(), filename.c_str()) == 0)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
uint8 *Resource::fileData(const char *file, uint32 *size) {
|
|
uint8 *buffer = 0;
|
|
Common::File file_;
|
|
|
|
// test to open it in the main dir
|
|
if (file_.open(file)) {
|
|
|
|
*size = file_.size();
|
|
buffer = new uint8[*size];
|
|
assert(buffer);
|
|
|
|
file_.read(buffer, *size);
|
|
|
|
file_.close();
|
|
} else {
|
|
// opens the file in a PAK File
|
|
Common::List<ResourceFile*>::iterator start = _pakfiles.begin();
|
|
|
|
for (;start != _pakfiles.end(); ++start) {
|
|
*size = (*start)->getFileSize(file);
|
|
|
|
if (!(*size))
|
|
continue;
|
|
|
|
buffer = (*start)->getFile(file);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!buffer || !(*size)) {
|
|
return 0;
|
|
}
|
|
|
|
return buffer;
|
|
}
|
|
|
|
bool Resource::fileHandle(const char *file, uint32 *size, Common::File &filehandle) {
|
|
filehandle.close();
|
|
|
|
if (filehandle.open(file))
|
|
return true;
|
|
|
|
Common::List<ResourceFile*>::iterator start = _pakfiles.begin();
|
|
|
|
for (;start != _pakfiles.end(); ++start) {
|
|
*size = (*start)->getFileSize(file);
|
|
|
|
if (!(*size))
|
|
continue;
|
|
|
|
if ((*start)->getFileHandle(file, filehandle)) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
///////////////////////////////////////////
|
|
// Pak file manager
|
|
#define PAKFile_Iterate Common::List<PakChunk>::iterator start=_files.begin();start != _files.end(); ++start
|
|
PAKFile::PAKFile(const char *file, bool isAmiga) : ResourceFile() {
|
|
_isAmiga = isAmiga;
|
|
|
|
Common::File pakfile;
|
|
uint8 *buffer = 0;
|
|
_open = false;
|
|
|
|
if (!pakfile.open(file)) {
|
|
debug(3, "couldn't open pakfile '%s'\n", file);
|
|
return;
|
|
}
|
|
|
|
uint32 filesize = pakfile.size();
|
|
buffer = new uint8[filesize];
|
|
assert(buffer);
|
|
|
|
pakfile.read(buffer, filesize);
|
|
pakfile.close();
|
|
|
|
// works with the file
|
|
uint32 pos = 0, startoffset = 0, endoffset = 0;
|
|
|
|
if (!_isAmiga) {
|
|
startoffset = READ_LE_UINT32(buffer + pos);
|
|
} else {
|
|
startoffset = READ_BE_UINT32(buffer + pos);
|
|
}
|
|
pos += 4;
|
|
|
|
while (pos < filesize) {
|
|
PakChunk chunk;
|
|
|
|
// saves the name
|
|
chunk._name = (const char*)buffer + pos;
|
|
pos += strlen(chunk._name.c_str()) + 1;
|
|
if (!(chunk._name[0]))
|
|
break;
|
|
|
|
if (!_isAmiga) {
|
|
endoffset = READ_LE_UINT32(buffer + pos);
|
|
} else {
|
|
endoffset = READ_BE_UINT32(buffer + pos);
|
|
}
|
|
pos += 4;
|
|
|
|
if (endoffset == 0) {
|
|
endoffset = filesize;
|
|
}
|
|
|
|
chunk._start = startoffset;
|
|
chunk._size = endoffset - startoffset;
|
|
|
|
_files.push_back(chunk);
|
|
|
|
if (endoffset == filesize)
|
|
break;
|
|
|
|
startoffset = endoffset;
|
|
}
|
|
_open = true;
|
|
delete [] buffer;
|
|
|
|
_filename = file;
|
|
_physfile = "";
|
|
}
|
|
|
|
PAKFile::PAKFile(const char *file, const char *physfile, const uint32 off, const uint8 *buffer, uint32 filesize, bool isAmiga) : ResourceFile() {
|
|
_isAmiga = isAmiga;
|
|
_open = false;
|
|
|
|
// works with the file
|
|
uint32 pos = 0, startoffset = 0, endoffset = 0;
|
|
|
|
if (!_isAmiga) {
|
|
startoffset = READ_LE_UINT32(buffer + pos);
|
|
} else {
|
|
startoffset = READ_BE_UINT32(buffer + pos);
|
|
}
|
|
pos += 4;
|
|
|
|
while (pos < filesize) {
|
|
PakChunk chunk;
|
|
|
|
// saves the name
|
|
chunk._name = (const char*)buffer + pos;
|
|
pos += strlen(chunk._name.c_str()) + 1;
|
|
if (!(chunk._name[0]))
|
|
break;
|
|
|
|
if (!_isAmiga) {
|
|
endoffset = READ_LE_UINT32(buffer + pos);
|
|
} else {
|
|
endoffset = READ_BE_UINT32(buffer + pos);
|
|
}
|
|
pos += 4;
|
|
|
|
if (endoffset == 0) {
|
|
endoffset = filesize;
|
|
}
|
|
|
|
chunk._start = startoffset;
|
|
chunk._size = endoffset - startoffset;
|
|
|
|
_files.push_back(chunk);
|
|
|
|
if (endoffset == filesize)
|
|
break;
|
|
|
|
startoffset = endoffset;
|
|
}
|
|
|
|
_open = true;
|
|
_physfile = physfile;
|
|
_physOffset = off;
|
|
_filename = file;
|
|
}
|
|
|
|
PAKFile::~PAKFile() {
|
|
_filename.clear();
|
|
_physfile.clear();
|
|
_open = false;
|
|
|
|
_files.clear();
|
|
}
|
|
|
|
uint8 *PAKFile::getFile(const char *file) {
|
|
for (PAKFile_Iterate) {
|
|
if (!scumm_stricmp(start->_name.c_str(), file)) {
|
|
Common::File pakfile;
|
|
if (!openFile(pakfile))
|
|
return false;
|
|
pakfile.seek(start->_start, SEEK_CUR);
|
|
uint8 *buffer = new uint8[start->_size];
|
|
assert(buffer);
|
|
pakfile.read(buffer, start->_size);
|
|
return buffer;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
bool PAKFile::getFileHandle(const char *file, Common::File &filehandle) {
|
|
filehandle.close();
|
|
|
|
for (PAKFile_Iterate) {
|
|
if (!scumm_stricmp(start->_name.c_str(), file)) {
|
|
if (!openFile(filehandle))
|
|
return false;
|
|
filehandle.seek(start->_start, SEEK_CUR);
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
uint32 PAKFile::getFileSize(const char* file) {
|
|
for (PAKFile_Iterate) {
|
|
if (!scumm_stricmp(start->_name.c_str(), file))
|
|
return start->_size;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
bool PAKFile::openFile(Common::File &filehandle) {
|
|
filehandle.close();
|
|
|
|
if (!filehandle.open(_physfile == "" ? _filename : _physfile)) {
|
|
debug(3, "couldn't open pakfile '%s'\n", _filename.c_str());
|
|
return false;
|
|
}
|
|
|
|
if (_physfile != "") {
|
|
filehandle.seek(_physOffset, SEEK_CUR);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
///////////////////////////////////////////
|
|
// Ins file manager
|
|
#define INSFile_Iterate Common::List<FileEntry>::iterator start=_files.begin();start != _files.end(); ++start
|
|
INSFile::INSFile(const char *file) : ResourceFile(), _files() {
|
|
Common::File pakfile;
|
|
_open = false;
|
|
|
|
if (!pakfile.open(file)) {
|
|
debug(3, "couldn't open insfile '%s'\n", file);
|
|
return;
|
|
}
|
|
|
|
// thanks to eriktorbjorn for this code (a bit modified though)
|
|
|
|
// skip first three bytes
|
|
pakfile.seek(3);
|
|
|
|
// first file is the index table
|
|
uint32 filesize = pakfile.readUint32LE();
|
|
|
|
Common::String temp = "";
|
|
|
|
for (uint i = 0; i < filesize; ++i) {
|
|
byte c = pakfile.readByte();
|
|
|
|
if (c == '\\') {
|
|
temp = "";
|
|
} else if (c == 0x0D) {
|
|
// line endings are CRLF
|
|
c = pakfile.readByte();
|
|
assert(c == 0x0A);
|
|
++i;
|
|
|
|
FileEntry newEntry;
|
|
newEntry._name = temp;
|
|
newEntry._start = 0;
|
|
newEntry._size = 0;
|
|
_files.push_back(newEntry);
|
|
|
|
temp = "";
|
|
} else {
|
|
temp += (char)c;
|
|
}
|
|
}
|
|
|
|
pakfile.seek(3);
|
|
|
|
for (INSFile_Iterate) {
|
|
filesize = pakfile.readUint32LE();
|
|
start->_size = filesize;
|
|
start->_start = pakfile.pos();
|
|
pakfile.seek(filesize, SEEK_CUR);
|
|
}
|
|
|
|
_filename = file;
|
|
_open = true;
|
|
}
|
|
|
|
INSFile::~INSFile() {
|
|
_filename.clear();
|
|
_open = false;
|
|
|
|
_files.clear();
|
|
}
|
|
|
|
uint8 *INSFile::getFile(const char *file) {
|
|
for (INSFile_Iterate) {
|
|
if (!scumm_stricmp(start->_name.c_str(), file)) {
|
|
Common::File pakfile;
|
|
if (!pakfile.open(_filename)) {
|
|
debug(3, "couldn't open insfile '%s'\n", _filename.c_str());
|
|
return false;
|
|
}
|
|
pakfile.seek(start->_start);
|
|
uint8 *buffer = new uint8[start->_size];
|
|
assert(buffer);
|
|
pakfile.read(buffer, start->_size);
|
|
return buffer;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
bool INSFile::getFileHandle(const char *file, Common::File &filehandle) {
|
|
for (INSFile_Iterate) {
|
|
if (!scumm_stricmp(start->_name.c_str(), file)) {
|
|
if (!filehandle.open(_filename)) {
|
|
debug(3, "couldn't open insfile '%s'\n", _filename.c_str());
|
|
return false;
|
|
}
|
|
filehandle.seek(start->_start, SEEK_CUR);
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
uint32 INSFile::getFileSize(const char *file) {
|
|
for (INSFile_Iterate) {
|
|
if (!scumm_stricmp(start->_name.c_str(), file))
|
|
return start->_size;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
////////////////////////////////////////////
|
|
void KyraEngine::loadPalette(const char *filename, uint8 *palData) {
|
|
debugC(9, kDebugLevelMain, "KyraEngine::loadPalette('%s' %p)", filename, (void *)palData);
|
|
uint32 fileSize = 0;
|
|
uint8 *srcData = _res->fileData(filename, &fileSize);
|
|
|
|
if (palData && fileSize) {
|
|
debugC(9, kDebugLevelMain,"Loading a palette of size %i from '%s'", fileSize, filename);
|
|
memcpy(palData, srcData, fileSize);
|
|
}
|
|
delete [] srcData;
|
|
}
|
|
|
|
} // end of namespace Kyra
|