Initial commit
This commit is contained in:
795
engines/gob/resources.cpp
Normal file
795
engines/gob/resources.cpp
Normal file
@@ -0,0 +1,795 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*
|
||||
* This file is dual-licensed.
|
||||
* In addition to the GPLv3 license mentioned above, this code is also
|
||||
* licensed under LGPL 2.1. See LICENSES/COPYING.LGPL file for the
|
||||
* full text of the license.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/util.h"
|
||||
#include "common/endian.h"
|
||||
#include "common/memstream.h"
|
||||
|
||||
#include "gob/gob.h"
|
||||
#include "gob/resources.h"
|
||||
#include "gob/totfile.h"
|
||||
#include "gob/dataio.h"
|
||||
#include "gob/game.h"
|
||||
#include "gob/global.h"
|
||||
|
||||
namespace Gob {
|
||||
|
||||
Resource::Resource(byte *data, int32 size, bool needFree,
|
||||
int16 width, int16 height) {
|
||||
|
||||
_data = data;
|
||||
_size = size;
|
||||
_width = width;
|
||||
_height = height;
|
||||
_needFree = needFree;
|
||||
|
||||
_stream = new Common::MemoryReadStream(data, size);
|
||||
}
|
||||
|
||||
Resource::~Resource() {
|
||||
delete _stream;
|
||||
|
||||
if (_needFree)
|
||||
delete[] _data;
|
||||
}
|
||||
|
||||
byte *Resource::getData() const {
|
||||
return _data;
|
||||
}
|
||||
|
||||
int32 Resource::getSize() const {
|
||||
return _size;
|
||||
}
|
||||
|
||||
int16 Resource::getWidth() const {
|
||||
return _width;
|
||||
}
|
||||
|
||||
int16 Resource::getHeight() const {
|
||||
return _height;
|
||||
}
|
||||
|
||||
Common::SeekableReadStream *Resource::stream() const {
|
||||
return _stream;
|
||||
}
|
||||
|
||||
|
||||
TextItem::TextItem(byte *data, int32 size) {
|
||||
_data = data;
|
||||
_size = size;
|
||||
|
||||
_stream = new Common::MemoryReadStream(data, size);
|
||||
}
|
||||
|
||||
TextItem::~TextItem() {
|
||||
delete _stream;
|
||||
}
|
||||
|
||||
byte *TextItem::getData() const {
|
||||
return _data;
|
||||
}
|
||||
|
||||
int32 TextItem::getSize() const {
|
||||
return _size;
|
||||
}
|
||||
|
||||
Common::SeekableReadStream *TextItem::stream() const {
|
||||
return _stream;
|
||||
}
|
||||
|
||||
|
||||
Resources::TOTResourceTable::TOTResourceTable() {
|
||||
itemsCount = 0;
|
||||
unknown = (byte)0;
|
||||
items = nullptr;
|
||||
dataOffset = 0u;
|
||||
}
|
||||
|
||||
Resources::TOTResourceTable::~TOTResourceTable() {
|
||||
delete[] items;
|
||||
}
|
||||
|
||||
|
||||
Resources::EXTResourceTable::EXTResourceTable() {
|
||||
itemsCount = 0;
|
||||
unknown = 0;
|
||||
items = nullptr;
|
||||
}
|
||||
|
||||
Resources::EXTResourceTable::~EXTResourceTable() {
|
||||
delete[] items;
|
||||
}
|
||||
|
||||
|
||||
Resources::TOTTextTable::TOTTextTable() {
|
||||
needFree = false;
|
||||
itemsCount = 0;
|
||||
data = nullptr;
|
||||
size = 0;
|
||||
items = nullptr;
|
||||
}
|
||||
|
||||
Resources::TOTTextTable::~TOTTextTable() {
|
||||
delete[] items;
|
||||
if (needFree)
|
||||
delete[] data;
|
||||
}
|
||||
|
||||
|
||||
Resources::Resources(GobEngine *vm) : _vm(vm) {
|
||||
unload(false);
|
||||
}
|
||||
|
||||
Resources::~Resources() {
|
||||
unload();
|
||||
}
|
||||
|
||||
bool Resources::load(const Common::String &fileName) {
|
||||
unload();
|
||||
|
||||
_totFile = TOTFile::createFileName(fileName, _hasLOM);
|
||||
|
||||
if (_hasLOM) {
|
||||
warning("Stub: Resources::load(%s)", fileName.c_str());
|
||||
unload();
|
||||
return false;
|
||||
}
|
||||
|
||||
_fileBase = TOTFile::getFileBase(fileName);
|
||||
|
||||
_extFile = _fileBase + ".ext";
|
||||
|
||||
bool hasTOTRes = loadTOTResourceTable();
|
||||
bool hasEXTRes = loadEXTResourceTable();
|
||||
|
||||
if (!hasTOTRes) {
|
||||
delete _totResourceTable;
|
||||
_totResourceTable = nullptr;
|
||||
}
|
||||
|
||||
if (!hasEXTRes) {
|
||||
delete _extResourceTable;
|
||||
_extResourceTable = nullptr;
|
||||
}
|
||||
|
||||
if (!hasTOTRes && !hasEXTRes) {
|
||||
if (_vm->getGameType() == kGameTypeAdibou2 || _vm->getGameType() == kGameTypeAdi4)
|
||||
return true; // Some "library" TOT files used in Adibou2 have no embed resources, nor external ones.
|
||||
else
|
||||
return false;
|
||||
};
|
||||
|
||||
if (!loadTOTTextTable(_fileBase)) {
|
||||
unload();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (hasTOTRes) {
|
||||
if (!loadIMFile()) {
|
||||
unload();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasEXTRes) {
|
||||
if (!loadEXFile()) {
|
||||
unload();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Resources::unload(bool del) {
|
||||
if (del) {
|
||||
delete _totResourceTable;
|
||||
delete _extResourceTable;
|
||||
delete _totTextTable;
|
||||
|
||||
delete[] _totData;
|
||||
delete[] _imData;
|
||||
|
||||
_fileBase.clear();
|
||||
_totFile.clear();
|
||||
_extFile.clear();
|
||||
_exFile.clear();
|
||||
}
|
||||
|
||||
_totResourceTable = nullptr;
|
||||
_extResourceTable = nullptr;
|
||||
_totTextTable = nullptr;
|
||||
_totResStart = 0;
|
||||
_totData = nullptr;
|
||||
_totSize = 0;
|
||||
_imData = nullptr;
|
||||
_imSize = 0;
|
||||
}
|
||||
|
||||
bool Resources::isLoaded() const {
|
||||
return (_totResourceTable != nullptr);
|
||||
}
|
||||
|
||||
bool Resources::loadTOTResourceTable() {
|
||||
TOTFile totFile(_vm);
|
||||
|
||||
if (!totFile.load(_totFile))
|
||||
return false;
|
||||
|
||||
TOTFile::Properties totProps;
|
||||
if (!totFile.getProperties(totProps))
|
||||
return false;
|
||||
|
||||
Common::SeekableReadStream *stream = totFile.getStream();
|
||||
if (!stream)
|
||||
return false;
|
||||
|
||||
_totResStart = totProps.scriptEnd;
|
||||
|
||||
if (totProps.resourcesOffset != 0xFFFFFFFF && totProps.resourcesOffset != 0) {
|
||||
_totResourceTable = new TOTResourceTable;
|
||||
|
||||
stream->seek(totProps.resourcesOffset);
|
||||
_totResourceTable->itemsCount = stream->readSint16LE();
|
||||
|
||||
uint32 resSize = _totResourceTable->itemsCount * kTOTResItemSize +
|
||||
kTOTResTableSize;
|
||||
|
||||
_totResourceTable->dataOffset = totProps.resourcesOffset + resSize;
|
||||
|
||||
|
||||
// Would the table actually fit into the TOT?
|
||||
if ((totProps.resourcesOffset + resSize) > ((uint32) stream->size()))
|
||||
return false;
|
||||
|
||||
_totResourceTable->unknown = stream->readByte();
|
||||
_totResourceTable->items = new TOTResourceItem[_totResourceTable->itemsCount];
|
||||
|
||||
for (int i = 0; i < _totResourceTable->itemsCount; ++i) {
|
||||
TOTResourceItem &item = _totResourceTable->items[i];
|
||||
|
||||
item.offset = stream->readSint32LE();
|
||||
item.size = stream->readUint16LE();
|
||||
item.width = stream->readSint16LE();
|
||||
item.height = stream->readSint16LE();
|
||||
|
||||
if (item.offset < 0) {
|
||||
item.type = kResourceIM;
|
||||
item.index = -item.offset - 1;
|
||||
} else
|
||||
item.type = kResourceTOT;
|
||||
}
|
||||
} else {
|
||||
_totResourceTable = nullptr;
|
||||
// Do not return yet: although there is no *sprite* resource table,
|
||||
// a text table may still be present.
|
||||
}
|
||||
|
||||
_totSize = stream->size() - _totResStart;
|
||||
|
||||
if (_totSize <= 0)
|
||||
return false;
|
||||
|
||||
if (!stream->seek(totProps.scriptEnd))
|
||||
return false;
|
||||
|
||||
_totData = new byte[_totSize];
|
||||
if (stream->read(_totData, _totSize) != _totSize)
|
||||
return false;
|
||||
|
||||
return !stream->err();
|
||||
}
|
||||
|
||||
bool Resources::loadEXTResourceTable() {
|
||||
_extResourceTable = new EXTResourceTable;
|
||||
|
||||
Common::SeekableReadStream *stream = _vm->_dataIO->getFile(_extFile);
|
||||
if (!stream)
|
||||
return false;
|
||||
|
||||
_extResourceTable->itemsCount = stream->readSint16LE();
|
||||
_extResourceTable->unknown = stream->readByte();
|
||||
|
||||
if (_extResourceTable->itemsCount > 0)
|
||||
_extResourceTable->items = new EXTResourceItem[_extResourceTable->itemsCount];
|
||||
|
||||
for (int i = 0; i < _extResourceTable->itemsCount; i++) {
|
||||
EXTResourceItem &item = _extResourceTable->items[i];
|
||||
|
||||
item.offset = stream->readUint32LE();
|
||||
item.size = stream->readUint16LE();
|
||||
item.width = stream->readUint16LE();
|
||||
item.height = stream->readUint16LE();
|
||||
|
||||
if (item.offset < 0) {
|
||||
item.type = kResourceEX;
|
||||
item.offset = -item.offset - 1;
|
||||
} else {
|
||||
item.type = kResourceEXT;
|
||||
item.offset += kEXTResTableSize +
|
||||
kEXTResItemSize * _extResourceTable->itemsCount;
|
||||
}
|
||||
|
||||
item.packed = (item.width & 0x8000) != 0;
|
||||
|
||||
item.width &= 0x7FFF;
|
||||
}
|
||||
|
||||
delete stream;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Resources::loadTOTTextTable(const Common::String &fileBase) {
|
||||
TOTFile totFile(_vm);
|
||||
|
||||
if (!totFile.load(_totFile))
|
||||
return false;
|
||||
|
||||
TOTFile::Properties totProps;
|
||||
if (!totFile.getProperties(totProps))
|
||||
return false;
|
||||
|
||||
Common::SeekableReadStream *stream = totFile.getStream();
|
||||
if (!stream)
|
||||
return false;
|
||||
|
||||
if (totProps.textsOffset == ((uint32) -1))
|
||||
// No texts
|
||||
return true;
|
||||
|
||||
_totTextTable = new TOTTextTable;
|
||||
|
||||
if (totProps.textsOffset == 0) {
|
||||
_totTextTable->data = loadTOTLocTexts(fileBase, _totTextTable->size);
|
||||
_totTextTable->needFree = true;
|
||||
} else {
|
||||
_totTextTable->data = _totData + totProps.textsOffset - _totResStart;
|
||||
_totTextTable->needFree = false;
|
||||
_totTextTable->size = totProps.textsSize;
|
||||
}
|
||||
|
||||
if (_totTextTable->data) {
|
||||
Common::MemoryReadStream totTextTable(_totTextTable->data, _totTextTable->size);
|
||||
_totTextTable->itemsCount = totTextTable.readSint16LE() & 0x3FFF;
|
||||
|
||||
_totTextTable->items = new TOTTextItem[_totTextTable->itemsCount];
|
||||
for (int i = 0; i < _totTextTable->itemsCount; ++i) {
|
||||
TOTTextItem &item = _totTextTable->items[i];
|
||||
|
||||
item.offset = totTextTable.readSint16LE();
|
||||
item.size = totTextTable.readSint16LE();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Resources::loadIMFile() {
|
||||
TOTFile totFile(_vm);
|
||||
|
||||
if (!totFile.load(_totFile))
|
||||
return false;
|
||||
|
||||
TOTFile::Properties totProps;
|
||||
if (!totFile.getProperties(totProps))
|
||||
return false;
|
||||
|
||||
if ((totProps.communHandling != 0) && (totProps.imFileNumber == 0))
|
||||
// No IM file
|
||||
return true;
|
||||
|
||||
Common::String imFile = "commun.im";
|
||||
|
||||
char num = totProps.imFileNumber + '0';
|
||||
if (num == '0')
|
||||
num = '1';
|
||||
|
||||
imFile += num;
|
||||
|
||||
Common::SeekableReadStream *stream = _vm->_dataIO->getFile(imFile);
|
||||
if (!stream)
|
||||
return true;
|
||||
|
||||
_imSize = stream->size();
|
||||
if (_imSize <= 0) {
|
||||
_imSize = 0;
|
||||
delete stream;
|
||||
return true;
|
||||
}
|
||||
|
||||
_imData = new byte[_imSize];
|
||||
if (stream->read(_imData, _imSize) != _imSize) {
|
||||
delete[] _imData;
|
||||
_imData = nullptr;
|
||||
_imSize = 0;
|
||||
}
|
||||
|
||||
delete stream;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Resources::loadEXFile() {
|
||||
TOTFile totFile(_vm);
|
||||
|
||||
if (!totFile.load(_totFile))
|
||||
return false;
|
||||
|
||||
TOTFile::Properties totProps;
|
||||
if (!totFile.getProperties(totProps))
|
||||
return false;
|
||||
|
||||
_exFile = "commun.ex";
|
||||
_exFile += totProps.exFileNumber + '0';
|
||||
|
||||
if (!_vm->_dataIO->hasFile(_exFile)) {
|
||||
_exFile.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Common::String Resources::getLocTextFile(const Common::String &fileBase,
|
||||
int language) {
|
||||
|
||||
Common::String locTextFile = fileBase + ".";
|
||||
switch (language) {
|
||||
case kLanguageFrench:
|
||||
locTextFile += "dat";
|
||||
break;
|
||||
case kLanguageGerman:
|
||||
locTextFile += "all";
|
||||
break;
|
||||
case kLanguageSpanish:
|
||||
locTextFile += "esp";
|
||||
break;
|
||||
case kLanguageItalian:
|
||||
locTextFile += "ita";
|
||||
break;
|
||||
case kLanguageAmerican:
|
||||
locTextFile += "usa";
|
||||
break;
|
||||
case kLanguageDutch:
|
||||
locTextFile += "ndl";
|
||||
break;
|
||||
case kLanguageKorean:
|
||||
locTextFile += "kor";
|
||||
break;
|
||||
case kLanguageHebrew:
|
||||
locTextFile += "isr";
|
||||
break;
|
||||
default:
|
||||
locTextFile += "ang";
|
||||
break;
|
||||
}
|
||||
|
||||
if (!_vm->_dataIO->hasFile(locTextFile))
|
||||
locTextFile.clear();
|
||||
|
||||
return locTextFile;
|
||||
}
|
||||
|
||||
byte *Resources::loadTOTLocTexts(const Common::String &fileBase, int32 &size) {
|
||||
Common::String locTextFile;
|
||||
|
||||
locTextFile = getLocTextFile(fileBase, _vm->_global->_languageWanted);
|
||||
|
||||
if (!locTextFile.empty()) {
|
||||
|
||||
_vm->_global->_foundLanguage = true;
|
||||
_vm->_global->_language = _vm->_global->_languageWanted;
|
||||
|
||||
} else if (!_vm->_global->_foundLanguage) {
|
||||
|
||||
// Trying US for GB and vice versa
|
||||
if (_vm->_global->_languageWanted == kLanguageBritish) {
|
||||
|
||||
locTextFile = getLocTextFile(fileBase, kLanguageAmerican);
|
||||
if (!locTextFile.empty())
|
||||
_vm->_global->_language = kLanguageAmerican;
|
||||
|
||||
} else if (_vm->_global->_languageWanted == kLanguageAmerican) {
|
||||
|
||||
locTextFile = getLocTextFile(fileBase, kLanguageBritish);
|
||||
if (!locTextFile.empty())
|
||||
_vm->_global->_language = kLanguageBritish;
|
||||
|
||||
}
|
||||
|
||||
// The .ALL suffix, normally for German, is also used for Italian in Adibou2
|
||||
if (_vm->getGameType() == kGameTypeAdibou2 || _vm->getGameType() == kGameTypeAdi4) {
|
||||
if (_vm->_global->_languageWanted == kLanguageItalian) {
|
||||
locTextFile = getLocTextFile(fileBase, kLanguageGerman);
|
||||
if (!locTextFile.empty())
|
||||
_vm->_global->_language = kLanguageItalian;
|
||||
}
|
||||
}
|
||||
|
||||
if (locTextFile.empty()) {
|
||||
// Looking for the first existing language
|
||||
for (int i = 0; i < 10; i++) {
|
||||
locTextFile = getLocTextFile(fileBase, i);
|
||||
if (!locTextFile.empty()) {
|
||||
_vm->_global->_language = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
debugC(1, kDebugFileIO, "Using language %d for %s",
|
||||
_vm->_global->_language, _totFile.c_str());
|
||||
|
||||
if (locTextFile.empty())
|
||||
return nullptr;
|
||||
|
||||
return _vm->_dataIO->getFile(locTextFile, size);
|
||||
}
|
||||
|
||||
Resource *Resources::getResource(uint16 id, int16 *width, int16 *height) const {
|
||||
if (_hasLOM) {
|
||||
warning("Stub: Resources::getResource(): Has LOM");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Resource *resource = nullptr;
|
||||
if (id >= 30000)
|
||||
resource = getEXTResource(id - 30000);
|
||||
else
|
||||
resource = getTOTResource(id);
|
||||
|
||||
if (!resource)
|
||||
return nullptr;
|
||||
|
||||
if (width)
|
||||
*width = resource->getWidth();
|
||||
if (height)
|
||||
*height = resource->getHeight();
|
||||
|
||||
return resource;
|
||||
}
|
||||
|
||||
TextItem *Resources::getTextItem(uint16 id) const {
|
||||
if (!_totTextTable || !_totTextTable->data)
|
||||
return nullptr;
|
||||
|
||||
if (id >= _totTextTable->itemsCount)
|
||||
return nullptr;
|
||||
|
||||
assert(_totTextTable->items);
|
||||
|
||||
TOTTextItem &totItem = _totTextTable->items[id];
|
||||
|
||||
if ((totItem.offset == 0xFFFF) || (totItem.size == 0))
|
||||
return nullptr;
|
||||
|
||||
if ((totItem.offset + totItem.size) > (_totTextTable->size)) {
|
||||
warning("TOT text %d offset %d out of range (%s, %d, %d)",
|
||||
id, totItem.offset, _totFile.c_str(), _totSize, totItem.size);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return new TextItem(_totTextTable->data + totItem.offset, totItem.size);
|
||||
}
|
||||
|
||||
byte *Resources::getTexts() const {
|
||||
if (!_totTextTable)
|
||||
return nullptr;
|
||||
|
||||
return _totTextTable->data;
|
||||
}
|
||||
|
||||
bool Resources::dumpResource(const Resource &resource,
|
||||
const Common::Path &fileName) const {
|
||||
|
||||
Common::DumpFile dump;
|
||||
|
||||
if (!dump.open(fileName))
|
||||
return false;
|
||||
|
||||
if (dump.write(resource.getData(), resource.getSize()) != ((uint32) resource.getSize()))
|
||||
return false;
|
||||
|
||||
if (!dump.flush())
|
||||
return false;
|
||||
if (dump.err())
|
||||
return false;
|
||||
|
||||
dump.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Resources::dumpResource(const Resource &resource, uint16 id,
|
||||
const Common::String &ext) const {
|
||||
|
||||
Common::String fileName = _fileBase;
|
||||
|
||||
fileName += Common::String::format("_%05d", id);
|
||||
fileName += ".";
|
||||
fileName += ext;
|
||||
|
||||
return dumpResource(resource, Common::Path(fileName));
|
||||
}
|
||||
|
||||
Resource *Resources::getTOTResource(uint16 id) const {
|
||||
if (!_totResourceTable || (id >= _totResourceTable->itemsCount)) {
|
||||
warning("Trying to load non-existent TOT resource (%s, %d/%d)",
|
||||
_totFile.c_str(), id,
|
||||
_totResourceTable ? (_totResourceTable->itemsCount - 1) : -1);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
assert(_totResourceTable->items);
|
||||
|
||||
TOTResourceItem &totItem = _totResourceTable->items[id];
|
||||
|
||||
byte *data = nullptr;
|
||||
if (totItem.type == kResourceIM)
|
||||
data = getIMData(totItem);
|
||||
if (totItem.type == kResourceTOT)
|
||||
data = getTOTData(totItem);
|
||||
|
||||
if (!data) {
|
||||
warning("Failed to load TOT resource (%s, %d/%d, %d)",
|
||||
_totFile.c_str(), id, _totResourceTable->itemsCount - 1, totItem.type);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return new Resource(data, totItem.size, false, totItem.width, totItem.height);
|
||||
}
|
||||
|
||||
Resource *Resources::getEXTResource(uint16 id) const {
|
||||
if (!_extResourceTable || (id > _extResourceTable->itemsCount)) {
|
||||
warning("Trying to load non-existent EXT resource (%s, %d/%d)",
|
||||
_totFile.c_str(), id,
|
||||
_extResourceTable ? (_extResourceTable->itemsCount - 1) : -1);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
assert(_extResourceTable->items);
|
||||
|
||||
EXTResourceItem &extItem = _extResourceTable->items[id];
|
||||
|
||||
uint32 size = extItem.size;
|
||||
|
||||
if (extItem.width & 0x4000)
|
||||
size += 1 << 16;
|
||||
if (extItem.width & 0x2000)
|
||||
size += 2 << 16;
|
||||
if (extItem.width & 0x1000)
|
||||
size += 4 << 16;
|
||||
if (extItem.height == 0)
|
||||
size += extItem.width << 16;
|
||||
|
||||
byte *data = nullptr;
|
||||
if (extItem.type == kResourceEXT)
|
||||
data = getEXTData(extItem, size);
|
||||
if (extItem.type == kResourceEX)
|
||||
data = getEXData(extItem, size);
|
||||
|
||||
if (!data) {
|
||||
warning("Failed to load EXT resource (%s, %d/%d, %d)",
|
||||
_totFile.c_str(), id, _extResourceTable->itemsCount - 1, extItem.type);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (extItem.packed) {
|
||||
byte *packedData = data;
|
||||
|
||||
int32 unpackSize;
|
||||
data = _vm->_dataIO->unpack(packedData, size, unpackSize);
|
||||
|
||||
size = unpackSize;
|
||||
|
||||
delete[] packedData;
|
||||
}
|
||||
|
||||
return new Resource(data, size, true, extItem.width & 0xFFF, extItem.height);
|
||||
}
|
||||
|
||||
byte *Resources::getTOTData(TOTResourceItem &totItem) const {
|
||||
if (totItem.size == 0)
|
||||
return nullptr;
|
||||
|
||||
int32 offset = _totResourceTable->dataOffset + totItem.offset - _totResStart;
|
||||
|
||||
if ((offset < 0) || (((uint32) (offset + totItem.size)) > _totSize)) {
|
||||
warning("TOT data %d offset %d out of range (%s, %d, %d)",
|
||||
totItem.index, totItem.offset, _totFile.c_str(), _totSize, totItem.size);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return _totData + offset;
|
||||
}
|
||||
|
||||
byte *Resources::getIMData(TOTResourceItem &totItem) const {
|
||||
if (totItem.size == 0)
|
||||
return nullptr;
|
||||
|
||||
int32 indexOffset = totItem.index * 4;
|
||||
if ((indexOffset < 0) || (((uint32) indexOffset) >= _imSize))
|
||||
return nullptr;
|
||||
|
||||
uint32 offset = READ_LE_UINT32(_imData + indexOffset);
|
||||
if ((offset + totItem.size) > _imSize)
|
||||
return nullptr;
|
||||
|
||||
return _imData + offset;
|
||||
}
|
||||
|
||||
byte *Resources::getEXTData(EXTResourceItem &extItem, uint32 &size) const {
|
||||
Common::SeekableReadStream *stream = _vm->_dataIO->getFile(_extFile);
|
||||
if (!stream)
|
||||
return nullptr;
|
||||
|
||||
if (!stream->seek(extItem.offset)) {
|
||||
delete stream;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// If that workaround is active, limit the resource size instead of throwing an error
|
||||
if (_vm->hasResourceSizeWorkaround())
|
||||
size = MIN<int>(size, stream->size() - extItem.offset);
|
||||
|
||||
byte *data = new byte[extItem.packed ? (size + 2) : size];
|
||||
if (stream->read(data, size) != size) {
|
||||
delete[] data;
|
||||
delete stream;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
delete stream;
|
||||
return data;
|
||||
}
|
||||
|
||||
byte *Resources::getEXData(EXTResourceItem &extItem, uint32 &size) const {
|
||||
Common::SeekableReadStream *stream = _vm->_dataIO->getFile(_exFile);
|
||||
if (!stream)
|
||||
return nullptr;
|
||||
|
||||
if (!stream->seek(extItem.offset)) {
|
||||
delete stream;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// If that workaround is active, limit the resource size instead of throwing an error
|
||||
if (_vm->hasResourceSizeWorkaround())
|
||||
size = MIN<int>(size, stream->size() - extItem.offset);
|
||||
|
||||
byte *data = new byte[extItem.packed ? (size + 2) : size];
|
||||
if (stream->read(data, size) != size) {
|
||||
delete[] data;
|
||||
delete stream;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
delete stream;
|
||||
return data;
|
||||
}
|
||||
|
||||
} // End of namespace Gob
|
||||
Reference in New Issue
Block a user