[Scummvm-cvs-logs] SF.net SVN: scummvm: [30820] scummvm/trunk/engines/kyra

lordhoto at users.sourceforge.net lordhoto at users.sourceforge.net
Fri Feb 8 00:13:13 CET 2008


Revision: 30820
          http://scummvm.svn.sourceforge.net/scummvm/?rev=30820&view=rev
Author:   lordhoto
Date:     2008-02-07 15:13:13 -0800 (Thu, 07 Feb 2008)

Log Message:
-----------
Reworked Kyrandia resource loading code.

Modified Paths:
--------------
    scummvm/trunk/engines/kyra/kyra_v3.cpp
    scummvm/trunk/engines/kyra/resource.cpp
    scummvm/trunk/engines/kyra/resource.h
    scummvm/trunk/engines/kyra/script.cpp
    scummvm/trunk/engines/kyra/script.h
    scummvm/trunk/engines/kyra/sound.cpp
    scummvm/trunk/engines/kyra/sound.h

Modified: scummvm/trunk/engines/kyra/kyra_v3.cpp
===================================================================
--- scummvm/trunk/engines/kyra/kyra_v3.cpp	2008-02-07 22:53:23 UTC (rev 30819)
+++ scummvm/trunk/engines/kyra/kyra_v3.cpp	2008-02-07 23:13:13 UTC (rev 30820)
@@ -244,13 +244,13 @@
 	if (_soundDigital->isPlaying(_musicSoundChannel))
 		return;
 
-	Common::File *handle = new Common::File();
+	/*Common::File *handle = new Common::File();
 	uint32 temp = 0;
 	_res->getFileHandle(_menuAudioFile, &temp, *handle);
 	if (handle->isOpen())
 		_musicSoundChannel = _soundDigital->playSound(handle, true);
 	else
-		delete handle;
+		delete handle;*/
 }
 
 void KyraEngine_v3::playMusicTrack(int track, int force) {
@@ -271,13 +271,13 @@
 	if (_musicSoundChannel == -1) {
 		assert(track < _soundListSize && track >= 0);
 
-		Common::File *handle = new Common::File();
+		/*Common::File *handle = new Common::File();
 		uint32 temp = 0;
 		_res->getFileHandle(_soundList[track], &temp, *handle);
 		if (handle->isOpen())
 			_musicSoundChannel = _soundDigital->playSound(handle);
 		else
-			delete handle;
+			delete handle;*/
 	}
 
 	_musicSoundChannel = track;

Modified: scummvm/trunk/engines/kyra/resource.cpp
===================================================================
--- scummvm/trunk/engines/kyra/resource.cpp	2008-02-07 22:53:23 UTC (rev 30819)
+++ scummvm/trunk/engines/kyra/resource.cpp	2008-02-07 23:13:13 UTC (rev 30820)
@@ -28,31 +28,17 @@
 #include "common/endian.h"
 #include "common/file.h"
 #include "common/fs.h"
-#include "common/hash-str.h"
 #include "common/func.h"
 #include "common/algorithm.h"
 
 #include "gui/message.h"
 
 #include "kyra/resource.h"
-#include "kyra/script.h"
-#include "kyra/wsamovie.h"
-#include "kyra/screen.h"
 
 namespace Kyra {
 
-namespace {
-struct ResFilenameEqual : public Common::UnaryFunction<ResourceFile*, bool> {
-	uint _filename;
-	ResFilenameEqual(uint file) : _filename(file) {}
-
-	bool operator()(const ResourceFile *f) {
-		return f->filename() == _filename;
-	}
-};
-} // end of anonymous namespace
-
-Resource::Resource(KyraEngine *vm) : _vm(vm) {
+Resource::Resource(KyraEngine *vm) : _loaders(), _map(), _vm(vm) {
+	initializeLoaders();
 }
 
 Resource::~Resource() {
@@ -95,12 +81,7 @@
 
 		return true;
 	} else if (_vm->game() == GI_KYRA3) {
-		// load the installation package file for kyra3
-		INSFile *insFile = new INSFile("WESTWOOD.001");
-		assert(insFile);
-		if (!insFile->isValid())
-			error("'WESTWOOD.001' file not found or corrupt");
-		_pakfiles.push_back(insFile);
+		loadPakFile("WESTWOOD.001");
 	}
 
 	FSList fslist;
@@ -115,7 +96,6 @@
 		};
 
 		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));
 	} else {
 		for (FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) {
 			Common::String filename = file->getName();
@@ -125,55 +105,48 @@
 			if (filename == "TWMUSIC.PAK")
 				continue;
 
-			if (filename.hasSuffix("PAK") || filename.hasSuffix("APK")) {
+			if (filename == ((_vm->gameFlags().lang == Common::EN_ANY) ? "JMC.PAK" : "EMC.PAK"))
+				continue;
+
+			if (filename.hasSuffix(".PAK") || filename.hasSuffix(".APK")) {
 				if (!loadPakFile(file->getName()))
 					error("couldn't open pakfile '%s'", file->getName().c_str());
 			}
 		}
-
-		if (_vm->gameFlags().platform == Common::kPlatformFMTowns || _vm->gameFlags().platform == Common::kPlatformPC98) {
-			uint unloadHash = (_vm->gameFlags().lang == Common::EN_ANY) ? Common::hashit_lower("JMC.PAK") : Common::hashit_lower("EMC.PAK");
-
-			ResIterator file = Common::find_if(_pakfiles.begin(), _pakfiles.end(), ResFilenameEqual(unloadHash));
-			if (file != _pakfiles.end()) {
-				delete *file;
-				_pakfiles.erase(file);
-			}
-		}
 	}
 
 	return true;
 }
 
 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;
-	}
+	ResFileMap::iterator iter = _map.find(filename);
+	if (iter == _map.end())
+		return false;
 
-	const bool isKyraDat = filename.equalsIgnoreCase(StaticResource::staticDataFilename());
-	uint32 size = 0;
+	iter->_value.loadable = true;
 
-	Common::File handle;
-	if (!getFileHandle(filename.c_str(), &size, handle)) {
-		(!isKyraDat ? error : warning)("couldn't load file: '%s'", filename.c_str());
+	if (!isAccessable(filename))
 		return false;
-	}
 
-	PAKFile *file = new PAKFile(filename.c_str(), handle.name(), handle, (_vm->gameFlags().platform == Common::kPlatformAmiga) && !isKyraDat);
-	handle.close();
+	if (iter->_value.preload)
+		return true;
 
-	if (!file)
-		return false;
+	Common::SeekableReadStream *stream = getFileStream(filename);
+	assert(stream);
 
-	if (!file->isValid()) {
-		error("'%s' is no valid pak file", filename.c_str());
-		delete file;
+	const ResArchiveLoader *loader = getLoader(iter->_value.type);
+	assert(loader);
+
+	loader->loadFile(filename, *stream, _map);
+	delete stream;
+	stream = 0;
+
+	iter = _map.find(filename);
+	if (iter == _map.end())
 		return false;
-	}
+	iter->_value.preload = true;
+	detectFileTypes();
 
-	_pakfiles.push_back(file);
 	return true;
 }
 
@@ -221,205 +194,252 @@
 }
 
 void Resource::unloadPakFile(const Common::String &filename) {
-	ResIterator pak = Common::find_if(_pakfiles.begin(), _pakfiles.end(), ResFilenameEqual(Common::hashit_lower(filename)));
-	if (pak != _pakfiles.end())
-		(*pak)->close();
+	ResFileMap::iterator iter = _map.find(filename);
+	if (iter != _map.end()) {
+		if (!iter->_value.prot)
+			iter->_value.loadable = false;
+	}
 }
 
 bool Resource::isInPakList(const Common::String &filename) const {
-	return (Common::find_if(_pakfiles.begin(), _pakfiles.end(), ResFilenameEqual(Common::hashit_lower(filename))) != _pakfiles.end());
+	return isAccessable(filename);
 }
 
 void Resource::unloadAllPakFiles() {
-	for (ResIterator start = _pakfiles.begin(); start != _pakfiles.end(); ++start) {
-		delete *start;
-		*start = 0;
+	FilesystemNode dir(ConfMan.get("path"));
+
+	if (!dir.exists() || !dir.isDirectory())
+		error("invalid game path '%s'", dir.getPath().c_str());
+
+	FSList fslist;
+	if (!dir.getChildren(fslist, FilesystemNode::kListFilesOnly))
+		error("can't list files inside game path '%s'", dir.getPath().c_str());
+
+	// remove all entries
+	_map.clear();
+	
+	Common::File temp;
+	if (temp.open("kyra.dat")) {
+		ResFileEntry entry;
+		entry.parent = "";
+		entry.size = temp.size();
+		entry.loadable = true;
+		entry.preload = false;
+		entry.prot = false;
+		entry.type = ResFileEntry::kPak;
+		entry.offset = 0;
+		_map["kyra.dat"] = entry;
+		temp.close();
 	}
-	_pakfiles.clear();
+	
+	for (FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) {
+		ResFileEntry entry;
+		entry.parent = "";
+		if (!temp.open(file->getPath()))
+			error("couldn't open file '%s'", file->getName().c_str());
+		entry.size = temp.size();
+		entry.offset = 0;
+		entry.loadable = true;
+		entry.preload = false;
+		entry.prot = false;
+		entry.type = ResFileEntry::kAutoDetect;
+		_map[file->getName()] = entry;
+		temp.close();
+	}
+
+	detectFileTypes();
 }
 
 uint8 *Resource::fileData(const char *file, uint32 *size) const {
-	Common::File fileHandle;
+	Common::SeekableReadStream *stream = getFileStream(file);
+	if (!stream)
+		return 0;
 
+	uint32 bufferSize = stream->size();
+	uint8 *buffer = new uint8[bufferSize];
+	assert(buffer);
 	if (size)
-		*size = 0;
+		*size = bufferSize;
+	stream->read(buffer, bufferSize);
+	delete stream;
+	return buffer;
+}
 
-	// test to open it in the main dir
-	if (fileHandle.open(file)) {
-		uint32 fileSize = fileHandle.size();
-		uint8 *buffer = new uint8[fileSize];
-		assert(buffer);
+uint32 Resource::getFileSize(const char *file) const {
+	if (!isAccessable(file))
+		return 0;
 
-		fileHandle.read(buffer, fileSize);
+	ResFileMap::const_iterator iter = _map.find(file);
+	if (iter != _map.end())
+		return iter->_value.size;
+	return 0;
+}
 
-		if (size)
-			*size = fileSize;
+bool Resource::loadFileToBuf(const char *file, void *buf, uint32 maxSize) {
+	Common::SeekableReadStream *stream = getFileStream(file);
+	if (!stream)
+		return false;
 
-		return buffer;
-	} else {
-		// opens the file inside a PAK File
-		uint fileHash = Common::hashit_lower(file);
-		for (ConstResIterator cur = _pakfiles.begin(); cur != _pakfiles.end(); ++cur) {
-			if (!(*cur)->isOpen())
-				continue;
+	if (maxSize < stream->size()) {
+		delete stream;
+		return false;
+	}
+	memset(buf, 0, maxSize);
+	stream->read(buf, stream->size());
+	delete stream;
+	return true;
+}
 
+Common::SeekableReadStream *Resource::getFileStream(const Common::String &file) const {
+	if (!isAccessable(file))
+		return 0;
 
-			uint8* result = (*cur)->getFile(fileHash);
+	ResFileMap::const_iterator iter = _map.find(file);
+	if (iter == _map.end())
+		return 0;
 
-			if (result) {
-				uint32 fileSize = (*cur)->getFileSize(fileHash);
+	if (!iter->_value.parent.empty()) {
+		Common::SeekableReadStream *parent = getFileStream(iter->_value.parent);
+		assert(parent);
 
-				if (!fileSize)
-					continue;
+		ResFileMap::const_iterator parentIter = _map.find(iter->_value.parent);
+		const ResArchiveLoader *loader = getLoader(parentIter->_value.type);
+		assert(loader);
 
-				if (size)
-					*size = fileSize;
-
-				return result;
-			}
-
-
+		return loader->loadFileFromArchive(file, parent, _map);
+	} else {
+		Common::File *stream = new Common::File();
+		if (!stream->open(file.c_str())) {
+			warning("Couldn't open file '%s'", file.c_str());
+			return 0;
 		}
+		return stream;
 	}
 
 	return 0;
 }
 
-bool Resource::getFileHandle(const char *file, uint32 *size, Common::File &filehandle) {
-	filehandle.close();
+bool Resource::isAccessable(const Common::String &file) const {
+	ResFileMap::const_iterator iter = _map.find(file);
+	while (true) {
+		if (iter == _map.end())
+			break;
 
-	if (filehandle.open(file)) {
-		if (size)
-			*size = filehandle.size();
-		return true;
-	}
+		if (!iter->_value.loadable)
+			return false;
 
-	uint fileHash = Common::hashit_lower(file);
-	for (ResIterator start = _pakfiles.begin() ;start != _pakfiles.end(); ++start) {
-		if (!(*start)->isOpen())
-			continue;
-
-		if ((*start)->getFileHandle(fileHash, filehandle)) {
-			uint32 tSize = (*start)->getFileSize(fileHash);
-
-			if (!tSize)
-				continue;
-
-			if (size)
-				*size = tSize;
-
-			return true;
-		}
+		if (!iter->_value.parent.empty())
+			iter = _map.find(iter->_value.parent);
+		else
+			return iter->_value.loadable;
 	}
-
 	return false;
 }
 
-uint32 Resource::getFileSize(const char *file) const {
-	Common::File temp;
-	if (temp.open(file))
-		return temp.size();
-
-	uint fileHash = Common::hashit_lower(file);
-	for (ConstResIterator start = _pakfiles.begin() ;start != _pakfiles.end(); ++start) {
-		if (!(*start)->isOpen())
+void Resource::detectFileTypes() {
+	for (ResFileMap::iterator i = _map.begin(); i != _map.end(); ++i) {
+		if (!isAccessable(i->_key))
 			continue;
 
-		uint32 size = (*start)->getFileSize(fileHash);
+		if (i->_value.type == ResFileEntry::kAutoDetect) {
+			for (LoaderIterator l = _loaders.begin(); l != _loaders.end(); ++l) {
+				Common::SeekableReadStream *stream = getFileStream(i->_key);
+				if ((*l)->isLoadable(i->_key, *stream)) {
+					i->_value.type = (*l)->getType();
+					i->_value.loadable = false;
+					i->_value.preload = false;
+					break;
+				}
+				delete stream;
+				stream = 0;
+			}
 
-		if (size)
-			return size;
+			if (i->_value.type == ResFileEntry::kAutoDetect) {
+				i->_value.type = ResFileEntry::kRaw;
+				i->_value.loadable = true;
+			}
+		}
 	}
-
-	return 0;
 }
 
-bool Resource::loadFileToBuf(const char *file, void *buf, uint32 maxSize) {
-	Common::File tempHandle;
-	uint32 size = 0;
+#pragma mark -
+#pragma mark - ResFileLodaer
+#pragma mark -
 
-	if (!getFileHandle(file, &size, tempHandle))
-		return false;
+class ResLoaderPak : public ResArchiveLoader {
+public:
+	bool isLoadable(const Common::String &filename, Common::SeekableReadStream &stream) const;
+	bool loadFile(const Common::String &filename, Common::SeekableReadStream &stream, ResFileMap &map) const;
+	Common::SeekableReadStream *loadFileFromArchive(const Common::String &file, Common::SeekableReadStream *archive, const ResFileMap &map) const;
 
-	if (size > maxSize)
-		return false;
+	ResFileEntry::kType getType() const {
+		return ResFileEntry::kPak;
+	}
+};
 
-	memset(buf, 0, maxSize);
-	tempHandle.read(buf, size);
-
-	return true;
+bool ResLoaderPak::isLoadable(const Common::String &filename, Common::SeekableReadStream &stream) const {
+	// TODO improve check:
+	Common::String file = filename;
+	file.toUppercase();
+	return ((file.hasSuffix(".PAK") && file != "TWMUSIC.PAK") || file.hasSuffix(".APK") || file.hasSuffix(".VRM") || file.hasSuffix(".TLK"));
 }
 
-///////////////////////////////////////////
-// Pak file manager
-PAKFile::PAKFile(const char *file, const char *physfile, Common::File &pakfile, bool isAmiga) : ResourceFile() {
-	_open = false;
+bool ResLoaderPak::loadFile(const Common::String &filename, Common::SeekableReadStream &stream, ResFileMap &map) const {
+	uint32 filesize = stream.size();
+	
+	Common::List<Common::String> filenames;
+	Common::List<ResFileEntry> entries;
 
-	if (!pakfile.isOpen()) {
-		debug(3, "couldn't open pakfile '%s'\n", file);
-		return;
-	}
-
-	uint32 off = pakfile.pos();
-	uint32 filesize = pakfile.size();
-
 	uint32 pos = 0, startoffset = 0, endoffset = 0;
+	bool switchEndian = false;
 
-	if (isAmiga)
-		startoffset = pakfile.readUint32BE();
-	else
-		startoffset = pakfile.readUint32LE();
-
+	startoffset = stream.readUint32LE(); pos += 4;
 	if (startoffset > filesize) {
-		warning("PAK file '%s' is corrupted", file);
-		return;
+		switchEndian = true;
+		startoffset = SWAP_BYTES_32(startoffset);
 	}
 
-	pos += 4;
-
 	while (pos < filesize) {
-		PakChunk chunk;
 		uint8 buffer[64];
 		uint32 nameLength;
 
 		// Move to the position of the next file entry
-		pakfile.seek(pos);
+		stream.seek(pos);
 
 		// Read in the header
-		if (pakfile.read(&buffer, 64) < 5) {
-			warning("PAK file '%s' is corrupted", file);
-			return;
+		if (stream.read(&buffer, 64) < 5) {
+			warning("PAK file '%s' is corrupted", filename.c_str());
+			return false;
 		}
 
 		// Quit now if we encounter an empty string
 		if (!(*((const char*)buffer)))
 			break;
 
-		chunk._name = Common::hashit_lower((const char*)buffer);
 		nameLength = strlen((const char*)buffer) + 1;
 
 		if (nameLength > 60) {
-			warning("PAK file '%s' is corrupted", file);
-			return;
+			warning("PAK file '%s' is corrupted", filename.c_str());
+			return false;
 		}
 
-		if (isAmiga)
-			endoffset = READ_BE_UINT32(buffer + nameLength);
-		else
-			endoffset = READ_LE_UINT32(buffer + nameLength);
+		endoffset = (switchEndian ? READ_BE_UINT32 : READ_LE_UINT32)(buffer + nameLength);
 
-		if (!endoffset) {
+		if (!endoffset)
 			endoffset = filesize;
-		} else if (endoffset > filesize || startoffset > endoffset) {
-			warning("PAK file '%s' is corrupted", file);
-			return;
-		}
 
 		if (startoffset != endoffset) {
-			chunk._start = startoffset;
-			chunk._size = endoffset - startoffset;
+			ResFileEntry entry;
+			entry.size = endoffset - startoffset;
+			entry.offset = startoffset;
+			entry.parent = filename;
+			entry.type = ResFileEntry::kAutoDetect;
+			entry.loadable = true;
+			entry.prot = false;
+			entry.preload = false;
 
-			_files.push_back(chunk);
+			filenames.push_back(Common::String((const char*)buffer));
+			entries.push_back(entry);
 		}
 
 		if (endoffset == filesize)
@@ -429,161 +449,129 @@
 		pos += nameLength + 4;
 	}
 
-	_open = true;
-	_filename = Common::hashit_lower(file);
-	_physfile = physfile;
-	_physOffset = off;
-}
+	assert(filenames.size() == entries.size());
 
+	Common::List<ResFileEntry>::iterator entry = entries.begin();
+	Common::List<Common::String>::iterator file = filenames.begin();
 
-PAKFile::~PAKFile() {
-	_physfile.clear();
-	_open = false;
+	for (; entry != entries.end(); ++entry, ++file) {
+		map.erase(*file);
+		map[*file] = *entry;
+	}
 
-	_files.clear();
+	return true;
 }
 
-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())
+Common::SeekableReadStream *ResLoaderPak::loadFileFromArchive(const Common::String &file, Common::SeekableReadStream *archive, const ResFileMap &map) const {
+	assert(archive);
+
+	ResFileMap::const_iterator entry = map.find(file);
+	if (entry == map.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;
+	archive->seek(entry->_value.offset, SEEK_SET);
+	Common::SeekableSubReadStream *stream = new Common::SeekableSubReadStream(archive, entry->_value.offset, entry->_value.offset + entry->_value.size, true);
+	assert(stream);
+	return stream;
 }
 
-bool PAKFile::getFileHandle(uint hash, Common::File &filehandle) const {
-	filehandle.close();
+class ResLoaderIns : public ResArchiveLoader {
+public:
+	bool isLoadable(const Common::String &filename, Common::SeekableReadStream &stream) const;
+	bool loadFile(const Common::String &filename, Common::SeekableReadStream &stream, ResFileMap &map) const;
+	Common::SeekableReadStream *loadFileFromArchive(const Common::String &file, Common::SeekableReadStream *archive, const ResFileMap &map) const;
 
-	ConstPakIterator file = Common::find_if(_files.begin(), _files.end(), Common::bind2nd(Common::EqualTo<uint>(), hash));
-	if (file == _files.end())
-		return false;
+	ResFileEntry::kType getType() const {
+		return ResFileEntry::kIns;
+	}
+};
 
-	if (!openFile(filehandle))
+bool ResLoaderIns::isLoadable(const Common::String &filename, Common::SeekableReadStream &stream) const {
+	stream.seek(3);
+	uint32 size = stream.readUint32LE();
+
+	if (size > stream.size())
 		return false;
 
-	filehandle.seek(file->_start, SEEK_CUR);
-	return true;
-}
+	stream.seek(size+1, SEEK_SET);
+	uint8 buffer[2];
+	stream.read(&buffer, 2);
 
-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;
+	return (buffer[0] == 0x0D && buffer[1] == 0x0A);
 }
 
-bool PAKFile::openFile(Common::File &filehandle) const {
-	filehandle.close();
+bool ResLoaderIns::loadFile(const Common::String &filename, Common::SeekableReadStream &stream, ResFileMap &map) const {
+	Common::List<Common::String> filenames;
 
-	if (!filehandle.open(_physfile))
-		return false;
-
-	filehandle.seek(_physOffset, SEEK_CUR);
-	return true;
-}
-
-///////////////////////////////////////////
-// 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)
+	stream.seek(3, SEEK_SET);
 
-	// skip first three bytes
-	pakfile.seek(3);
-
 	// first file is the index table
-	uint32 filesize = pakfile.readUint32LE();
-
+	uint32 size = stream.readUint32LE();
 	Common::String temp = "";
 
-	for (uint i = 0; i < filesize; ++i) {
-		byte c = pakfile.readByte();
+	for (uint32 i = 0; i < size; ++i) {
+		byte c = stream.readByte();
 
 		if (c == '\\') {
 			temp = "";
 		} else if (c == 0x0D) {
 			// line endings are CRLF
-			c = pakfile.readByte();
+			c = stream.readByte();
 			assert(c == 0x0A);
 			++i;
 
-			FileEntry newEntry;
-			newEntry._name = Common::hashit_lower(temp.c_str());
-			newEntry._start = 0;
-			newEntry._size = 0;
-			_files.push_back(newEntry);
-
-			temp = "";
+			filenames.push_back(temp);
 		} else {
 			temp += (char)c;
 		}
 	}
 
-	pakfile.seek(3);
+	stream.seek(3, SEEK_SET);
 
-	for (FileIterator start = _files.begin(); start != _files.end(); ++start) {
-		filesize = pakfile.readUint32LE();
-		start->_size = filesize;
-		start->_start = pakfile.pos();
-		pakfile.seek(filesize, SEEK_CUR);
-	}
+	for (Common::List<Common::String>::iterator file = filenames.begin(); file != filenames.end(); ++file) {
+		map.erase(*file);
 
-	_filename = Common::hashit_lower(file);
-	_physfile = file;
-	_open = true;
-}
+		ResFileEntry entry;
+		entry.parent = filename;
+		entry.type = ResFileEntry::kAutoDetect;
+		entry.loadable = true;
+		entry.preload = false;
+		entry.prot = false;
+		entry.size = stream.readUint32LE();
+		entry.offset = stream.pos();
+		stream.seek(entry.size, SEEK_CUR);
 
-INSFile::~INSFile() {
-	_open = false;
+		map[*file] = entry;
+	}
 
-	_files.clear();
+	return true;
 }
 
-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())
+Common::SeekableReadStream *ResLoaderIns::loadFileFromArchive(const Common::String &file, Common::SeekableReadStream *archive, const ResFileMap &map) const {
+	assert(archive);
+
+	ResFileMap::const_iterator entry = map.find(file);
+	if (entry == map.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;
+	archive->seek(entry->_value.offset, SEEK_SET);
+	Common::SeekableSubReadStream *stream = new Common::SeekableSubReadStream(archive, entry->_value.offset, entry->_value.offset + entry->_value.size, true);
+	assert(stream);
+	return stream;
 }
 
-bool INSFile::getFileHandle(uint hash, Common::File &filehandle) const {
-	ConstFileIterator file = Common::find_if(_files.begin(), _files.end(), Common::bind2nd(Common::EqualTo<uint>(), hash));
-
-	if (file == _files.end())
-		return false;
-
-	if (!filehandle.open(_physfile))
-		return false;
-
-	filehandle.seek(file->_start, SEEK_CUR);
-	return true;
+void Resource::initializeLoaders() {
+	_loaders.push_back(new ResLoaderPak());
+	_loaders.push_back(new ResLoaderIns());
 }
 
-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;
+const ResArchiveLoader *Resource::getLoader(ResFileEntry::kType type) const {
+	for (CLoaderIterator i = _loaders.begin(); i != _loaders.end(); ++i) {
+		if ((*i)->getType() == type)
+			return *i;
+	}
+	return 0;
 }
 
 } // end of namespace Kyra

Modified: scummvm/trunk/engines/kyra/resource.h
===================================================================
--- scummvm/trunk/engines/kyra/resource.h	2008-02-07 22:53:23 UTC (rev 30819)
+++ scummvm/trunk/engines/kyra/resource.h	2008-02-07 23:13:13 UTC (rev 30820)
@@ -31,84 +31,46 @@
 #include "common/str.h"
 #include "common/file.h"
 #include "common/list.h"
+#include "common/hash-str.h"
+#include "common/hashmap.h"
+#include "common/stream.h"
 
 #include "kyra/kyra.h"
 
 namespace Kyra {
 
-class ResourceFile {
-public:
-	ResourceFile() : _open(false), _protected(false), _filename() {}
-	virtual ~ResourceFile() {}
+struct ResFileEntry {
+	Common::String parent;
+	uint32 size;
 
-	virtual uint8 *getFile(uint file) const = 0;
-	virtual bool getFileHandle(uint file, Common::File &filehandle) const = 0;
-	virtual uint32 getFileSize(uint file) const = 0;
+	bool preload;
+	bool loadable;
+	bool prot;
 
-	uint filename() const { return _filename; }
-
-	virtual bool isValid(void) const { return (_filename != 0); }
-	bool isOpen(void) const { return _open; }
-
-	virtual void close() { if (!_protected) _open = false; }
-	virtual void protect(const bool prot = true) { _protected = prot; }
-	virtual void open() { _open = true; }
-protected:
-	bool _open;
-	bool _protected;
-	uint _filename;
-};
-
-// standard Package format for Kyrandia games
-class PAKFile : public ResourceFile {
-	struct PakChunk {
-		uint _name;
-		uint32 _start;
-		uint32 _size;
-
-		operator uint() const { return _name; }
+	enum kType {
+		kRaw = 0,
+		kPak = 1,
+		kIns = 2,
+		kAutoDetect
 	};
-
-public:
-	PAKFile(const char *file, const char *physfile, Common::File &pakfile, bool isAmiga = false);
-	~PAKFile();
-
-	uint8 *getFile(uint file) const;
-	bool getFileHandle(uint file, Common::File &filehandle) const;
-	uint32 getFileSize(uint file) const;
-private:
-	bool openFile(Common::File &filehandle) const;
-
-	Common::String _physfile;
-	uint32 _physOffset;
-
-	typedef Common::List<PakChunk>::iterator PakIterator;
-	typedef Common::List<PakChunk>::const_iterator ConstPakIterator;
-	Common::List<PakChunk> _files; // the entries
+	kType type;
+	uint32 offset;
 };
 
-// installation file packages for (Kyra2/)Kyra3
-class INSFile : public ResourceFile {
-	struct FileEntry {
-		uint _name;
-		uint32 _start;
-		uint32 _size;
+typedef Common::HashMap<Common::String, ResFileEntry, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> ResFileMap;
+class Resource;
 
-		operator uint() const { return _name; }
-	};
+class ResArchiveLoader {
 public:
-	INSFile(const char *file);
-	~INSFile();
+	virtual ~ResArchiveLoader() {}
 
-	uint8 *getFile(uint file) const;
-	bool getFileHandle(uint file, Common::File &filehandle) const;
-	uint32 getFileSize(uint file) const;
-protected:
-	typedef Common::List<FileEntry>::iterator FileIterator;
-	typedef Common::List<FileEntry>::const_iterator ConstFileIterator;
-	Common::List<FileEntry> _files; // the entries
+	virtual bool isLoadable(const Common::String &filename, Common::SeekableReadStream &stream) const = 0;
+	virtual bool loadFile(const Common::String &filename, Common::SeekableReadStream &stream, ResFileMap &map) const = 0;
+	// parameter 'archive' can be deleted by this method and it may not be deleted from the caller
+	virtual Common::SeekableReadStream *loadFileFromArchive(const Common::String &file, Common::SeekableReadStream *archive, const ResFileMap &map) const = 0;
 
-	Common::String _physfile;
+	virtual ResFileEntry::kType getType() const = 0;
+protected:
 };
 
 class Resource {
@@ -129,18 +91,22 @@
 
 	uint32 getFileSize(const char *file) const;
 	uint8* fileData(const char *file, uint32 *size) const;
-	// gives back a file handle
-	// it is possible that the needed file is embedded in the returned handle
-	bool getFileHandle(const char *file, uint32 *size, Common::File &filehandle);
+	Common::SeekableReadStream *getFileStream(const Common::String &file) const;
 
 	bool loadFileToBuf(const char *file, void *buf, uint32 maxSize);
-
 protected:
-	typedef Common::List<ResourceFile*>::iterator ResIterator;
-	typedef Common::List<ResourceFile*>::const_iterator ConstResIterator;
+	bool isAccessable(const Common::String &file) const;
 
+	void detectFileTypes();
+
+	void initializeLoaders();
+	const ResArchiveLoader *getLoader(ResFileEntry::kType type) const;
+	typedef Common::List<ResArchiveLoader*>::iterator LoaderIterator;
+	typedef Common::List<ResArchiveLoader*>::const_iterator CLoaderIterator;
+	Common::List<ResArchiveLoader*> _loaders;
+	ResFileMap _map;
+
 	KyraEngine *_vm;
-	Common::List<ResourceFile*> _pakfiles;
 };
 
 // TODO?: maybe prefix all things here with 'kKyra1' instead of 'k'

Modified: scummvm/trunk/engines/kyra/script.cpp
===================================================================
--- scummvm/trunk/engines/kyra/script.cpp	2008-02-07 22:53:23 UTC (rev 30819)
+++ scummvm/trunk/engines/kyra/script.cpp	2008-02-07 23:13:13 UTC (rev 30820)
@@ -217,43 +217,44 @@
 void ScriptFileParser::setFile(const char *filename, Resource *res) {
 	destroy();
 
-	if (!res->getFileHandle(filename, &_endOffset, _scriptFile))
-		return;
-	_startOffset = _scriptFile.pos();
-	_endOffset += _startOffset;
+	_stream = res->getFileStream(filename);
+	assert(_stream);
+	_startOffset = 0;
+	_endOffset = _stream->size();
 }
 
 void ScriptFileParser::destroy() {
-	_scriptFile.close();
+	delete _stream;
+	_stream = 0;
 	_startOffset = _endOffset = 0;
 }
 
 uint32 ScriptFileParser::getFORMBlockSize() {
-	uint32 oldOffset = _scriptFile.pos();
+	uint32 oldOffset = _stream->pos();
 
-	uint32 data = _scriptFile.readUint32LE();
+	uint32 data = _stream->readUint32LE();
 
 	if (data != FORM_CHUNK) {
-		_scriptFile.seek(oldOffset);
+		_stream->seek(oldOffset);
 		return (uint32)-1;
 	}
 
-	data = _scriptFile.readUint32BE();
+	data = _stream->readUint32BE();
 	return data;
 }
 
 uint32 ScriptFileParser::getIFFBlockSize(const uint32 chunkName) {
 	uint32 size = (uint32)-1;
 
-	_scriptFile.seek(_startOffset + 0x0C);
+	_stream->seek(_startOffset + 0x0C);
 
-	while (_scriptFile.pos() < _endOffset) {
-		uint32 chunk = _scriptFile.readUint32LE();
-		uint32 size_temp = _scriptFile.readUint32BE();
+	while (_stream->pos() < _endOffset) {
+		uint32 chunk = _stream->readUint32LE();
+		uint32 size_temp = _stream->readUint32BE();
 
 		if (chunk != chunkName) {
-			_scriptFile.seek((size_temp + 1) & (~1), SEEK_CUR);
-			assert(_scriptFile.pos() <= _endOffset);
+			_stream->seek((size_temp + 1) & (~1), SEEK_CUR);
+			assert(_stream->pos() <= _endOffset);
 		} else {
 			size = size_temp;
 			break;
@@ -264,20 +265,20 @@
 }
 
 bool ScriptFileParser::loadIFFBlock(const uint32 chunkName, void *loadTo, uint32 ptrSize) {
-	_scriptFile.seek(_startOffset + 0x0C);
+	_stream->seek(_startOffset + 0x0C);
 
-	while (_scriptFile.pos() < _endOffset) {
-		uint32 chunk = _scriptFile.readUint32LE();
-		uint32 chunkSize = _scriptFile.readUint32BE();
+	while (_stream->pos() < _endOffset) {
+		uint32 chunk = _stream->readUint32LE();
+		uint32 chunkSize = _stream->readUint32BE();
 
 		if (chunk != chunkName) {
-			_scriptFile.seek((chunkSize + 1) & (~1), SEEK_CUR);
-			assert(_scriptFile.pos() <= _endOffset);
+			_stream->seek((chunkSize + 1) & (~1), SEEK_CUR);
+			assert(_stream->pos() <= _endOffset);
 		} else {
 			uint32 loadSize = 0;
 
 			loadSize = MIN(ptrSize, chunkSize);
-			_scriptFile.read(loadTo, loadSize);
+			_stream->read(loadTo, loadSize);
 			return true;
 		}
 	}

Modified: scummvm/trunk/engines/kyra/script.h
===================================================================
--- scummvm/trunk/engines/kyra/script.h	2008-02-07 22:53:23 UTC (rev 30819)
+++ scummvm/trunk/engines/kyra/script.h	2008-02-07 23:13:13 UTC (rev 30820)
@@ -29,7 +29,7 @@
 #include "kyra/kyra.h"
 #include "kyra/util.h"
 
-#include "common/file.h"
+#include "common/stream.h"
 
 namespace Kyra {
 
@@ -63,14 +63,14 @@
 
 class ScriptFileParser {
 public:
-	ScriptFileParser() : _scriptFile(), _startOffset(0), _endOffset(0) {}
-	ScriptFileParser(const char *filename, Resource *res) : _scriptFile(), _startOffset(0), _endOffset(0) { setFile(filename, res); }
+	ScriptFileParser() : _stream(0), _startOffset(0), _endOffset(0) {}
+	ScriptFileParser(const char *filename, Resource *res) : _stream(0), _startOffset(0), _endOffset(0) { setFile(filename, res); }
 	~ScriptFileParser() { destroy(); }
 
 	// 'script' must be allocated with new!
 	void setFile(const char *filename, Resource *res);
 
-	operator bool() const { return (_startOffset != _endOffset) && _scriptFile.isOpen(); }
+	operator bool() const { return (_startOffset != _endOffset) && _stream; }
 
 	uint32 getFORMBlockSize();
 	uint32 getIFFBlockSize(const uint32 chunk);
@@ -78,7 +78,7 @@
 private:
 	void destroy();
 
-	Common::File _scriptFile;
+	Common::SeekableReadStream *_stream;
 	uint32 _startOffset;
 	uint32 _endOffset;
 };

Modified: scummvm/trunk/engines/kyra/sound.cpp
===================================================================
--- scummvm/trunk/engines/kyra/sound.cpp	2008-02-07 22:53:23 UTC (rev 30819)
+++ scummvm/trunk/engines/kyra/sound.cpp	2008-02-07 23:13:13 UTC (rev 30820)
@@ -39,7 +39,7 @@
 namespace Kyra {
 
 Sound::Sound(KyraEngine *vm, Audio::Mixer *mixer)
-	: _vm(vm), _mixer(mixer), _currentVocFile(0), _vocHandle(), _compressHandle(),
+	: _vm(vm), _mixer(mixer), _currentVocFile(0), _vocHandle(),
 	_musicEnabled(1), _sfxEnabled(true), _soundDataList(0) {
 }
 
@@ -56,14 +56,10 @@
 		strcpy(filenamebuffer, file);
 		strcat(filenamebuffer, _supportedCodes[i].fileext);
 
-		_compressHandle.close();
-		_vm->resource()->getFileHandle(filenamebuffer, &fileSize, _compressHandle);
-		if (!_compressHandle.isOpen())
+		Common::SeekableReadStream *stream = _vm->resource()->getFileStream(filenamebuffer);
+		if (!stream)
 			continue;
-
-		Common::MemoryReadStream *tmp = _compressHandle.readStream(fileSize);
-		assert(tmp);
-		_currentVocFile = _supportedCodes[i].streamFunc(tmp, true, 0, 0, 1);
+		_currentVocFile = _supportedCodes[i].streamFunc(stream, true, 0, 0, 1);
 		found = true;
 		break;
 	}

Modified: scummvm/trunk/engines/kyra/sound.h
===================================================================
--- scummvm/trunk/engines/kyra/sound.h	2008-02-07 22:53:23 UTC (rev 30819)
+++ scummvm/trunk/engines/kyra/sound.h	2008-02-07 23:13:13 UTC (rev 30820)
@@ -192,7 +192,6 @@
 	const AudioDataStruct *_soundDataList;
 	Audio::AudioStream *_currentVocFile;
 	Audio::SoundHandle _vocHandle;
-	Common::File _compressHandle;
 
 	struct SpeechCodecs {
 		const char *fileext;


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.




More information about the Scummvm-git-logs mailing list