diff options
Diffstat (limited to 'engines/agos/installshield_cab.cpp')
-rw-r--r-- | engines/agos/installshield_cab.cpp | 126 |
1 files changed, 73 insertions, 53 deletions
diff --git a/engines/agos/installshield_cab.cpp b/engines/agos/installshield_cab.cpp index a8b5d0fba2..f7b49a64c5 100644 --- a/engines/agos/installshield_cab.cpp +++ b/engines/agos/installshield_cab.cpp @@ -46,59 +46,80 @@ #include "agos/installshield_cab.h" #include "common/debug.h" +#include "common/file.h" #include "common/memstream.h" #include "common/zlib.h" namespace AGOS { -InstallShieldCabinet::InstallShieldCabinet() : Common::Archive() { - _stream = 0; -} +class InstallShieldCabinet : public Common::Archive { + Common::String _installShieldFilename; + +public: + InstallShieldCabinet(const Common::String &filename); + ~InstallShieldCabinet(); + + // Common::Archive API implementation + bool hasFile(const Common::String &name); + int listMembers(Common::ArchiveMemberList &list); + Common::ArchiveMemberPtr getMember(const Common::String &name); + Common::SeekableReadStream *createReadStreamForMember(const Common::String &name) const; + +private: + struct FileEntry { + uint32 uncompressedSize; + uint32 compressedSize; + uint32 offset; + uint16 flags; + }; + + typedef Common::HashMap<Common::String, FileEntry, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> FileMap; + FileMap _map; +}; InstallShieldCabinet::~InstallShieldCabinet() { - close(); + _map.clear(); } -bool InstallShieldCabinet::open(const Common::String &filename) { - close(); +InstallShieldCabinet::InstallShieldCabinet(const Common::String &filename) : _installShieldFilename(filename) { + Common::File installShieldFile; - _stream = SearchMan.createReadStreamForMember(filename); - - if (!_stream) - return false; + if (!installShieldFile.open(_installShieldFilename)) { + warning("InstallShieldCabinet::InstallShieldCabinet(): Could not find the archive file %s", _installShieldFilename.c_str()); + return; + } // Note that we only support a limited subset of cabinet files // Only single cabinet files and ones without data shared between // cabinets. // Check for the magic uint32 - if (_stream->readUint32LE() != 0x28635349) { - close(); - return false; + if (installShieldFile.readUint32LE() != 0x28635349) { + warning("InstallShieldCabinet::InstallShieldCabinet(): Magic ID doesn't match"); + return; } - uint32 version = _stream->readUint32LE(); + uint32 version = installShieldFile.readUint32LE(); if (version != 0x01000004) { warning("Unsupported CAB version %08x", version); - close(); - return false; + return; } - /* uint32 volumeInfo = */ _stream->readUint32LE(); - uint32 cabDescriptorOffset = _stream->readUint32LE(); - /* uint32 cabDescriptorSize = */ _stream->readUint32LE(); + /* uint32 volumeInfo = */ installShieldFile.readUint32LE(); + uint32 cabDescriptorOffset = installShieldFile.readUint32LE(); + /* uint32 cabDescriptorSize = */ installShieldFile.readUint32LE(); - _stream->seek(cabDescriptorOffset); + installShieldFile.seek(cabDescriptorOffset); - _stream->skip(12); - uint32 fileTableOffset = _stream->readUint32LE(); - _stream->skip(4); - uint32 fileTableSize = _stream->readUint32LE(); - uint32 fileTableSize2 = _stream->readUint32LE(); - uint32 directoryCount = _stream->readUint32LE(); - _stream->skip(8); - uint32 fileCount = _stream->readUint32LE(); + installShieldFile.skip(12); + uint32 fileTableOffset = installShieldFile.readUint32LE(); + installShieldFile.skip(4); + uint32 fileTableSize = installShieldFile.readUint32LE(); + uint32 fileTableSize2 = installShieldFile.readUint32LE(); + uint32 directoryCount = installShieldFile.readUint32LE(); + installShieldFile.skip(8); + uint32 fileCount = installShieldFile.readUint32LE(); if (fileTableSize != fileTableSize2) warning("file table sizes do not match"); @@ -106,49 +127,42 @@ bool InstallShieldCabinet::open(const Common::String &filename) { // We're ignoring file groups and components since we // should not need them. Moving on to the files... - _stream->seek(cabDescriptorOffset + fileTableOffset); + installShieldFile.seek(cabDescriptorOffset + fileTableOffset); uint32 fileTableCount = directoryCount + fileCount; uint32 *fileTableOffsets = new uint32[fileTableCount]; for (uint32 i = 0; i < fileTableCount; i++) - fileTableOffsets[i] = _stream->readUint32LE(); + fileTableOffsets[i] = installShieldFile.readUint32LE(); for (uint32 i = directoryCount; i < fileCount + directoryCount; i++) { - _stream->seek(cabDescriptorOffset + fileTableOffset + fileTableOffsets[i]); - uint32 nameOffset = _stream->readUint32LE(); - /* uint32 directoryIndex = */ _stream->readUint32LE(); + installShieldFile.seek(cabDescriptorOffset + fileTableOffset + fileTableOffsets[i]); + uint32 nameOffset = installShieldFile.readUint32LE(); + /* uint32 directoryIndex = */ installShieldFile.readUint32LE(); // First read in data needed by us to get at the file data FileEntry entry; - entry.flags = _stream->readUint16LE(); - entry.uncompressedSize = _stream->readUint32LE(); - entry.compressedSize = _stream->readUint32LE(); - _stream->skip(20); - entry.offset = _stream->readUint32LE(); + entry.flags = installShieldFile.readUint16LE(); + entry.uncompressedSize = installShieldFile.readUint32LE(); + entry.compressedSize = installShieldFile.readUint32LE(); + installShieldFile.skip(20); + entry.offset = installShieldFile.readUint32LE(); // Then let's get the string - _stream->seek(cabDescriptorOffset + fileTableOffset + nameOffset); + installShieldFile.seek(cabDescriptorOffset + fileTableOffset + nameOffset); Common::String fileName; - char c = _stream->readByte(); + char c = installShieldFile.readByte(); while (c) { fileName += c; - c = _stream->readByte(); + c = installShieldFile.readByte(); } - _map[fileName] = entry; } delete[] fileTableOffsets; - - return true; -} - -void InstallShieldCabinet::close() { - delete _stream; _stream = 0; - _map.clear(); } bool InstallShieldCabinet::hasFile(const Common::String &name) { + warning("hasFile: Filename %s", name.c_str()); return _map.contains(name); } @@ -164,23 +178,25 @@ Common::ArchiveMemberPtr InstallShieldCabinet::getMember(const Common::String &n } Common::SeekableReadStream *InstallShieldCabinet::createReadStreamForMember(const Common::String &name) const { - if (!_stream || !_map.contains(name)) + if (!_map.contains(name)) return 0; const FileEntry &entry = _map[name]; - _stream->seek(entry.offset); + Common::File archiveFile; + archiveFile.open(_installShieldFilename); + archiveFile.seek(entry.offset); if (!(entry.flags & 0x04)) { // Not compressed - return _stream->readStream(entry.uncompressedSize); + return archiveFile.readStream(entry.uncompressedSize); } #ifdef USE_ZLIB byte *src = (byte *)malloc(entry.compressedSize); byte *dst = (byte *)malloc(entry.uncompressedSize); - _stream->read(src, entry.compressedSize); + archiveFile.read(src, entry.compressedSize); bool result = Common::inflateZlibHeaderless(dst, entry.uncompressedSize, src, entry.compressedSize); free(src); @@ -198,4 +214,8 @@ Common::SeekableReadStream *InstallShieldCabinet::createReadStreamForMember(cons #endif } +Common::Archive *makeInstallShieldArchive(const Common::String &name) { + return new InstallShieldCabinet(name); +} + } // End of namespace AGOS |