diff options
author | Einar Johan Trøan Sømåen | 2012-07-25 03:20:17 +0200 |
---|---|---|
committer | Einar Johan Trøan Sømåen | 2012-07-25 03:21:22 +0200 |
commit | ab8d13ee5806f7d9cf6e352482934ad371a55e11 (patch) | |
tree | 82af98d2071c92c0d97e6ce6c674f91fd7a9f74e /engines/wintermute/base/file | |
parent | 7521d0f26545381a740307d3a1d2f52e53462bfa (diff) | |
download | scummvm-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.
Diffstat (limited to 'engines/wintermute/base/file')
-rw-r--r-- | engines/wintermute/base/file/BPkgFile.cpp | 107 | ||||
-rw-r--r-- | engines/wintermute/base/file/BPkgFile.h | 49 | ||||
-rw-r--r-- | engines/wintermute/base/file/base_file_entry.cpp | 53 | ||||
-rw-r--r-- | engines/wintermute/base/file/base_file_entry.h | 6 | ||||
-rw-r--r-- | engines/wintermute/base/file/base_package.cpp | 245 | ||||
-rw-r--r-- | engines/wintermute/base/file/base_package.h | 58 |
6 files changed, 299 insertions, 219 deletions
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
|