2007-05-30 21:56:52 +00:00
|
|
|
/* 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.
|
2004-10-15 06:06:47 +00:00
|
|
|
*
|
|
|
|
* 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
|
2005-10-18 01:30:26 +00:00
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
2004-10-15 06:06:47 +00:00
|
|
|
*
|
2006-02-09 12:19:53 +00:00
|
|
|
* $URL$
|
|
|
|
* $Id$
|
2004-10-15 06:06:47 +00:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2005-06-24 15:23:51 +00:00
|
|
|
#include "common/stdafx.h"
|
2006-07-15 20:30:36 +00:00
|
|
|
#include "common/config-manager.h"
|
2006-03-29 15:59:37 +00:00
|
|
|
#include "common/endian.h"
|
2004-10-15 06:06:47 +00:00
|
|
|
#include "common/file.h"
|
2006-07-15 20:30:36 +00:00
|
|
|
#include "common/fs.h"
|
2006-09-16 20:51:05 +00:00
|
|
|
#include "common/hash-str.h"
|
2007-05-23 12:02:31 +00:00
|
|
|
#include "common/func.h"
|
|
|
|
#include "common/algorithm.h"
|
2006-07-08 12:23:44 +00:00
|
|
|
|
|
|
|
#include "gui/message.h"
|
|
|
|
|
2005-08-19 22:12:09 +00:00
|
|
|
#include "kyra/resource.h"
|
2005-06-24 16:01:42 +00:00
|
|
|
#include "kyra/script.h"
|
2005-08-19 22:12:09 +00:00
|
|
|
#include "kyra/wsamovie.h"
|
2006-02-09 07:37:19 +00:00
|
|
|
#include "kyra/screen.h"
|
2004-10-15 06:06:47 +00:00
|
|
|
|
|
|
|
namespace Kyra {
|
2007-05-23 12:02:31 +00:00
|
|
|
|
|
|
|
namespace {
|
2007-07-29 16:33:11 +00:00
|
|
|
struct ResFilenameEqual : public Common::UnaryFunction<ResourceFile*, bool> {
|
2007-05-23 12:02:31 +00:00
|
|
|
uint _filename;
|
|
|
|
ResFilenameEqual(uint file) : _filename(file) {}
|
|
|
|
|
2007-07-29 16:33:11 +00:00
|
|
|
bool operator()(const ResourceFile *f) {
|
2007-05-23 12:02:31 +00:00
|
|
|
return f->filename() == _filename;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
} // end of anonymous namespace
|
|
|
|
|
2007-04-01 13:10:50 +00:00
|
|
|
Resource::Resource(KyraEngine *vm) {
|
|
|
|
_vm = vm;
|
2005-07-30 21:11:48 +00:00
|
|
|
|
2007-04-01 13:10:50 +00:00
|
|
|
if (_vm->game() == GI_KYRA1) {
|
2006-07-08 13:56:56 +00:00
|
|
|
// we're loading KYRA.DAT here too (but just for Kyrandia 1)
|
2007-05-23 12:02:31 +00:00
|
|
|
if (!loadPakFile("KYRA.DAT") || !StaticResource::checkKyraDat()) {
|
2006-07-15 20:46:27 +00:00
|
|
|
GUI::MessageDialog errorMsg("You're missing the 'KYRA.DAT' file or it got corrupted, (re)get it from the ScummVM website");
|
2006-07-08 12:23:44 +00:00
|
|
|
errorMsg.runModal();
|
2006-07-15 20:46:27 +00:00
|
|
|
error("You're missing the 'KYRA.DAT' file or it got corrupted, (re)get it from the ScummVM website");
|
2006-05-28 04:08:25 +00:00
|
|
|
}
|
2006-07-15 20:30:36 +00:00
|
|
|
|
2006-07-15 20:32:54 +00:00
|
|
|
// We only need kyra.dat for the demo.
|
2007-04-01 13:10:50 +00:00
|
|
|
if (_vm->gameFlags().isDemo)
|
2006-07-15 20:32:54 +00:00
|
|
|
return;
|
|
|
|
|
2006-07-15 20:30:36 +00:00
|
|
|
// only VRM file we need in the *whole* game for kyra1
|
2007-04-01 13:10:50 +00:00
|
|
|
if (_vm->gameFlags().isTalkie)
|
2006-07-16 19:44:39 +00:00
|
|
|
loadPakFile("CHAPTER1.VRM");
|
2007-04-01 13:10:50 +00:00
|
|
|
} else if (_vm->game() == GI_KYRA3) {
|
2006-07-08 13:56:56 +00:00
|
|
|
// load the installation package file for kyra3
|
|
|
|
INSFile *insFile = new INSFile("WESTWOOD.001");
|
|
|
|
assert(insFile);
|
|
|
|
if (!insFile->isValid())
|
2007-05-23 12:02:31 +00:00
|
|
|
error("'WESTWOOD.001' file not found or corrupt");
|
2006-07-08 13:56:56 +00:00
|
|
|
_pakfiles.push_back(insFile);
|
2006-05-28 04:08:25 +00:00
|
|
|
}
|
2006-07-15 20:32:54 +00:00
|
|
|
|
2006-07-15 20:30:36 +00:00
|
|
|
FSList fslist;
|
|
|
|
FilesystemNode dir(ConfMan.get("path"));
|
2006-07-15 20:32:54 +00:00
|
|
|
|
2007-03-20 21:11:42 +00:00
|
|
|
if (!dir.listDir(fslist, FilesystemNode::kListFilesOnly))
|
2006-07-15 20:30:36 +00:00
|
|
|
error("invalid game path '%s'", dir.path().c_str());
|
2004-11-14 20:11:22 +00:00
|
|
|
|
2007-04-01 13:10:50 +00:00
|
|
|
if (_vm->game() == GI_KYRA1 && _vm->gameFlags().isTalkie) {
|
2006-09-16 14:36:53 +00:00
|
|
|
static const char *list[] = {
|
2006-10-24 00:30:48 +00:00
|
|
|
"ADL.PAK", "CHAPTER1.VRM", "COL.PAK", "FINALE.PAK", "INTRO1.PAK", "INTRO2.PAK",
|
|
|
|
"INTRO3.PAK", "INTRO4.PAK", "MISC.PAK", "SND.PAK", "STARTUP.PAK", "XMI.PAK",
|
2007-05-23 12:02:31 +00:00
|
|
|
"CAVE.APK", "DRAGON1.APK", "DRAGON2.APK", "LAGOON.APK"
|
2006-09-16 14:36:53 +00:00
|
|
|
};
|
|
|
|
|
2007-05-23 12:02:31 +00:00
|
|
|
Common::for_each(list, list + ARRAYSIZE(list), Common::bind1st(Common::mem_fun(&Resource::loadPakFile), this));
|
|
|
|
Common::for_each(_pakfiles.begin(), _pakfiles.end(), Common::bind2nd(Common::mem_fun(&ResourceFile::protect), true));
|
2006-09-16 14:36:53 +00:00
|
|
|
} else {
|
|
|
|
for (FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) {
|
|
|
|
Common::String filename = file->name();
|
|
|
|
filename.toUppercase();
|
2007-03-24 00:04:08 +00:00
|
|
|
|
|
|
|
// No real PAK file!
|
|
|
|
if (filename == "TWMUSIC.PAK")
|
|
|
|
continue;
|
|
|
|
|
2006-09-16 14:36:53 +00:00
|
|
|
if (filename.hasSuffix("PAK") || filename.hasSuffix("APK")) {
|
2007-04-15 16:41:20 +00:00
|
|
|
if (!loadPakFile(file->name()))
|
2006-09-16 14:36:53 +00:00
|
|
|
error("couldn't open pakfile '%s'", file->name().c_str());
|
2006-07-15 20:37:32 +00:00
|
|
|
}
|
2006-07-15 20:30:36 +00:00
|
|
|
}
|
2007-01-25 14:38:11 +00:00
|
|
|
|
2007-04-01 13:10:50 +00:00
|
|
|
if (_vm->gameFlags().platform == Common::kPlatformFMTowns) {
|
|
|
|
uint unloadHash = (_vm->gameFlags().lang == Common::EN_ANY) ? Common::hashit_lower("JMC.PAK") : Common::hashit_lower("EMC.PAK");
|
2007-01-25 14:38:11 +00:00
|
|
|
|
2007-05-23 12:02:31 +00:00
|
|
|
ResIterator file = Common::find_if(_pakfiles.begin(), _pakfiles.end(), ResFilenameEqual(unloadHash));
|
|
|
|
if (file != _pakfiles.end()) {
|
|
|
|
delete *file;
|
|
|
|
_pakfiles.erase(file);
|
2007-01-25 14:38:11 +00:00
|
|
|
}
|
|
|
|
}
|
2004-10-15 06:06:47 +00:00
|
|
|
}
|
2004-11-14 20:11:22 +00:00
|
|
|
}
|
2005-07-30 21:11:48 +00:00
|
|
|
|
2005-08-19 22:12:09 +00:00
|
|
|
Resource::~Resource() {
|
2007-05-23 12:02:31 +00:00
|
|
|
for (ResIterator start = _pakfiles.begin() ;start != _pakfiles.end(); ++start) {
|
2006-07-08 13:56:56 +00:00
|
|
|
delete *start;
|
|
|
|
*start = 0;
|
2005-10-12 19:15:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-05-23 12:02:31 +00:00
|
|
|
bool Resource::loadPakFile(const Common::String &filename) {
|
|
|
|
ResIterator listFile = Common::find_if(_pakfiles.begin(), _pakfiles.end(), ResFilenameEqual(Common::hashit_lower(filename)));
|
|
|
|
if (listFile != _pakfiles.end()) {
|
|
|
|
(*listFile)->open();
|
|
|
|
return true;
|
2006-09-16 20:51:05 +00:00
|
|
|
}
|
2006-07-08 13:56:56 +00:00
|
|
|
|
2007-05-23 12:02:31 +00:00
|
|
|
const bool isKyraDat = filename.equalsIgnoreCase("KYRA.DAT");
|
2006-07-08 13:56:56 +00:00
|
|
|
uint32 size = 0;
|
2006-09-09 12:21:49 +00:00
|
|
|
|
2006-07-08 14:25:23 +00:00
|
|
|
Common::File handle;
|
2006-09-09 17:14:47 +00:00
|
|
|
if (!getFileHandle(filename.c_str(), &size, handle)) {
|
2007-05-23 12:02:31 +00:00
|
|
|
(!isKyraDat ? error : warning)("couldn't load file: '%s'", filename.c_str());
|
2006-03-18 14:43:18 +00:00
|
|
|
return false;
|
2004-10-15 06:06:47 +00:00
|
|
|
}
|
2006-07-08 13:56:56 +00:00
|
|
|
|
2007-05-23 12:02:31 +00:00
|
|
|
PAKFile *file = new PAKFile(filename.c_str(), handle.name(), handle, (_vm->gameFlags().platform == Common::kPlatformAmiga) && !isKyraDat);
|
2006-07-08 14:25:23 +00:00
|
|
|
handle.close();
|
2006-07-08 13:56:56 +00:00
|
|
|
|
|
|
|
if (!file)
|
|
|
|
return false;
|
2007-03-20 21:11:42 +00:00
|
|
|
|
2006-07-08 14:25:23 +00:00
|
|
|
if (!file->isValid()) {
|
2007-05-23 12:02:31 +00:00
|
|
|
error("'%s' is no valid pak file", filename.c_str());
|
2006-07-08 14:25:23 +00:00
|
|
|
delete file;
|
|
|
|
return false;
|
|
|
|
}
|
2006-07-08 13:56:56 +00:00
|
|
|
|
|
|
|
_pakfiles.push_back(file);
|
2005-10-12 19:15:32 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2006-06-03 18:30:07 +00:00
|
|
|
void Resource::unloadPakFile(const Common::String &filename) {
|
2007-05-23 12:02:31 +00:00
|
|
|
ResIterator pak = Common::find_if(_pakfiles.begin(), _pakfiles.end(), ResFilenameEqual(Common::hashit_lower(filename)));
|
|
|
|
if (pak != _pakfiles.end())
|
|
|
|
(*pak)->close();
|
2005-10-12 19:15:32 +00:00
|
|
|
}
|
|
|
|
|
2007-05-23 12:02:31 +00:00
|
|
|
bool Resource::isInPakList(const Common::String &filename) const {
|
|
|
|
return (Common::find_if(_pakfiles.begin(), _pakfiles.end(), ResFilenameEqual(Common::hashit_lower(filename))) != _pakfiles.end());
|
2004-11-14 20:11:22 +00:00
|
|
|
}
|
2005-07-30 21:11:48 +00:00
|
|
|
|
2007-05-23 12:02:31 +00:00
|
|
|
uint8 *Resource::fileData(const char *file, uint32 *size) const {
|
2007-03-20 20:46:19 +00:00
|
|
|
Common::File fileHandle;
|
2005-07-30 21:11:48 +00:00
|
|
|
|
2006-07-30 07:51:11 +00:00
|
|
|
if (size)
|
|
|
|
*size = 0;
|
|
|
|
|
2004-11-14 20:11:22 +00:00
|
|
|
// test to open it in the main dir
|
2007-03-20 20:46:19 +00:00
|
|
|
if (fileHandle.open(file)) {
|
|
|
|
uint32 fileSize = fileHandle.size();
|
|
|
|
uint8 *buffer = new uint8[fileSize];
|
2004-11-14 20:11:22 +00:00
|
|
|
assert(buffer);
|
2005-07-30 21:11:48 +00:00
|
|
|
|
2007-03-20 20:46:19 +00:00
|
|
|
fileHandle.read(buffer, fileSize);
|
2006-07-30 08:22:39 +00:00
|
|
|
|
|
|
|
if (size)
|
2007-03-20 20:46:19 +00:00
|
|
|
*size = fileSize;
|
2005-07-30 21:11:48 +00:00
|
|
|
|
2007-03-20 20:46:19 +00:00
|
|
|
return buffer;
|
2004-11-14 20:11:22 +00:00
|
|
|
} else {
|
2007-05-23 12:02:31 +00:00
|
|
|
// opens the file inside a PAK File
|
2006-09-16 20:51:05 +00:00
|
|
|
uint fileHash = Common::hashit_lower(file);
|
2007-05-23 12:02:31 +00:00
|
|
|
for (ConstResIterator cur = _pakfiles.begin(); cur != _pakfiles.end(); ++cur) {
|
|
|
|
if (!(*cur)->isOpen())
|
2006-09-16 20:51:05 +00:00
|
|
|
continue;
|
|
|
|
|
2006-07-30 07:51:11 +00:00
|
|
|
|
2007-07-02 23:02:54 +00:00
|
|
|
uint8* result = (*cur)->getFile(fileHash);
|
|
|
|
|
|
|
|
if (result) {
|
|
|
|
uint32 fileSize = (*cur)->getFileSize(fileHash);
|
|
|
|
|
|
|
|
if (!fileSize)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (size)
|
|
|
|
*size = fileSize;
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
2006-07-30 07:51:11 +00:00
|
|
|
|
|
|
|
|
2004-10-15 06:06:47 +00:00
|
|
|
}
|
2004-11-14 20:11:22 +00:00
|
|
|
}
|
2005-07-30 21:11:48 +00:00
|
|
|
|
2007-03-20 20:46:19 +00:00
|
|
|
return 0;
|
2004-11-14 20:11:22 +00:00
|
|
|
}
|
2005-07-30 21:11:48 +00:00
|
|
|
|
2006-09-09 17:14:47 +00:00
|
|
|
bool Resource::getFileHandle(const char *file, uint32 *size, Common::File &filehandle) {
|
2006-02-10 16:39:56 +00:00
|
|
|
filehandle.close();
|
|
|
|
|
2007-07-29 17:21:21 +00:00
|
|
|
if (filehandle.open(file)) {
|
|
|
|
if (size)
|
|
|
|
*size = filehandle.size();
|
2006-02-10 16:39:56 +00:00
|
|
|
return true;
|
2007-07-29 17:21:21 +00:00
|
|
|
}
|
2006-02-10 16:39:56 +00:00
|
|
|
|
2006-09-16 20:51:05 +00:00
|
|
|
uint fileHash = Common::hashit_lower(file);
|
2007-05-23 12:02:31 +00:00
|
|
|
for (ResIterator start = _pakfiles.begin() ;start != _pakfiles.end(); ++start) {
|
2006-09-16 20:51:05 +00:00
|
|
|
if (!(*start)->isOpen())
|
|
|
|
continue;
|
|
|
|
|
2007-07-02 23:02:54 +00:00
|
|
|
if ((*start)->getFileHandle(fileHash, filehandle)) {
|
2007-07-29 17:21:21 +00:00
|
|
|
uint32 tSize = (*start)->getFileSize(fileHash);
|
2006-02-10 16:39:56 +00:00
|
|
|
|
2007-07-29 17:21:21 +00:00
|
|
|
if (!tSize)
|
2007-07-02 23:02:54 +00:00
|
|
|
continue;
|
2006-02-10 16:39:56 +00:00
|
|
|
|
2007-07-29 17:21:21 +00:00
|
|
|
if (size)
|
|
|
|
*size = tSize;
|
|
|
|
|
2006-02-10 16:39:56 +00:00
|
|
|
return true;
|
2007-07-02 23:02:54 +00:00
|
|
|
}
|
2006-02-10 16:39:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2007-05-23 12:02:31 +00:00
|
|
|
uint32 Resource::getFileSize(const char *file) const {
|
2006-07-31 16:37:34 +00:00
|
|
|
Common::File temp;
|
|
|
|
if (temp.open(file))
|
|
|
|
return temp.size();
|
|
|
|
|
2006-09-16 20:51:05 +00:00
|
|
|
uint fileHash = Common::hashit_lower(file);
|
2007-05-23 12:02:31 +00:00
|
|
|
for (ConstResIterator start = _pakfiles.begin() ;start != _pakfiles.end(); ++start) {
|
2006-09-16 20:51:05 +00:00
|
|
|
if (!(*start)->isOpen())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
uint32 size = (*start)->getFileSize(fileHash);
|
2006-07-31 16:37:34 +00:00
|
|
|
|
|
|
|
if (size)
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Resource::loadFileToBuf(const char *file, void *buf, uint32 maxSize) {
|
|
|
|
Common::File tempHandle;
|
|
|
|
uint32 size = 0;
|
2007-03-20 21:11:42 +00:00
|
|
|
|
2006-09-09 17:14:47 +00:00
|
|
|
if (!getFileHandle(file, &size, tempHandle))
|
2006-07-31 16:37:34 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
if (size > maxSize)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
memset(buf, 0, maxSize);
|
|
|
|
tempHandle.read(buf, size);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2004-10-15 06:06:47 +00:00
|
|
|
///////////////////////////////////////////
|
|
|
|
// Pak file manager
|
2006-09-10 13:16:34 +00:00
|
|
|
PAKFile::PAKFile(const char *file, const char *physfile, Common::File &pakfile, bool isAmiga) : ResourceFile() {
|
2004-11-14 20:11:22 +00:00
|
|
|
_open = false;
|
2005-07-30 21:11:48 +00:00
|
|
|
|
2006-09-10 13:16:34 +00:00
|
|
|
if (!pakfile.isOpen()) {
|
2006-06-03 18:30:07 +00:00
|
|
|
debug(3, "couldn't open pakfile '%s'\n", file);
|
2004-11-14 20:11:22 +00:00
|
|
|
return;
|
|
|
|
}
|
2004-10-15 06:06:47 +00:00
|
|
|
|
2006-09-10 13:16:34 +00:00
|
|
|
uint32 off = pakfile.pos();
|
2004-11-14 20:11:22 +00:00
|
|
|
uint32 filesize = pakfile.size();
|
2004-10-15 06:06:47 +00:00
|
|
|
|
2004-11-14 20:11:22 +00:00
|
|
|
uint32 pos = 0, startoffset = 0, endoffset = 0;
|
2004-10-15 06:06:47 +00:00
|
|
|
|
2007-05-23 12:02:31 +00:00
|
|
|
if (isAmiga)
|
2006-09-10 13:16:34 +00:00
|
|
|
startoffset = pakfile.readUint32BE();
|
2007-05-23 12:02:31 +00:00
|
|
|
else
|
|
|
|
startoffset = pakfile.readUint32LE();
|
2007-03-20 21:11:42 +00:00
|
|
|
|
|
|
|
if (startoffset > filesize) {
|
|
|
|
warning("PAK file '%s' is corrupted", file);
|
|
|
|
return;
|
2006-03-14 19:48:08 +00:00
|
|
|
}
|
2007-03-20 21:11:42 +00:00
|
|
|
|
2004-11-14 20:11:22 +00:00
|
|
|
pos += 4;
|
2004-10-15 06:06:47 +00:00
|
|
|
|
2004-11-14 20:11:22 +00:00
|
|
|
while (pos < filesize) {
|
2006-06-03 17:58:13 +00:00
|
|
|
PakChunk chunk;
|
2006-09-10 13:16:34 +00:00
|
|
|
uint8 buffer[64];
|
2006-09-09 12:21:49 +00:00
|
|
|
uint32 nameLength;
|
|
|
|
|
|
|
|
// Move to the position of the next file entry
|
|
|
|
pakfile.seek(pos);
|
|
|
|
|
|
|
|
// Read in the header
|
2007-03-20 21:11:42 +00:00
|
|
|
if (pakfile.read(&buffer, 64) < 5) {
|
|
|
|
warning("PAK file '%s' is corrupted", file);
|
|
|
|
return;
|
|
|
|
}
|
2006-09-09 12:21:49 +00:00
|
|
|
|
|
|
|
// Quit now if we encounter an empty string
|
|
|
|
if (!(*((const char*)buffer)))
|
2006-08-08 21:34:19 +00:00
|
|
|
break;
|
|
|
|
|
2006-09-16 20:51:05 +00:00
|
|
|
chunk._name = Common::hashit_lower((const char*)buffer);
|
2006-09-10 13:16:34 +00:00
|
|
|
nameLength = strlen((const char*)buffer) + 1;
|
2004-10-15 06:06:47 +00:00
|
|
|
|
2007-03-20 21:11:42 +00:00
|
|
|
if (nameLength > 60) {
|
|
|
|
warning("PAK file '%s' is corrupted", file);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-05-23 12:02:31 +00:00
|
|
|
if (isAmiga)
|
2006-09-09 12:21:49 +00:00
|
|
|
endoffset = READ_BE_UINT32(buffer + nameLength);
|
2007-05-23 12:02:31 +00:00
|
|
|
else
|
|
|
|
endoffset = READ_LE_UINT32(buffer + nameLength);
|
2005-07-30 21:11:48 +00:00
|
|
|
|
2007-03-20 21:11:42 +00:00
|
|
|
if (!endoffset) {
|
2004-11-14 20:11:22 +00:00
|
|
|
endoffset = filesize;
|
2007-03-20 21:11:42 +00:00
|
|
|
} else if (endoffset > filesize || startoffset > endoffset) {
|
|
|
|
warning("PAK file '%s' is corrupted", file);
|
|
|
|
return;
|
2004-11-14 20:11:22 +00:00
|
|
|
}
|
2004-10-15 06:06:47 +00:00
|
|
|
|
2007-03-20 21:11:42 +00:00
|
|
|
if (startoffset != endoffset) {
|
|
|
|
chunk._start = startoffset;
|
|
|
|
chunk._size = endoffset - startoffset;
|
2004-10-15 06:06:47 +00:00
|
|
|
|
2007-03-20 21:11:42 +00:00
|
|
|
_files.push_back(chunk);
|
|
|
|
}
|
2005-07-30 21:11:48 +00:00
|
|
|
|
2004-11-14 20:11:22 +00:00
|
|
|
if (endoffset == filesize)
|
|
|
|
break;
|
2004-11-11 13:37:35 +00:00
|
|
|
|
2004-11-14 20:11:22 +00:00
|
|
|
startoffset = endoffset;
|
2006-09-09 12:21:49 +00:00
|
|
|
pos += nameLength + 4;
|
2004-10-16 22:28:29 +00:00
|
|
|
}
|
2006-07-08 13:56:56 +00:00
|
|
|
|
2006-09-10 13:16:34 +00:00
|
|
|
_open = true;
|
2006-09-16 20:51:05 +00:00
|
|
|
_filename = Common::hashit_lower(file);
|
2006-07-08 14:25:23 +00:00
|
|
|
_physfile = physfile;
|
|
|
|
_physOffset = off;
|
2006-07-08 13:56:56 +00:00
|
|
|
}
|
|
|
|
|
2006-09-10 13:16:34 +00:00
|
|
|
|
2004-11-14 20:11:22 +00:00
|
|
|
PAKFile::~PAKFile() {
|
2006-07-08 14:25:23 +00:00
|
|
|
_physfile.clear();
|
2004-11-14 20:11:22 +00:00
|
|
|
_open = false;
|
2004-10-15 06:06:47 +00:00
|
|
|
|
2006-06-03 17:58:13 +00:00
|
|
|
_files.clear();
|
2004-11-14 20:11:22 +00:00
|
|
|
}
|
2004-10-15 06:06:47 +00:00
|
|
|
|
2007-05-23 12:02:31 +00:00
|
|
|
uint8 *PAKFile::getFile(uint hash) const {
|
|
|
|
ConstPakIterator file = Common::find_if(_files.begin(), _files.end(), Common::bind2nd(Common::EqualTo<uint>(), hash));
|
|
|
|
if (file == _files.end())
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
Common::File pakfile;
|
|
|
|
if (!openFile(pakfile))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
pakfile.seek(file->_start, SEEK_CUR);
|
|
|
|
uint8 *buffer = new uint8[file->_size];
|
|
|
|
assert(buffer);
|
|
|
|
pakfile.read(buffer, file->_size);
|
|
|
|
return buffer;
|
2004-11-14 20:11:22 +00:00
|
|
|
}
|
2004-10-15 06:06:47 +00:00
|
|
|
|
2007-05-23 12:02:31 +00:00
|
|
|
bool PAKFile::getFileHandle(uint hash, Common::File &filehandle) const {
|
2006-02-10 16:39:56 +00:00
|
|
|
filehandle.close();
|
|
|
|
|
2007-05-23 12:02:31 +00:00
|
|
|
ConstPakIterator file = Common::find_if(_files.begin(), _files.end(), Common::bind2nd(Common::EqualTo<uint>(), hash));
|
|
|
|
if (file == _files.end())
|
|
|
|
return false;
|
2007-03-20 21:11:42 +00:00
|
|
|
|
2007-05-23 12:02:31 +00:00
|
|
|
if (!openFile(filehandle))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
filehandle.seek(file->_start, SEEK_CUR);
|
|
|
|
return true;
|
2006-02-10 16:39:56 +00:00
|
|
|
}
|
|
|
|
|
2007-05-23 12:02:31 +00:00
|
|
|
uint32 PAKFile::getFileSize(uint hash) const {
|
|
|
|
ConstPakIterator file = Common::find_if(_files.begin(), _files.end(), Common::bind2nd(Common::EqualTo<uint>(), hash));
|
|
|
|
return (file != _files.end()) ? file->_size : 0;
|
2004-11-14 20:11:22 +00:00
|
|
|
}
|
2006-02-09 07:37:19 +00:00
|
|
|
|
2007-05-23 12:02:31 +00:00
|
|
|
bool PAKFile::openFile(Common::File &filehandle) const {
|
2006-07-08 14:25:23 +00:00
|
|
|
filehandle.close();
|
|
|
|
|
2007-03-20 21:11:42 +00:00
|
|
|
if (!filehandle.open(_physfile))
|
2006-07-08 14:25:23 +00:00
|
|
|
return false;
|
|
|
|
|
2006-09-10 13:16:34 +00:00
|
|
|
filehandle.seek(_physOffset, SEEK_CUR);
|
2006-07-08 14:25:23 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2006-07-08 13:56:56 +00:00
|
|
|
///////////////////////////////////////////
|
|
|
|
// Ins file manager
|
|
|
|
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;
|
2006-09-16 20:51:05 +00:00
|
|
|
newEntry._name = Common::hashit_lower(temp.c_str());
|
2006-07-08 13:56:56 +00:00
|
|
|
newEntry._start = 0;
|
|
|
|
newEntry._size = 0;
|
|
|
|
_files.push_back(newEntry);
|
|
|
|
|
|
|
|
temp = "";
|
|
|
|
} else {
|
|
|
|
temp += (char)c;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pakfile.seek(3);
|
|
|
|
|
2007-05-23 12:02:31 +00:00
|
|
|
for (FileIterator start = _files.begin(); start != _files.end(); ++start) {
|
2006-07-08 13:56:56 +00:00
|
|
|
filesize = pakfile.readUint32LE();
|
|
|
|
start->_size = filesize;
|
|
|
|
start->_start = pakfile.pos();
|
|
|
|
pakfile.seek(filesize, SEEK_CUR);
|
|
|
|
}
|
|
|
|
|
2006-09-16 20:51:05 +00:00
|
|
|
_filename = Common::hashit_lower(file);
|
|
|
|
_physfile = file;
|
2006-07-08 13:56:56 +00:00
|
|
|
_open = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
INSFile::~INSFile() {
|
|
|
|
_open = false;
|
|
|
|
|
|
|
|
_files.clear();
|
|
|
|
}
|
|
|
|
|
2007-05-23 12:02:31 +00:00
|
|
|
uint8 *INSFile::getFile(uint hash) const {
|
|
|
|
ConstFileIterator file = Common::find_if(_files.begin(), _files.end(), Common::bind2nd(Common::EqualTo<uint>(), hash));
|
|
|
|
if (file == _files.end())
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
Common::File pakfile;
|
|
|
|
if (!pakfile.open(_physfile))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
pakfile.seek(file->_start);
|
|
|
|
uint8 *buffer = new uint8[file->_size];
|
|
|
|
assert(buffer);
|
|
|
|
pakfile.read(buffer, file->_size);
|
|
|
|
return buffer;
|
2006-07-08 13:56:56 +00:00
|
|
|
}
|
|
|
|
|
2007-05-23 12:02:31 +00:00
|
|
|
bool INSFile::getFileHandle(uint hash, Common::File &filehandle) const {
|
|
|
|
ConstFileIterator file = Common::find_if(_files.begin(), _files.end(), Common::bind2nd(Common::EqualTo<uint>(), hash));
|
2007-03-20 21:11:42 +00:00
|
|
|
|
2007-05-23 12:02:31 +00:00
|
|
|
if (file == _files.end())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!filehandle.open(_physfile))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
filehandle.seek(file->_start, SEEK_CUR);
|
|
|
|
return true;
|
2006-07-08 13:56:56 +00:00
|
|
|
}
|
|
|
|
|
2007-05-23 12:02:31 +00:00
|
|
|
uint32 INSFile::getFileSize(uint hash) const {
|
|
|
|
ConstFileIterator file = Common::find_if(_files.begin(), _files.end(), Common::bind2nd(Common::EqualTo<uint>(), hash));
|
|
|
|
return (file != _files.end()) ? file->_size : 0;
|
2006-07-08 13:56:56 +00:00
|
|
|
}
|
|
|
|
|
2004-10-15 06:06:47 +00:00
|
|
|
} // end of namespace Kyra
|
2007-04-15 16:41:20 +00:00
|
|
|
|