From 4581b26b12d21801eee0c5df2dbd1b260300498c Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Thu, 20 Feb 2014 22:27:01 -0500 Subject: MADS: Implemented resource manager using ScummVM Archive interface --- engines/mads/compression.cpp | 4 +- engines/mads/font.cpp | 4 +- engines/mads/mads.cpp | 2 +- engines/mads/msurface.cpp | 23 ++- engines/mads/nebular/dialogs_nebular.h | 2 + engines/mads/resources.cpp | 259 ++++++++++++++++++++++++++++++++- engines/mads/resources.h | 35 +++-- 7 files changed, 293 insertions(+), 36 deletions(-) (limited to 'engines/mads') diff --git a/engines/mads/compression.cpp b/engines/mads/compression.cpp index b5e24dfc5e..febb6ec90f 100644 --- a/engines/mads/compression.cpp +++ b/engines/mads/compression.cpp @@ -46,9 +46,9 @@ MadsPack::MadsPack(Common::SeekableReadStream *stream) { } MadsPack::MadsPack(const Common::String &resourceName, MADSEngine *vm) { - Common::SeekableReadStream *stream = vm->_resources->get(resourceName); + Common::SeekableReadStream *stream = nullptr; //vm->_resources->get(resourceName); initialise(stream); - vm->_resources->toss(resourceName); +// vm->_resources->toss(resourceName); } void MadsPack::initialise(Common::SeekableReadStream *stream) { diff --git a/engines/mads/font.cpp b/engines/mads/font.cpp index e97cc95fdf..076eca92c6 100644 --- a/engines/mads/font.cpp +++ b/engines/mads/font.cpp @@ -233,7 +233,7 @@ void FontM4::setFont(const Common::String &filename) { _sysFont = false; _filename = filename; - Common::SeekableReadStream *fontFile = _vm->_resources->openFile(filename); + Common::SeekableReadStream *fontFile = nullptr; //_vm->_resources->openFile(filename); if (fontFile->readUint32LE() != MKTAG('F', 'O', 'N', 'T')) { warning("Font: FONT tag expected"); @@ -272,7 +272,7 @@ void FontM4::setFont(const Common::String &filename) { _charData = new uint8[fontSize]; fontFile->read(_charData, fontSize); - _vm->_resources->toss(filename); +// _vm->_resources->toss(filename); } int FontM4::getBpp(int charWidth) { diff --git a/engines/mads/mads.cpp b/engines/mads/mads.cpp index 05c11409db..ec99b314a7 100644 --- a/engines/mads/mads.cpp +++ b/engines/mads/mads.cpp @@ -72,10 +72,10 @@ void MADSEngine::initialise() { MSurface::setVm(this); MSprite::setVm(this); + ResourcesManager::init(this); _events = new EventsManager(this); _palette = Palette::init(this); _font = Font::init(this); - _resources = new ResourcesManager(this); _screen = MSurface::init(true); _sound = new SoundManager(this, _mixer); _userInterface = UserInterface::init(this); diff --git a/engines/mads/msurface.cpp b/engines/mads/msurface.cpp index f71a4a7a4e..2c0b433159 100644 --- a/engines/mads/msurface.cpp +++ b/engines/mads/msurface.cpp @@ -26,6 +26,7 @@ #include "mads/mads.h" #include "mads/msprite.h" #include "mads/msurface.h" +#include "mads/resources.h" namespace MADS { @@ -412,14 +413,14 @@ void MSurfaceMADS::loadBackground(int roomNumber, RGBList **palData) { tileMap[i] = mapStream->readUint16LE(); delete mapStream; - _vm->_resources->toss(resourceName); +// _vm->_resources->toss(resourceName); // -------------------------------------------------------------------------------- // Tile map data, which needs to be kept compressed, as the tile offsets refer to // the compressed data. Each tile is then uncompressed separately sprintf(resourceName, "rm%d.tt", roomNumber); - Common::SeekableReadStream *tileDataComp = _vm->_resources->get(resourceName); + Common::SeekableReadStream *tileDataComp = nullptr; //_vm->_resources->get(resourceName); MadsPack tileData(tileDataComp); Common::SeekableReadStream *tileDataUncomp = tileData.getItemStream(0); @@ -499,7 +500,7 @@ void MSurfaceMADS::loadBackground(int roomNumber, RGBList **palData) { } } tileSet.clear(); - _vm->_resources->toss(resourceName); +// _vm->_resources->toss(resourceName); } void MSurfaceMADS::loadInterface(int index, RGBList **palData) { @@ -534,10 +535,10 @@ void MSurfaceNebular::loadBackground(int roomNumber, RGBList **palData) { empty(); Common::String resourceName = Common::String::format("rm%d.art", roomNumber); - Common::SeekableReadStream *stream = _vm->_resources->get(resourceName); + Common::SeekableReadStream *stream = nullptr; //_vm->_resources->get(resourceName); loadBackgroundStream(stream, palData); - _vm->_resources->toss(resourceName); +// _vm->_resources->toss(resourceName); } void MSurfaceNebular::loadBackgroundStream(Common::SeekableReadStream *source, RGBList **palData) { @@ -597,10 +598,10 @@ void MSurfaceM4::loadBackground(int roomNumber, RGBList **palData) { if (palData) *palData = NULL; Common::String resourceName = Common::String::format("%i.tt", roomNumber); - Common::SeekableReadStream *stream = _vm->_resources->get(resourceName); + Common::SeekableReadStream *stream = nullptr;//_vm->_resources->get(resourceName); loadBackgroundStream(stream); - _vm->_resources->toss(resourceName); +// _vm->_resources->toss(resourceName); } void MSurfaceM4::loadBackgroundStream(Common::SeekableReadStream *source) { @@ -663,15 +664,11 @@ void MSurfaceM4::loadBackgroundStream(Common::SeekableReadStream *source) { /*------------------------------------------------------------------------*/ void MSurfaceRiddle::loadBackground(const Common::String &sceneName) { - char resourceName[20]; - Common::SeekableReadStream *stream; // Loads a Riddle scene Common::String resName = Common::String::format("%s.tt", sceneName.c_str()); - stream = _vm->_resources->get(resourceName); - - loadBackgroundStream(stream); + File stream(resName); - _vm->_resources->toss(resourceName); + loadBackgroundStream(&stream); } } // End of namespace MADS diff --git a/engines/mads/nebular/dialogs_nebular.h b/engines/mads/nebular/dialogs_nebular.h index 669ac1e775..a747f7575d 100644 --- a/engines/mads/nebular/dialogs_nebular.h +++ b/engines/mads/nebular/dialogs_nebular.h @@ -31,6 +31,8 @@ namespace MADS { namespace Nebular { class CopyProtectionDialog { +private: + public: static bool show() { return false; } }; diff --git a/engines/mads/resources.cpp b/engines/mads/resources.cpp index 27b94a9e55..0630230bec 100644 --- a/engines/mads/resources.cpp +++ b/engines/mads/resources.cpp @@ -21,12 +21,267 @@ */ #include "common/scummsys.h" +#include "common/archive.h" +#include "common/substream.h" +#include "common/textconsole.h" +#include "mads/mads.h" #include "mads/resources.h" namespace MADS { -ResourcesManager::ResourcesManager(MADSEngine *vm) { - _vm = vm; +enum ResourceType {RESTYPE_ROOM, RESTYPE_SC, RESTYPE_TEXT, RESTYPE_QUO, RESTYPE_I, + RESTYPE_OB, RESTYPE_FONT, RESTYPE_SOUND, RESTYPE_SPEECH, RESTYPE_HAS_EXT, RESTYPE_NO_EXT}; + +/** + * HAG Archives implementation + */ +class HagArchive : public Common::Archive { +private: + /** + * Details of a single entry in a HAG file index + */ + struct HagEntry { + Common::String _resourceName; + uint32 _offset; + uint32 _size; + + HagEntry(): _offset(0), _size(0) {} + HagEntry(Common::String resourceName, uint32 offset, uint32 size): + _resourceName(resourceName), _offset(offset), _size(size) {} + }; + + class HagIndex { + public: + Common::List _entries; + Common::String _filename; + }; + + Common::Array _index; + + /** + * Load the index of all the game's HAG files + */ + void loadIndex(); + + /** + * Given a resource name, opens up the correct HAG file and returns whether + * an entry with the given name exists. + */ + bool getHeaderEntry(const Common::String &resourceName, HagIndex &hagIndex, HagEntry &hagEntry) const; + + /** + * Returns the HAG resource filename that will contain a given resource + */ + Common::String getResourceFilename(const Common::String &resourceName) const; + + /** + * Return a resource type given a resource name + */ + ResourceType getResourceType(const Common::String &resourceName) const; +public: + HagArchive(); + virtual ~HagArchive(); + + // Archive implementation + virtual bool hasFile(const Common::String &name) const; + virtual int listMembers(Common::ArchiveMemberList &list) const; + virtual const Common::ArchiveMemberPtr getMember(const Common::String &name) const; + virtual Common::SeekableReadStream *createReadStreamForMember(const Common::String &name) const; +}; + +void ResourcesManager::init(MADSEngine *vm) { + if (vm->getGameFeatures() & GF_MADS) + SearchMan.add("HAG", new HagArchive()); + else + error("Unsupported game engine"); +} + +/*------------------------------------------------------------------------*/ + +void File::openFile(const Common::String &filename) { + if (!Common::File::open(filename)) + error("Could not open file - %s", filename.c_str()); +} + +/*------------------------------------------------------------------------*/ + +const char *const MADSCONCAT_STRING = "MADSCONCAT"; + +HagArchive::HagArchive() { + loadIndex(); +} + +HagArchive::~HagArchive() { +} + +// Archive implementation +bool HagArchive::hasFile(const Common::String &name) const { + HagIndex hagIndex; + HagEntry hagEntry; + return getHeaderEntry(name, hagIndex, hagEntry); +} + +int HagArchive::listMembers(Common::ArchiveMemberList &list) const { + int members = 0; + + for (uint hagCtr = 0; hagCtr < _index.size(); ++hagCtr) { + HagIndex hagIndex = _index[hagCtr]; + Common::List::iterator i; + + for (i = hagIndex._entries.begin(); i != hagIndex._entries.end(); ++i) { + list.push_back(Common::ArchiveMemberList::value_type( + new Common::GenericArchiveMember((*i)._resourceName, this))); + ++members; + } + } + + return members; +} + +const Common::ArchiveMemberPtr HagArchive::getMember(const Common::String &name) const { + if (!hasFile(name)) + return Common::ArchiveMemberPtr(); + + return Common::ArchiveMemberPtr(new Common::GenericArchiveMember(name, this)); +} + +Common::SeekableReadStream *HagArchive::createReadStreamForMember(const Common::String &name) const { + HagIndex hagIndex; + HagEntry hagEntry; + + if (getHeaderEntry(name, hagIndex, hagEntry)) { + // Entry found. If the correct file is not already open, open it + Common::File f; + if (!f.open(hagIndex._filename)) + error("Could not open HAG file"); + + // Return a substream for the specific resource + return new Common::SeekableSubReadStream(&f, + hagEntry._offset, hagEntry._size, DisposeAfterUse::YES); + } + + return nullptr; +} + +void HagArchive::loadIndex() { + Common::File hagFile; + + for (int sectionIndex = -1; sectionIndex < 10; ++sectionIndex) { + Common::String filename = (sectionIndex == -1) ? "GLOBAL.HAG" : + Common::String::format("SECTION%d.HAG", sectionIndex); + if (!hagFile.open(filename)) + error("Could not locate HAG file - %s", filename.c_str()); + + // Check for header + char headerBuffer[16]; + if ((hagFile.read(headerBuffer, 16) != 16) || + (strncmp(headerBuffer, MADSCONCAT_STRING, 10) != 0)) + error("Invalid HAG file opened"); + + // Scan through the HAG index + int numEntries = hagFile.readUint16LE(); + + HagIndex hagIndex; + for (int idx = 0; idx < numEntries; ++idx) { + // Read in the details of the next resource + char resourceBuffer[14]; + uint32 offset = hagFile.readUint32LE(); + uint32 size = hagFile.readUint32LE(); + hagFile.read(resourceBuffer, 14); + + hagIndex._entries.push_back(HagEntry(resourceBuffer, offset, size)); + } + + hagFile.close(); + _index.push_back(hagIndex); + } +} + +bool HagArchive::getHeaderEntry(const Common::String &resourceName, + HagIndex &hagIndex, HagEntry &hagEntry) const { + Common::String resName = resourceName; + resName.toUppercase(); + if (resName[0] == '*') + resName.deleteChar(0); + + Common::String hagFilename = getResourceFilename(resName); + + // Find the index for the given file + for (uint hagCtr = 0; hagCtr < _index.size(); ++hagCtr) { + hagIndex = _index[hagCtr]; + + if (hagIndex._filename == hagFilename) { + Common::List::iterator ei; + for (ei = hagIndex._entries.begin(); ei != hagIndex._entries.end(); ++ei) { + hagEntry = *ei; + if (hagEntry._resourceName == resName) + return true; + } + } + } + + return false; +} + +Common::String HagArchive::getResourceFilename(const Common::String &resourceName) const { + ResourceType resType = getResourceType(resourceName); + Common::String outputFilename = "GLOBAL.HAG"; + + if ((resType == RESTYPE_ROOM) || (resType == RESTYPE_SC)) { + int value = atoi(resourceName.c_str() + 2); + int hagFileNum = (resType == RESTYPE_ROOM) ? value / 100 : value; + + if (hagFileNum > 0) + outputFilename = Common::String::format("SECTION%d.HAG", hagFileNum); + } + + if (resType == RESTYPE_SPEECH) + outputFilename = "SPEECH.HAG"; + + return outputFilename; +} + +ResourceType HagArchive::getResourceType(const Common::String &resourceName) const { + if (resourceName.hasPrefix("RM")) { + // Room resource + return RESTYPE_ROOM; + } else if (resourceName.hasPrefix("SC")) { + // SC resource + return RESTYPE_SC; + } else if (resourceName.hasSuffix(".TXT")) { + // Text resource + return RESTYPE_TEXT; + } else if (resourceName.hasSuffix(".QUO")) { + // QUO resource + return RESTYPE_QUO; + } else if (resourceName.hasPrefix("I")) { + // I resource + return RESTYPE_I; + } else if (resourceName.hasPrefix("OB")) { + // OB resource + return RESTYPE_OB; + } else if (resourceName.hasPrefix("FONT")) { + // FONT resource + return RESTYPE_FONT; + } else if (resourceName.hasPrefix("SOUND")) { + // SOUND resource + return RESTYPE_SOUND; + } else if (resourceName.hasPrefix("SPCHC")) { + // SPEECH resource + return RESTYPE_SPEECH; + } + + // Check for a known extension + const char *extPos = strchr(resourceName.c_str(), '.'); + if (extPos) { + ++extPos; + if (!strcmp(extPos, "FL") || !strcmp(extPos, "LBM") || !strcmp(extPos, "ANM") || + !strcmp(extPos, "AA") || !strcmp(extPos, "SS")) { + return RESTYPE_HAS_EXT; + } + } + + return RESTYPE_NO_EXT; } } // End of namespace MADS diff --git a/engines/mads/resources.h b/engines/mads/resources.h index 68bb475aee..f4b7009e13 100644 --- a/engines/mads/resources.h +++ b/engines/mads/resources.h @@ -24,7 +24,7 @@ #define MADS_RESOURCES_H #include "common/scummsys.h" -#include "common/stream.h" +#include "common/file.h" #include "common/str.h" namespace MADS { @@ -32,29 +32,32 @@ namespace MADS { class MADSEngine; class ResourcesManager { -private: - MADSEngine *_vm; public: - ResourcesManager(MADSEngine *vm); + /** + * Instantiates the resource manager + */ + static void init(MADSEngine *vm); +}; +/** + * Derived file class + */ +class File: public Common::File { +public: /** - * Return a named resource + * Constructor */ - Common::SeekableReadStream *get(const Common::String &resourceName, bool loadFlag = false) { - // TODO - return nullptr; - } + File(): Common::File() {} - Common::SeekableReadStream *openFile(const Common::String &resourceName) { - return get(resourceName, false); - } + /** + * Constructor + */ + File(const Common::String &filename) { openFile(filename); } /** - * Release a previously loaded resource + * Opens the given file, throwing an error if it can't be opened */ - void toss(const Common::String &resourceName) { - // TODO - } + void openFile(const Common::String &filename); }; } // End of namespace MADS -- cgit v1.2.3