aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEinar Johan Trøan Sømåen2012-07-25 03:20:17 +0200
committerEinar Johan Trøan Sømåen2012-07-25 03:21:22 +0200
commitab8d13ee5806f7d9cf6e352482934ad371a55e11 (patch)
tree82af98d2071c92c0d97e6ce6c674f91fd7a9f74e
parent7521d0f26545381a740307d3a1d2f52e53462bfa (diff)
downloadscummvm-rg350-ab8d13ee5806f7d9cf6e352482934ad371a55e11.tar.gz
scummvm-rg350-ab8d13ee5806f7d9cf6e352482934ad371a55e11.tar.bz2
scummvm-rg350-ab8d13ee5806f7d9cf6e352482934ad371a55e11.zip
WINTERMUTE: Change the DCP-file access to work as an Common::Archive.
-rw-r--r--engines/wintermute/base/base_file_manager.cpp236
-rw-r--r--engines/wintermute/base/base_file_manager.h12
-rw-r--r--engines/wintermute/base/file/BPkgFile.cpp107
-rw-r--r--engines/wintermute/base/file/BPkgFile.h49
-rw-r--r--engines/wintermute/base/file/base_file_entry.cpp53
-rw-r--r--engines/wintermute/base/file/base_file_entry.h6
-rw-r--r--engines/wintermute/base/file/base_package.cpp245
-rw-r--r--engines/wintermute/base/file/base_package.h58
-rw-r--r--engines/wintermute/module.mk1
9 files changed, 320 insertions, 447 deletions
diff --git a/engines/wintermute/base/base_file_manager.cpp b/engines/wintermute/base/base_file_manager.cpp
index 3317b01c6f..2661081528 100644
--- a/engines/wintermute/base/base_file_manager.cpp
+++ b/engines/wintermute/base/base_file_manager.cpp
@@ -29,13 +29,10 @@
#include "engines/wintermute/base/base_file_manager.h"
#include "engines/wintermute/base/file/base_disk_file.h"
#include "engines/wintermute/base/file/base_save_thumb_file.h"
-#include "engines/wintermute/base/file/base_file_entry.h"
#include "engines/wintermute/base/file/base_package.h"
#include "engines/wintermute/base/file/base_resources.h"
-#include "engines/wintermute/base/file/BPkgFile.h"
#include "engines/wintermute/base/base_registry.h"
#include "engines/wintermute/base/base_game.h"
-#include "engines/wintermute/base/file/dcpackage.h"
#include "engines/wintermute/wintermute.h"
#include "common/str.h"
#include "common/tokenizer.h"
@@ -71,31 +68,18 @@ bool BaseFileManager::cleanup() {
// delete registered paths
_packagePaths.clear();
- // delete file entries
- _filesIter = _files.begin();
- while (_filesIter != _files.end()) {
- delete _filesIter->_value;
- _filesIter++;
- }
- _files.clear();
-
// close open files
for (uint32 i = 0; i < _openFiles.size(); i++) {
delete _openFiles[i];
}
_openFiles.clear();
-
// delete packages
- for (uint32 i = 0; i < _packages.size(); i++)
- delete _packages[i];
_packages.clear();
return STATUS_OK;
}
-
-
//////////////////////////////////////////////////////////////////////
byte *BaseFileManager::readWholeFile(const Common::String &filename, uint32 *size, bool mustExist) {
byte *buffer = NULL;
@@ -149,19 +133,6 @@ bool BaseFileManager::saveFile(const Common::String &filename, byte *buffer, uin
return STATUS_OK;
}
-
-//////////////////////////////////////////////////////////////////////////
-bool BaseFileManager::requestCD(int cd, char *packageFile, const char *filename) {
- // unmount all non-local packages
- for (uint32 i = 0; i < _packages.size(); i++) {
- if (_packages[i]->_cd > 0) _packages[i]->close();
- }
-
-
- return STATUS_FAILED;
-}
-
-
//////////////////////////////////////////////////////////////////////////
bool BaseFileManager::addPath(TPathType type, const Common::FSNode &path) {
if (!path.exists())
@@ -189,8 +160,6 @@ bool BaseFileManager::reloadPaths() {
return initPaths();
}
-
-#define TEMP_BUFFER_SIZE 32768
//////////////////////////////////////////////////////////////////////////
bool BaseFileManager::initPaths() {
if (!_gameRef) // This function only works when the game-registry is loaded
@@ -248,7 +217,6 @@ bool BaseFileManager::registerPackages(const Common::FSList &fslist) {
}
}
}
- debugC(kWinterMuteDebugFileAccess, " Registered %d files in %d package(s)", _files.size(), _packages.size());
return true;
}
@@ -278,177 +246,44 @@ bool BaseFileManager::registerPackages() {
}
}
- debugC(kWinterMuteDebugFileAccess | kWinterMuteDebugLog, " Registered %d files in %d package(s)", _files.size(), _packages.size());
+// debugC(kWinterMuteDebugFileAccess | kWinterMuteDebugLog, " Registered %d files in %d package(s)", _files.size(), _packages.size());
return STATUS_OK;
}
bool BaseFileManager::registerPackage(Common::FSNode file, const Common::String &filename, bool searchSignature) {
- uint32 absoluteOffset = 0;
- bool boundToExe = false;
- Common::SeekableReadStream * package = file.createReadStream();
- if (!package)
- return STATUS_FAILED;
- if (searchSignature) {
- uint32 offset;
- if (!findPackageSignature(package, &offset)) {
- delete package;
- return STATUS_OK;
- } else {
- package->seek(offset, SEEK_SET);
- absoluteOffset = offset;
- boundToExe = true;
- }
- }
-
- TPackageHeader hdr;
- hdr.readFromStream(package);
- if (hdr._magic1 != PACKAGE_MAGIC_1 || hdr._magic2 != PACKAGE_MAGIC_2 || hdr._packageVersion > PACKAGE_VERSION) {
- debugC(kWinterMuteDebugFileAccess | kWinterMuteDebugLog, " Invalid header in package file '%s'. Ignoring.", filename.c_str());
- delete package;
- return STATUS_OK;
- }
-
- if (hdr._packageVersion != PACKAGE_VERSION) {
- debugC(kWinterMuteDebugFileAccess | kWinterMuteDebugLog, " Warning: package file '%s' is outdated.", filename.c_str());
- }
-
- // new in v2
- if (hdr._packageVersion == PACKAGE_VERSION) {
- uint32 dirOffset;
- dirOffset = package->readUint32LE();
- dirOffset += absoluteOffset;
- package->seek(dirOffset, SEEK_SET);
- }
-
- for (uint32 i = 0; i < hdr._numDirs; i++) {
- BasePackage *pkg = new BasePackage(this);
- pkg->_fsnode = file;
- if (!pkg) return STATUS_FAILED;
-
- pkg->_boundToExe = boundToExe;
-
- // read package info
- byte nameLength = package->readByte();
- pkg->_name = new char[nameLength];
- package->read(pkg->_name, nameLength);
- pkg->_cd = package->readByte();
- pkg->_priority = hdr._priority;
-
- if (!hdr._masterIndex) pkg->_cd = 0; // override CD to fixed disk
- _packages.push_back(pkg);
-
-
- // read file entries
- uint32 numFiles = package->readUint32LE();
-
- for (uint32 j = 0; j < numFiles; j++) {
- char *name;
- uint32 offset, length, compLength, flags, timeDate1, timeDate2;
+ PackageSet *pack = new PackageSet(file, filename, searchSignature);
+ _packages.add(file.getName(), pack, pack->getPriority() , true);
- nameLength = package->readByte();
- name = new char[nameLength];
- package->read(name, nameLength);
-
- // v2 - xor name
- if (hdr._packageVersion == PACKAGE_VERSION) {
- for (int k = 0; k < nameLength; k++) {
- ((byte *)name)[k] ^= 'D';
- }
- }
- debugC(kWinterMuteDebugFileAccess, "Package contains %s", name);
- // some old version of ProjectMan writes invalid directory entries
- // so at least prevent strupr from corrupting memory
- name[nameLength - 1] = '\0';
-
- Common::String upcName = name;
- upcName.toUppercase();
- delete[] name;
- name = NULL;
-
- offset = package->readUint32LE();
- offset += absoluteOffset;
- length = package->readUint32LE();
- compLength = package->readUint32LE();
- flags = package->readUint32LE();
-
- if (hdr._packageVersion == PACKAGE_VERSION) {
- timeDate1 = package->readUint32LE();
- timeDate2 = package->readUint32LE();
- }
- _filesIter = _files.find(upcName.c_str());
- if (_filesIter == _files.end()) {
- BaseFileEntry *file = new BaseFileEntry();
- file->_package = pkg;
- file->_offset = offset;
- file->_length = length;
- file->_compressedLength = compLength;
- file->_flags = flags;
-
- _files[upcName.c_str()] = file;
- } else {
- // current package has lower CD number or higher priority, than the registered
- if (pkg->_cd < _filesIter->_value->_package->_cd || pkg->_priority > _filesIter->_value->_package->_priority) {
- _filesIter->_value->_package = pkg;
- _filesIter->_value->_offset = offset;
- _filesIter->_value->_length = length;
- _filesIter->_value->_compressedLength = compLength;
- _filesIter->_value->_flags = flags;
- }
- }
- }
- }
-
-
- delete package;
return STATUS_OK;
}
-
//////////////////////////////////////////////////////////////////////////
-Common::File *BaseFileManager::openPackage(const Common::String &name) {
- //TODO: Is it really necessary to do this when we have the ScummVM-system?
- Common::File *ret = new Common::File();
- for (Common::FSList::iterator it = _packagePaths.begin(); it != _packagePaths.end(); it++) {
- Common::String packageName = (*it).getName();
- if (packageName == (name + ".dcp"))
- ret->open((*it));
- if (ret->isOpen()) {
- return ret;
- }
- }
- Common::String filename = Common::String::format("%s.%s", name.c_str(), PACKAGE_EXTENSION);
- ret->open(filename);
- if (ret->isOpen()) {
- return ret;
+Common::SeekableReadStream *BaseFileManager::openPkgFile(const Common::String &filename) {
+ Common::String upcName = filename;
+ upcName.toUppercase();
+ Common::SeekableReadStream *file = NULL;
+ char fileName[MAX_PATH_LENGTH];
+ strcpy(fileName, upcName.c_str());
+
+ // correct slashes
+ for (int32 i = 0; i < upcName.size(); i++) {
+ if (upcName[i] == '/')
+ upcName.setChar('\\', (uint32)i);
}
- warning("BaseFileManager::OpenPackage - Couldn't load file %s", name.c_str());
- delete ret;
- return NULL;
-}
-
-
-//////////////////////////////////////////////////////////////////////////
-BaseFileEntry *BaseFileManager::getPackageEntry(const Common::String &filename) {
- Common::String upc_name = filename;
- upc_name.toUppercase();
-
- BaseFileEntry *ret = NULL;
- _filesIter = _files.find(upc_name.c_str());
- if (_filesIter != _files.end()) ret = _filesIter->_value;
-
- return ret;
+ Common::ArchiveMemberPtr entry = _packages.getMember(upcName);
+ file = entry->createReadStream();
+ return file;
}
bool BaseFileManager::hasFile(const Common::String &filename) {
if (diskFileExists(filename))
return true;
- if (getPackageEntry(filename))
+ if (_packages.hasFile(filename))
return true; // We don't bother checking if the file can actually be opened, something bigger is wrong if that is the case.
if (BaseResources::hasFile(filename))
return true;
return false;
- return true;
}
//////////////////////////////////////////////////////////////////////////
@@ -495,7 +330,7 @@ Common::SeekableReadStream *BaseFileManager::openFileRaw(const Common::String &f
if (ret)
return ret;
- ret = openPkgFile(filename, this);
+ ret = openPkgFile(filename);
if (ret)
return ret;
@@ -507,37 +342,4 @@ Common::SeekableReadStream *BaseFileManager::openFileRaw(const Common::String &f
return NULL;
}
-
-//////////////////////////////////////////////////////////////////////////
-bool BaseFileManager::findPackageSignature(Common::SeekableReadStream *f, uint32 *offset) {
- byte buf[32768];
-
- byte signature[8];
- ((uint32 *)signature)[0] = PACKAGE_MAGIC_1;
- ((uint32 *)signature)[1] = PACKAGE_MAGIC_2;
-
- uint32 fileSize = (uint32)f->size();
- uint32 startPos = 1024 * 1024;
- uint32 bytesRead = startPos;
-
- while (bytesRead < fileSize - 16) {
- uint32 toRead = MIN((unsigned int)32768, fileSize - bytesRead);
- f->seek((int32)startPos, SEEK_SET);
- uint32 actuallyRead = f->read(buf, toRead);
- if (actuallyRead != toRead) return false;
-
- for (uint32 i = 0; i < toRead - 8; i++)
- if (!memcmp(buf + i, signature, 8)) {
- *offset = startPos + i;
- return true;
- }
-
- bytesRead = bytesRead + toRead - 16;
- startPos = startPos + toRead - 16;
-
- }
- return false;
-
-}
-
} // end of namespace WinterMute
diff --git a/engines/wintermute/base/base_file_manager.h b/engines/wintermute/base/base_file_manager.h
index 776fc32df1..89d1e5b46b 100644
--- a/engines/wintermute/base/base_file_manager.h
+++ b/engines/wintermute/base/base_file_manager.h
@@ -35,10 +35,7 @@
#include "common/file.h"
namespace WinterMute {
-class BaseFile;
-class BaseFileEntry;
class BaseGame;
-class BasePackage;
class BaseFileManager {
public:
bool cleanup();
@@ -55,10 +52,6 @@ public:
bool saveFile(const Common::String &filename, byte *buffer, uint32 bufferSize, bool compressed = false, byte *prefixBuffer = NULL, uint32 prefixSize = 0);
// Used only for detection
bool registerPackages(const Common::FSList &fslist);
- // Used by BasePackage only
- BaseFileEntry *getPackageEntry(const Common::String &filename);
- Common::File *openPackage(const Common::String &name);
- bool requestCD(int cd, char *packageFile, const char *filename);
private:
typedef enum {
PATH_PACKAGE,
@@ -69,13 +62,12 @@ private:
bool addPath(TPathType type, const Common::FSNode &path);
bool registerPackages();
Common::SeekableReadStream *openFileRaw(const Common::String &filename);
+ Common::SeekableReadStream *openPkgFile(const Common::String &filename);
Common::FSList _packagePaths;
bool findPackageSignature(Common::SeekableReadStream *f, uint32 *offset);
bool registerPackage(Common::FSNode package, const Common::String &filename = "", bool searchSignature = false);
- Common::Array<BasePackage *> _packages;
+ Common::SearchSet _packages;
Common::Array<Common::SeekableReadStream *> _openFiles;
- Common::HashMap<Common::String, BaseFileEntry *> _files;
- Common::HashMap<Common::String, BaseFileEntry *>::iterator _filesIter;
// This class is intentionally not a subclass of Base, as it needs to be used by
// the detector too, without launching the entire engine:
BaseGame *_gameRef;
diff --git a/engines/wintermute/base/file/BPkgFile.cpp b/engines/wintermute/base/file/BPkgFile.cpp
deleted file mode 100644
index be37571901..0000000000
--- a/engines/wintermute/base/file/BPkgFile.cpp
+++ /dev/null
@@ -1,107 +0,0 @@
-/* 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.
- *
- */
-
-/*
- * This file is based on WME Lite.
- * http://dead-code.org/redir.php?target=wmelite
- * Copyright (c) 2011 Jan Nedoma
- */
-
-#include "engines/wintermute/base/file/base_package.h"
-#include "engines/wintermute/base/file/BPkgFile.h"
-#include "engines/wintermute/base/base_game.h"
-#include "engines/wintermute/base/base_file_manager.h"
-#include "common/util.h"
-#include "common/file.h"
-#include "common/stream.h"
-#include "common/substream.h"
-#include "common/zlib.h"
-
-namespace WinterMute {
-
-// This file is only needed until the next merge/rebase, as wrapCompressedStream now can set a known size
-// as such it is not renamed to follow the convention of the rest of the files.
-
-// HACK: wrapCompressedStream might set the size to 0, so we need a way to override it.
-class CBPkgFile : public Common::SeekableReadStream {
- uint32 _size;
- Common::SeekableReadStream *_stream;
-public:
- CBPkgFile(Common::SeekableReadStream *stream, uint32 knownLength) : _size(knownLength), _stream(stream) {}
- virtual ~CBPkgFile() {
- delete _stream;
- }
- virtual uint32 read(void *dataPtr, uint32 dataSize) {
- return _stream->read(dataPtr, dataSize);
- }
- virtual bool eos() const {
- return _stream->eos();
- }
- virtual int32 pos() const {
- return _stream->pos();
- }
- virtual int32 size() const {
- return _size;
- }
- virtual bool seek(int32 offset, int whence = SEEK_SET) {
- return _stream->seek(offset, whence);
- }
-};
-
-Common::SeekableReadStream *openPkgFile(const Common::String &filename, BaseFileManager *fileManager) {
- BaseFileEntry *fileEntry;
- Common::SeekableReadStream *file = NULL;
- char fileName[MAX_PATH_LENGTH];
- strcpy(fileName, filename.c_str());
-
- // correct slashes
- for (uint32 i = 0; i < strlen(fileName); i++) {
- if (fileName[i] == '/') fileName[i] = '\\';
- }
-
- fileEntry = fileManager->getPackageEntry(fileName);
- if (!fileEntry) return NULL;
-
- file = fileEntry->_package->getFilePointer();
- if (!file) return NULL;
-
- // TODO: Cleanup
- bool compressed = (fileEntry->_compressedLength != 0);
- /* _size = fileEntry->_length; */
-
- if (compressed) {
- // TODO: Really, most of this logic might be doable directly in the fileEntry?
- // But for now, this should get us rolling atleast.
- file = Common::wrapCompressedReadStream(new Common::SeekableSubReadStream(file, fileEntry->_offset, fileEntry->_offset + fileEntry->_length, DisposeAfterUse::YES));
- } else {
- file = new Common::SeekableSubReadStream(file, fileEntry->_offset, fileEntry->_offset + fileEntry->_length, DisposeAfterUse::YES);
- }
- if (file->size() == 0) {
- file = new CBPkgFile(file, fileEntry->_length);
- }
-
- file->seek(0);
-
- return file;
-}
-
-} // end of namespace WinterMute
diff --git a/engines/wintermute/base/file/BPkgFile.h b/engines/wintermute/base/file/BPkgFile.h
deleted file mode 100644
index ca1b1f837d..0000000000
--- a/engines/wintermute/base/file/BPkgFile.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/* 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.
- *
- */
-
-/*
- * This file is based on WME Lite.
- * http://dead-code.org/redir.php?target=wmelite
- * Copyright (c) 2011 Jan Nedoma
- */
-
-#ifndef WINTERMUTE_BPKGFILE_H
-#define WINTERMUTE_BPKGFILE_H
-
-#include "engines/wintermute/base/file/base_file_entry.h"
-
-// This file is only needed until the next merge/rebase, as wrapCompressedStream now can set a known size
-// as such it is not renamed to follow the convention of the rest of the files.
-
-namespace Common {
-class SeekableReadStream;
-class File;
-}
-
-namespace WinterMute {
-
-class BaseFileManager;
-Common::SeekableReadStream *openPkgFile(const Common::String &filename, BaseFileManager *fileManager);
-
-} // end of namespace WinterMute
-
-#endif
diff --git a/engines/wintermute/base/file/base_file_entry.cpp b/engines/wintermute/base/file/base_file_entry.cpp
index 43527f9fc0..5032650704 100644
--- a/engines/wintermute/base/file/base_file_entry.cpp
+++ b/engines/wintermute/base/file/base_file_entry.cpp
@@ -27,8 +27,61 @@
*/
#include "engines/wintermute/base/file/base_file_entry.h"
+#include "engines/wintermute/base/file/base_package.h"
+#include "common/stream.h"
+#include "common/substream.h"
+#include "common/zlib.h"
namespace WinterMute {
+// HACK: wrapCompressedStream might set the size to 0, so we need a way to override it.
+class CBPkgFile : public Common::SeekableReadStream {
+ uint32 _size;
+ Common::SeekableReadStream *_stream;
+public:
+ CBPkgFile(Common::SeekableReadStream *stream, uint32 knownLength) : _size(knownLength), _stream(stream) {}
+ virtual ~CBPkgFile() {
+ delete _stream;
+ }
+ virtual uint32 read(void *dataPtr, uint32 dataSize) {
+ return _stream->read(dataPtr, dataSize);
+ }
+ virtual bool eos() const {
+ return _stream->eos();
+ }
+ virtual int32 pos() const {
+ return _stream->pos();
+ }
+ virtual int32 size() const {
+ return _size;
+ }
+ virtual bool seek(int32 offset, int whence = SEEK_SET) {
+ return _stream->seek(offset, whence);
+ }
+};
+
+Common::SeekableReadStream *BaseFileEntry::createReadStream() const {
+ Common::SeekableReadStream *file = _package->getFilePointer();
+ if (!file) return NULL;
+
+ // TODO: Cleanup
+ bool compressed = (_compressedLength != 0);
+ /* _size = fileEntry->_length; */
+
+ if (compressed) {
+ // TODO: Really, most of this logic might be doable directly in the fileEntry?
+ // But for now, this should get us rolling atleast.
+ file = Common::wrapCompressedReadStream(new Common::SeekableSubReadStream(file, _offset, _offset + _length, DisposeAfterUse::YES));
+ } else {
+ file = new Common::SeekableSubReadStream(file, _offset, _offset + _length, DisposeAfterUse::YES);
+ }
+ if (file->size() == 0) {
+ file = new CBPkgFile(file, _length);
+ }
+
+ file->seek(0);
+
+ return file;
+}
//////////////////////////////////////////////////////////////////////////
BaseFileEntry::BaseFileEntry(){
diff --git a/engines/wintermute/base/file/base_file_entry.h b/engines/wintermute/base/file/base_file_entry.h
index 086a70e7ed..b94a6cd9fc 100644
--- a/engines/wintermute/base/file/base_file_entry.h
+++ b/engines/wintermute/base/file/base_file_entry.h
@@ -29,14 +29,18 @@
#ifndef WINTERMUTE_BFILEENTRY_H
#define WINTERMUTE_BFILEENTRY_H
+#include "common/archive.h"
#include "common/str.h"
+#include "common/stream.h"
namespace WinterMute {
class BasePackage;
-class BaseFileEntry {
+class BaseFileEntry : public Common::ArchiveMember {
public:
+ virtual Common::SeekableReadStream *createReadStream() const;
+ virtual Common::String getName() const { return _filename; }
uint32 _timeDate2;
uint32 _timeDate1;
uint32 _flags;
diff --git a/engines/wintermute/base/file/base_package.cpp b/engines/wintermute/base/file/base_package.cpp
index 1706a7a50b..6987cad3e6 100644
--- a/engines/wintermute/base/file/base_package.cpp
+++ b/engines/wintermute/base/file/base_package.cpp
@@ -27,78 +27,229 @@
*/
#include "engines/wintermute/base/file/base_package.h"
-#include "engines/wintermute/base/base_file_manager.h"
+#include "engines/wintermute/base/file/base_file_entry.h"
+#include "engines/wintermute/base/file/dcpackage.h"
+#include "engines/wintermute/wintermute.h"
#include "common/file.h"
#include "common/stream.h"
+#include "common/debug.h"
namespace WinterMute {
-//////////////////////////////////////////////////////////////////////
-// Construction/Destruction
-//////////////////////////////////////////////////////////////////////
-
-//////////////////////////////////////////////////////////////////////////
-BasePackage::BasePackage(BaseFileManager *fileMan)/*: BaseClass(inGame) */{
- _file = NULL;
- _name = NULL;
+BasePackage::BasePackage() {
+ _name = "";
_cd = 0;
_priority = 0;
_boundToExe = false;
- _fileManager = fileMan;
}
+Common::SeekableReadStream *BasePackage::getFilePointer() {
+ Common::SeekableReadStream *stream = _fsnode.createReadStream();
-//////////////////////////////////////////////////////////////////////////
-BasePackage::~BasePackage() {
- if (_name) delete [] _name;
- closeFilePointer(_file);
+ return stream;
}
-
-//////////////////////////////////////////////////////////////////////////
-bool BasePackage::open() {
- if (_file) return true;
- else {
- _file = getFilePointer();
- return _file ? true : false;
+static bool findPackageSignature(Common::SeekableReadStream *f, uint32 *offset) {
+ byte buf[32768];
+
+ byte signature[8];
+ ((uint32 *)signature)[0] = PACKAGE_MAGIC_1;
+ ((uint32 *)signature)[1] = PACKAGE_MAGIC_2;
+
+ uint32 fileSize = (uint32)f->size();
+ uint32 startPos = 1024 * 1024;
+ uint32 bytesRead = startPos;
+
+ while (bytesRead < fileSize - 16) {
+ uint32 toRead = MIN((unsigned int)32768, fileSize - bytesRead);
+ f->seek((int32)startPos, SEEK_SET);
+ uint32 actuallyRead = f->read(buf, toRead);
+ if (actuallyRead != toRead) return false;
+
+ for (uint32 i = 0; i < toRead - 8; i++)
+ if (!memcmp(buf + i, signature, 8)) {
+ *offset = startPos + i;
+ return true;
+ }
+
+ bytesRead = bytesRead + toRead - 16;
+ startPos = startPos + toRead - 16;
+
}
+ return false;
+
}
+PackageSet::PackageSet(Common::FSNode file, const Common::String &filename, bool searchSignature) {
+ uint32 absoluteOffset = 0;
+ _priority = 0;
+ bool boundToExe = false;
+ Common::SeekableReadStream *stream = file.createReadStream();
+ if (!stream)
+ return;
+ if (searchSignature) {
+ uint32 offset;
+ if (!findPackageSignature(stream, &offset)) {
+ delete stream;
+ return;
+ } else {
+ stream->seek(offset, SEEK_SET);
+ absoluteOffset = offset;
+ boundToExe = true;
+ }
+ }
+
+ TPackageHeader hdr;
+ hdr.readFromStream(stream);
+ if (hdr._magic1 != PACKAGE_MAGIC_1 || hdr._magic2 != PACKAGE_MAGIC_2 || hdr._packageVersion > PACKAGE_VERSION) {
+ debugC(kWinterMuteDebugFileAccess | kWinterMuteDebugLog, " Invalid header in package file '%s'. Ignoring.", filename.c_str());
+ delete stream;
+ return;
+ }
+
+ if (hdr._packageVersion != PACKAGE_VERSION) {
+ debugC(kWinterMuteDebugFileAccess | kWinterMuteDebugLog, " Warning: package file '%s' is outdated.", filename.c_str());
+ }
+ _priority = hdr._priority;
+ // new in v2
+ if (hdr._packageVersion == PACKAGE_VERSION) {
+ uint32 dirOffset;
+ dirOffset = stream->readUint32LE();
+ dirOffset += absoluteOffset;
+ stream->seek(dirOffset, SEEK_SET);
+ }
+ assert(hdr._numDirs == 1);
+ for (uint32 i = 0; i < hdr._numDirs; i++) {
+ BasePackage *pkg = new BasePackage();
+ if (!pkg) return;
+ pkg->_fsnode = file;
+
+ pkg->_boundToExe = boundToExe;
+
+ // read package info
+ byte nameLength = stream->readByte();
+ char *pkgName = new char[nameLength];
+ stream->read(pkgName, nameLength);
+ pkg->_name = pkgName;
+ pkg->_cd = stream->readByte();
+ pkg->_priority = hdr._priority;
+ delete[] pkgName;
+ pkgName = NULL;
+
+ if (!hdr._masterIndex) pkg->_cd = 0; // override CD to fixed disk
+ _packages.push_back(pkg);
+
+
+ // read file entries
+ uint32 numFiles = stream->readUint32LE();
+
+ for (uint32 j = 0; j < numFiles; j++) {
+ char *name;
+ uint32 offset, length, compLength, flags, timeDate1, timeDate2;
+
+ nameLength = stream->readByte();
+ name = new char[nameLength];
+ stream->read(name, nameLength);
+
+ // v2 - xor name
+ if (hdr._packageVersion == PACKAGE_VERSION) {
+ for (int k = 0; k < nameLength; k++) {
+ ((byte *)name)[k] ^= 'D';
+ }
+ }
+ debugC(kWinterMuteDebugFileAccess, "Package contains %s", name);
+ warning( "Package contains %s", name);
+ // some old version of ProjectMan writes invalid directory entries
+ // so at least prevent strupr from corrupting memory
+ name[nameLength - 1] = '\0';
+
+ Common::String upcName = name;
+ upcName.toUppercase();
+ delete[] name;
+ name = NULL;
+
+ offset = stream->readUint32LE();
+ offset += absoluteOffset;
+ length = stream->readUint32LE();
+ compLength = stream->readUint32LE();
+ flags = stream->readUint32LE();
+
+ if (hdr._packageVersion == PACKAGE_VERSION) {
+ timeDate1 = stream->readUint32LE();
+ timeDate2 = stream->readUint32LE();
+ }
+ _filesIter = _files.find(upcName.c_str());
+ if (_filesIter == _files.end()) {
+ BaseFileEntry *fileEntry = new BaseFileEntry();
+ fileEntry->_package = pkg;
+ fileEntry->_offset = offset;
+ fileEntry->_length = length;
+ fileEntry->_compressedLength = compLength;
+ fileEntry->_flags = flags;
+
+ _files[upcName.c_str()] = Common::ArchiveMemberPtr(fileEntry);
+ } else {
+ // current package has higher priority than the registered
+ // TODO: This cast might be a bit ugly.
+ BaseFileEntry *filePtr = (BaseFileEntry*) &*(_filesIter->_value);
+ if (pkg->_priority > filePtr->_package->_priority) {
+ filePtr->_package = pkg;
+ filePtr->_offset = offset;
+ filePtr->_length = length;
+ filePtr->_compressedLength = compLength;
+ filePtr->_flags = flags;
+ }
+ }
+ }
+ }
+ debugC(kWinterMuteDebugFileAccess, " Registered %d files in %d package(s)", _files.size(), _packages.size());
+
+ delete stream;
+}
-//////////////////////////////////////////////////////////////////////////
-bool BasePackage::close() {
- delete _file;
- _file = NULL;
- return true;
+PackageSet::~PackageSet() {
+ for (Common::Array<BasePackage*>::iterator it = _packages.begin(); it != _packages.end(); it++) {
+ delete *it;
+ }
+ _packages.clear();
}
+bool PackageSet::hasFile(const Common::String &name) const {
+ Common::String upcName = name;
+ upcName.toUppercase();
+ Common::HashMap<Common::String, Common::ArchiveMemberPtr>::const_iterator it;
+ it = _files.find(upcName.c_str());
+ return (it != _files.end());
+}
-//////////////////////////////////////////////////////////////////////////
-bool BasePackage::read(Common::SeekableReadStream *file, uint32 offset, byte *buffer, uint32 size) {
- bool ret;
- if (!(ret = open())) return ret;
- else {
- if (file->seek(offset, SEEK_SET)) return false;
- if (file->read(buffer, size) != 1) return false;
- else return true;
+int PackageSet::listMembers(Common::ArchiveMemberList &list) const {
+ Common::HashMap<Common::String, Common::ArchiveMemberPtr>::const_iterator it = _files.begin();
+ Common::HashMap<Common::String, Common::ArchiveMemberPtr>::const_iterator end = _files.end();
+ int count = 0;
+ for (; it != end; ++it) {
+ const Common::ArchiveMemberPtr ptr(it->_value);
+ list.push_back(ptr);
+ count++;
}
+ return count;
}
-//////////////////////////////////////////////////////////////////////////
-Common::SeekableReadStream *BasePackage::getFilePointer() {
- Common::SeekableReadStream *stream = _fsnode.createReadStream();
-/* Common::File *file = _fileManager->openPackage(_name);
- if (!file) {
- _fileManager->requestCD(_cd, _name, "");
- file = _fileManager->openPackage(_name);
- }*/
- return stream;
+const Common::ArchiveMemberPtr PackageSet::getMember(const Common::String &name) const {
+ Common::String upcName = name;
+ upcName.toUppercase();
+ Common::HashMap<Common::String, Common::ArchiveMemberPtr>::const_iterator it;
+ it = _files.find(upcName.c_str());
+ return Common::ArchiveMemberPtr(it->_value);
}
-//////////////////////////////////////////////////////////////////////////
-void BasePackage::closeFilePointer(Common::SeekableReadStream *&file) {
- delete file;
- file = NULL;
+Common::SeekableReadStream *PackageSet::createReadStreamForMember(const Common::String &name) const {
+ Common::String upcName = name;
+ upcName.toUppercase();
+ Common::HashMap<Common::String, Common::ArchiveMemberPtr>::const_iterator it;
+ it = _files.find(upcName.c_str());
+ if (it != _files.end())
+ return it->_value->createReadStream();
+ return NULL;
}
} // end of namespace WinterMute
diff --git a/engines/wintermute/base/file/base_package.h b/engines/wintermute/base/file/base_package.h
index 673655a710..b9a7bc5934 100644
--- a/engines/wintermute/base/file/base_package.h
+++ b/engines/wintermute/base/file/base_package.h
@@ -29,32 +29,60 @@
#ifndef WINTERMUTE_BPACKAGE_H
#define WINTERMUTE_BPACKAGE_H
+#include "common/archive.h"
#include "common/stream.h"
#include "common/fs.h"
-namespace Common {
-class SeekableReadStream;
-}
-
namespace WinterMute {
-class BaseFileManager;
class BasePackage {
- BaseFileManager *_fileManager;
public:
Common::SeekableReadStream *getFilePointer();
- void closeFilePointer(Common::SeekableReadStream *&file);
-
Common::FSNode _fsnode;
bool _boundToExe;
byte _priority;
- bool read(Common::SeekableReadStream *file, uint32 offset, byte *buffer, uint32 size);
- bool close();
- bool open();
- char *_name;
+ Common::String _name;
int _cd;
- Common::SeekableReadStream *_file;
- BasePackage(BaseFileManager *fileMan);
- ~BasePackage();
+ BasePackage();
+};
+
+class PackageSet : public Common::Archive {
+public:
+ virtual ~PackageSet();
+
+ PackageSet(Common::FSNode package, const Common::String &filename = "", bool searchSignature = false);
+ /**
+ * Check if a member with the given name is present in the Archive.
+ * Patterns are not allowed, as this is meant to be a quick File::exists()
+ * replacement.
+ */
+ virtual bool hasFile(const Common::String &name) const;
+
+ /**
+ * Add all members of the Archive to list.
+ * Must only append to list, and not remove elements from it.
+ *
+ * @return the number of names added to list
+ */
+ virtual int listMembers(Common::ArchiveMemberList &list) const;
+
+ /**
+ * Returns a ArchiveMember representation of the given file.
+ */
+ virtual const Common::ArchiveMemberPtr getMember(const Common::String &name) const;
+
+ /**
+ * Create a stream bound to a member with the specified name in the
+ * archive. If no member with this name exists, 0 is returned.
+ * @return the newly created input stream
+ */
+ virtual Common::SeekableReadStream *createReadStreamForMember(const Common::String &name) const;
+
+ int getPriority() const { return _priority; }
+private:
+ byte _priority;
+ Common::Array<BasePackage *> _packages;
+ Common::HashMap<Common::String, Common::ArchiveMemberPtr> _files;
+ Common::HashMap<Common::String, Common::ArchiveMemberPtr>::iterator _filesIter;
};
} // end of namespace WinterMute
diff --git a/engines/wintermute/module.mk b/engines/wintermute/module.mk
index 3ad30cf66b..02ba08f255 100644
--- a/engines/wintermute/module.mk
+++ b/engines/wintermute/module.mk
@@ -44,7 +44,6 @@ MODULE_OBJS := \
base/file/base_package.o \
base/file/base_resources.o \
base/file/base_save_thumb_file.o \
- base/file/BPkgFile.o \
base/font/base_font_bitmap.o \
base/font/base_font_truetype.o \
base/font/base_font.o \