Initial commit

This commit is contained in:
2026-02-02 04:50:13 +01:00
commit 5b11698731
22592 changed files with 7677434 additions and 0 deletions

View File

@@ -0,0 +1,134 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "engines/grim/update/lang_filter.h"
#include "common/file.h"
#include "common/archive.h"
#include "common/str.h"
namespace Grim {
const char *LangFilter::kLanguages1[7] = { "@@_", "US_", "FR_", "GE_", "IT_", "PT_", "SP_" };
const char *LangFilter::kLanguages2[7] = { "Common/", "Eng/", "Fra/", "Deu/", "Ita/", "Brz/", "Esp/" };
LangFilter::LangFilter(Common::Archive *arc, Common::Language lang) : _arc(arc) {
if (!_arc)
return;
switch (lang) {
case Common::EN_ANY:
case Common::EN_GRB:
case Common::EN_USA:
_lang = kEnglish;
break;
case Common::FR_FRA:
_lang = kFrench;
break;
case Common::DE_DEU:
_lang = kGerman;
break;
case Common::IT_ITA:
_lang = kItalian;
break;
case Common::PT_BRA:
_lang = kPortuguese;
break;
case Common::ES_ESP:
_lang = kSpanish;
break;
default:
_lang = kCommon;
break;
}
}
bool LangFilter::hasFile(const Common::Path &path) const {
if (!_arc)
return false;
return (_arc->hasFile(Common::Path(kLanguages1[_lang]).appendInPlace(path))) ||
(_arc->hasFile(Common::Path(kLanguages1[kCommon]).appendInPlace(path))) ||
(_arc->hasFile(Common::Path(kLanguages2[_lang]).appendInPlace(path))) ||
(_arc->hasFile(Common::Path(kLanguages2[kCommon]).appendInPlace(path)));
}
int LangFilter::listMembers(Common::ArchiveMemberList &list) const {
if (!_arc)
return false;
Common::ArchiveMemberList orgList;
Common::String orgName, name;
_arc->listMembers(orgList);
int num = 0;
// Search only files with the right language and create a list with their basenames
for (Common::ArchiveMemberList::const_iterator it = orgList.begin(); it != orgList.end(); ++it) {
orgName = (*it)->getName();
if (orgName.hasPrefix(kLanguages1[_lang]) || orgName.hasPrefix(kLanguages1[kCommon]))
name = Common::String(orgName.c_str() + 3);
else if (orgName.hasPrefix(kLanguages2[_lang]) || orgName.hasPrefix(kLanguages2[kCommon])) {
int i = 0;
while (orgName[i++] != '/') {;}
name = Common::String(orgName.c_str() + i);
// If the file is a subfolder, reject it
if (name.contains('/'))
continue;
} else
continue;
name.toLowercase();
list.push_back(getMember(Common::Path(name)));
++num;
}
return num;
}
const Common::ArchiveMemberPtr LangFilter::getMember(const Common::Path &path) const {
return Common::ArchiveMemberPtr(new Common::GenericArchiveMember(path, *this));
}
Common::SeekableReadStream *LangFilter::createReadStreamForMember(const Common::Path &path) const {
if (!_arc)
return nullptr;
// Search the right file
Common::Path fullName;
Common::List<Common::Path> pathsToTry;
pathsToTry.push_front(Common::Path(kLanguages1[_lang]).appendInPlace(path));
pathsToTry.push_front(Common::Path(kLanguages1[kCommon]).appendInPlace(path));
pathsToTry.push_front(Common::Path(kLanguages2[_lang]).appendInPlace(path));
pathsToTry.push_front(Common::Path(kLanguages2[kCommon]).appendInPlace(path));
for (Common::List<Common::Path>::const_iterator it = pathsToTry.begin(); it != pathsToTry.end(); ++it)
if (_arc->hasFile(*it)) {
fullName = *it;
break;
}
if (fullName.empty())
return nullptr;
return _arc->createReadStreamForMember(fullName);
}
} // End of namespace Grim

View File

@@ -0,0 +1,62 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef LANGFILTER_H
#define LANGFILTER_H
#include "common/archive.h"
#include "common/language.h"
namespace Grim {
class LangFilter : public Common::Archive {
public:
LangFilter(Common::Archive *arc, Common::Language lang);
~LangFilter() {
delete _arc;
}
// Common::Archive API implementation
bool hasFile(const Common::Path &path) const override;
int listMembers(Common::ArchiveMemberList &list) const override;
const Common::ArchiveMemberPtr getMember(const Common::Path &path) const override;
Common::SeekableReadStream *createReadStreamForMember(const Common::Path &path) const override;
private:
Common::Archive *_arc;
enum kLang {
kCommon = 0,
kEnglish,
kFrench,
kGerman,
kItalian,
kPortuguese,
kSpanish
};
kLang _lang;
static const char *kLanguages1[7];
static const char *kLanguages2[7];
};
} // end of namespace Grim
#endif

View File

@@ -0,0 +1,297 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "engines/grim/update/mscab.h"
#include "common/file.h"
#include "common/archive.h"
#include "common/memstream.h"
#include "common/compression/deflate.h"
#include "common/str.h"
namespace Grim {
MsCabinet::~MsCabinet() {
for (CacheMap::iterator it = _cache.begin(); it != _cache.end(); it++)
delete[] it->_value;
_folderMap.clear();
_fileMap.clear();
delete _data;
delete _decompressor;
}
MsCabinet::MsCabinet(Common::SeekableReadStream *data) :
_data(data), _decompressor(nullptr) {
if (!_data)
return;
// CFHEADER PARSING
// Verify Head-signature
uint32 tag = _data->readUint32BE();
if (tag != MKTAG('M','S','C','F'))
return;
/* uint32 reserved1 = */ _data->readUint32LE();
uint32 length = _data->readUint32LE();
if (length > uint32(_data->size()))
return;
/* uint32 reserved2 = */ _data->readUint32LE();
uint32 filesOffset = _data->readUint32LE();
/* uint32 reserved3 = */ _data->readUint32LE();
byte versionMinor = _data->readByte();
byte versionMajor = _data->readByte();
if (versionMajor != 1 || versionMinor != 3)
return;
uint16 numFolders = _data->readUint16LE();
uint16 numFiles = _data->readUint16LE();
if (numFolders == 0 || numFiles == 0)
return;
// This implementation doesn't support multicabinet and reserved fields
uint16 flags = _data->readUint16LE();
if (flags != 0)
return;
/* uint16 setId = */ _data->readUint16LE();
/* uint16 iCab = */ _data->readUint16LE();
if (_data->err())
return;
//CFFOLDERs PARSING
for (uint16 i = 0; i < numFolders; ++i) {
FolderEntry fEntry;
fEntry.offset = _data->readUint32LE();
fEntry.num_blocks = _data->readUint16LE();
fEntry.comp_type = _data->readUint16LE();
if (_data->err())
return;
_folderMap[i] = fEntry;
}
// CFFILEs PARSING
_data->seek(filesOffset);
if (_data->err())
return;
for (uint16 i = 0; i < numFiles; ++i) {
FileEntry fEntry;
fEntry.length = _data->readUint32LE();
fEntry.folderOffset = _data->readUint32LE();
uint16 iFolder = _data->readUint16LE();
/* uint16 date = */ _data->readUint16LE();
/* uint16 time = */ _data->readUint16LE();
/* uint16 attribs = */ _data->readUint16LE();
Common::String name = readString(_data);
for (uint l = 0; l < name.size(); ++l)
if (name[l] == '\\')
name.setChar('/', l);
if (_data->err()) {
_fileMap.clear();
return;
}
if (_folderMap.contains(iFolder))
fEntry.folder = &_folderMap[iFolder];
else {
_fileMap.clear();
return;
}
_fileMap[Common::Path(name, '/')] = fEntry;
}
}
/* read a null-terminated string from a stream
Copied from ScummVm MohawkEngine_LivingBooks.*/
Common::String MsCabinet::readString(Common::ReadStream *stream) {
Common::String ret;
while (!stream->eos()) {
byte in = stream->readByte();
if (!in)
break;
ret += in;
}
return ret;
}
bool MsCabinet::hasFile(const Common::Path &path) const {
return _fileMap.contains(path);
}
int MsCabinet::listMembers(Common::ArchiveMemberList &list) const {
for (FileMap::const_iterator it = _fileMap.begin(); it != _fileMap.end(); it++)
list.push_back(getMember(it->_key));
return _fileMap.size();
}
const Common::ArchiveMemberPtr MsCabinet::getMember(const Common::Path &path) const {
return Common::ArchiveMemberPtr(new Common::GenericArchiveMember(path, *this));
}
Common::SeekableReadStream *MsCabinet::createReadStreamForMember(const Common::Path &path) const {
byte *fileBuf;
if (!hasFile(path))
return nullptr;
const FileEntry &entry = _fileMap[path];
// Check if the file has already been decompressed and it's in the cache,
// otherwise decompress it and put it in the cache
if (_cache.contains(path))
fileBuf = _cache[path];
else {
// Check if the decompressor should be reinitialized
if (!_decompressor || entry.folder != _decompressor->getFolder()) {
delete _decompressor;
_decompressor = new Decompressor(entry.folder, _data);
}
if (!_decompressor->decompressFile(fileBuf, entry))
return nullptr;
_cache[path] = fileBuf;
}
return new Common::MemoryReadStream(fileBuf, entry.length, DisposeAfterUse::NO);
}
MsCabinet::Decompressor::Decompressor(const MsCabinet::FolderEntry *folder, Common::SeekableReadStream *data) :
_curFolder(folder), _data(data), _curBlock(-1), _compressedBlock(nullptr), _decompressedBlock(nullptr), _fileBuf(nullptr),
_inBlockEnd(0), _inBlockStart(0), _endBlock(0), _startBlock(0) {
// Alloc the decompression buffers
_compressedBlock = new byte[kCabInputmax];
_decompressedBlock = new byte[kCabBlockSize];
}
MsCabinet::Decompressor::~Decompressor() {
delete[] _decompressedBlock;
delete[] _compressedBlock;
delete[] _fileBuf;
}
bool MsCabinet::Decompressor::decompressFile(byte *&fileBuf, const FileEntry &entry) {
// Ref: https://web.archive.org/web/20220518002805/http://blogs.kde.org/node/3181
uint16 uncompressedLen, compressedLen;
byte hdrS[4];
byte *buf_tmp, *dict;
bool decRes;
// Sanity checks
if (!_compressedBlock || entry.folder != _curFolder)
return false;
_startBlock = entry.folderOffset / kCabBlockSize;
_inBlockStart = entry.folderOffset % kCabBlockSize;
_endBlock = (entry.folderOffset + entry.length) / kCabBlockSize;
_inBlockEnd = (entry.folderOffset + entry.length) % kCabBlockSize;
// Check if the decompressor should be reinitialized
if (_curBlock > _startBlock || _curBlock == -1) {
_data->seek(entry.folder->offset);
// Check the compression method (only mszip supported)
if (entry.folder->comp_type != kMszipCompression)
return false;
_curBlock = -1; // No block decompressed
}
// Check if the file is contained in the folder
if ((entry.length + entry.folderOffset) / kCabBlockSize > entry.folder->num_blocks)
return false;
_fileBuf = new byte[entry.length];
buf_tmp = _fileBuf;
// If a part of this file has been decompressed in the last block, make a copy of it
copyBlock(buf_tmp);
while ((_curBlock + 1) <= _endBlock) {
// Read the CFDATA header
_data->readUint32LE(); // checksum
_data->read(hdrS, 4);
compressedLen = READ_LE_UINT16(hdrS);
uncompressedLen = READ_LE_UINT16(hdrS + 2);
if (_data->err())
return false;
if (compressedLen > kCabInputmax || uncompressedLen > kCabBlockSize)
return false;
// Read the compressed block
if (_data->read(_compressedBlock, compressedLen) != compressedLen)
return false;
// Check the CK header
if (_compressedBlock[0] != 'C' || _compressedBlock[1] != 'K')
return false;
// Decompress the block. If it isn't the first, provide the previous block as dictonary
dict = (_curBlock >= 0) ? _decompressedBlock : nullptr;
decRes = Common::inflateZlibHeaderless(_decompressedBlock, uncompressedLen, _compressedBlock + 2, compressedLen - 2, dict, kCabBlockSize);
if (!decRes)
return false;
_curBlock++;
// Copy the decompressed data, if needed
copyBlock(buf_tmp);
}
fileBuf = _fileBuf;
_fileBuf = nullptr;
return true;
}
void MsCabinet::Decompressor::copyBlock(byte *&data_ptr) const {
uint16 start, end, size;
if (_startBlock <= _curBlock && _curBlock <= _endBlock) {
start = (_startBlock == _curBlock) ? _inBlockStart : 0;
end = (_endBlock == _curBlock) ? _inBlockEnd : uint16(kCabBlockSize);
size = end - start;
memcpy(data_ptr, _decompressedBlock + start, size);
data_ptr += size;
}
}
} // End of namespace Grim

103
engines/grim/update/mscab.h Normal file
View File

@@ -0,0 +1,103 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef MSCAB_H
#define MSCAB_H
#include "common/hashmap.h"
#include "common/hash-str.h"
#include "common/stream.h"
#include "common/archive.h"
#include "common/str.h"
#include "common/util.h"
namespace Grim {
class MsCabinet : public Common::Archive {
public:
MsCabinet(Common::SeekableReadStream *data);
~MsCabinet();
// Common::Archive API implementation
bool hasFile(const Common::Path &path) const override;
int listMembers(Common::ArchiveMemberList &list) const override;
const Common::ArchiveMemberPtr getMember(const Common::Path &path) const override;
Common::SeekableReadStream *createReadStreamForMember(const Common::Path &path) const override;
private:
Common::SeekableReadStream *_data;
struct FolderEntry {
uint16 comp_type; // The compression type
uint16 num_blocks; // The total number of data blocks used by this folder
uint32 offset; // The cabinet offset of first datablock
};
struct FileEntry {
uint32 length; // Uncompressed size of the file in bytes
FolderEntry *folder; // Folder holding this file
uint32 folderOffset; // Uncompressed offset in the folder
};
typedef Common::HashMap<Common::Path, FileEntry, Common::Path::IgnoreCase_Hash, Common::Path::IgnoreCase_EqualTo> FileMap;
FileMap _fileMap;
typedef Common::HashMap<uint16, FolderEntry> FolderMap;
FolderMap _folderMap;
Common::String readString(Common::ReadStream *stream);
// Decompressor
class Decompressor {
public:
Decompressor(const FolderEntry *folder, Common::SeekableReadStream *_data);
~Decompressor();
bool decompressFile(byte *&fileBuf, const FileEntry &entry);
const FolderEntry *getFolder() const {
return _curFolder;
}
private:
Common::SeekableReadStream *_data;
const FolderEntry *_curFolder;
int16 _curBlock;
byte *_compressedBlock, *_decompressedBlock;
byte *_fileBuf;
uint16 _startBlock, _inBlockStart, _endBlock, _inBlockEnd;
void copyBlock(byte *&data_ptr) const;
enum {
kMszipCompression = 1,
kCabBlockSize = 0x8000,
kCabInputmax = kCabBlockSize + 12
};
};
mutable Decompressor *_decompressor;
// Cache
typedef Common::HashMap<Common::Path, byte *, Common::Path::IgnoreCase_Hash, Common::Path::IgnoreCase_EqualTo> CacheMap;
mutable CacheMap _cache;
};
} // End of namespace Grim
#endif

View File

@@ -0,0 +1,133 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/endian.h"
#include "common/stream.h"
#include "engines/grim/update/packfile.h"
namespace Grim {
const uint32 PackFile::_knownOffsets[] = { 0x1c000, 0x21000, 0x23000, 0x24000, 0 };
PackFile::PackFile(Common::SeekableReadStream *data):
_codeTable(nullptr), _orgStream(data), _offset(0), _kCodeTableSize(0x100) {
uint32 magicContainer, magicCabinet, key;
for (int i = 0; _knownOffsets[i] != 0; ++i) {
if (_knownOffsets[i] > uint32(_orgStream->size()))
continue;
_orgStream->seek(_knownOffsets[i]);
// Check for content signature
magicContainer = _orgStream->readUint32BE();
if (!err() && magicContainer == MKTAG('1','C','N','T')) {
key = _orgStream->readUint32LE();
createCodeTable(key);
_offset = _orgStream->pos();
// Check for cabinet signature
magicCabinet = readUint32BE();
if (!err() && magicCabinet == MKTAG('M','S','C','F'))
break;
else {
delete[] _codeTable;
_codeTable = nullptr;
_offset = 0;
continue;
}
}
}
_size = _orgStream->size() - _offset;
_orgStream->seek(_offset);
}
PackFile::~PackFile() {
delete[] _codeTable;
delete _orgStream;
}
bool PackFile::err() const {
return _orgStream->err();
}
void PackFile::clearErr() {
_orgStream->clearErr();
}
void PackFile::createCodeTable(uint32 key) {
const uint32 kRandA = 0x343FD;
const uint32 kRandB = 0x269EC3;
uint32 value = key;
delete[] _codeTable;
_codeTable = new uint16[_kCodeTableSize * 2];
for (uint i = 0; i < _kCodeTableSize; i++) {
value = kRandA * value + kRandB;
_codeTable[i] = uint16((value >> 16) & 0x7FFF);
}
}
void PackFile::decode(uint8 *data, uint32 dataSize, uint32 start_point) {
for (uint32 i = 0; i < dataSize; i++) {
data[i] ^= uint8(_codeTable[(i + start_point) % _kCodeTableSize]);
data[i] -= uint8(_codeTable[(i + start_point) % _kCodeTableSize] >> 8);
}
}
uint32 PackFile::read(void *dataPtr, uint32 dataSize) {
uint32 start_point, count;
start_point = uint32(pos());
count = _orgStream->read(dataPtr, dataSize);
if (err() || count != dataSize)
return 0;
if (_codeTable)
decode((uint8*)dataPtr, count, start_point);
return count;
}
bool PackFile::eos() const {
return _orgStream->eos();
}
int64 PackFile::pos() const {
return _orgStream->pos() - _offset;
}
int64 PackFile::size() const {
return _size;
}
bool PackFile::seek(int64 offset, int whence) {
if (_codeTable && whence == SEEK_SET)
offset += _offset;
return _orgStream->seek(offset, whence);
}
} // end of namespace Grim

View File

@@ -0,0 +1,59 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PACKFILE_H
#define PACKFILE_H
namespace Common {
class SeekableReadStream;
}
namespace Grim {
class PackFile : public Common::SeekableReadStream {
public:
PackFile(Common::SeekableReadStream *data);
~PackFile();
bool err() const;
void clearErr();
uint32 read(void *dataPtr, uint32 dataSize);
bool eos() const;
int64 pos() const;
int64 size() const;
bool seek(int64 offset, int whence = SEEK_SET);
private:
Common::SeekableReadStream *_orgStream;
int32 _offset, _size;
uint16 *_codeTable;
const uint32 _kCodeTableSize;
void createCodeTable(uint32 key);
void decode(uint8 *data, uint32 size, uint32 start_point);
static const uint32 _knownOffsets[5];
};
} // end of namespace Grim
#endif

View File

@@ -0,0 +1,46 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/stream.h"
#include "engines/grim/update/packfile.h"
#include "engines/grim/update/mscab.h"
#include "engines/grim/update/lang_filter.h"
#include "engines/grim/update/update.h"
#include "engines/grim/grim.h"
namespace Grim {
Common::Archive *loadUpdateArchive(Common::SeekableReadStream *data) {
Common::SeekableReadStream *updStream = new PackFile(data);
MsCabinet *cab = new MsCabinet(updStream);
LangFilter *update = new LangFilter(cab, g_grim->getGameLanguage());
Common::ArchiveMemberList list;
if (update->listMembers(list) == 0) {
delete update;
return nullptr;
} else
return update;
}
} // end of namespace Grim

View File

@@ -0,0 +1,40 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef UPDATE_H
#define UPDATE_H
namespace Common {
class Archive;
class SeekableReadStream;
}
namespace Grim {
/**
* This method creates an Archive instance corresponding to the content
* of a GF or EMI update executable, with the current game language.
*/
Common::Archive *loadUpdateArchive(Common::SeekableReadStream *data);
} // end of namespace Grim
#endif