mirror of
https://github.com/libretro/scummvm.git
synced 2025-02-24 13:13:58 +00:00
173 lines
4.8 KiB
C++
173 lines
4.8 KiB
C++
/* ResidualVM - A 3D game interpreter
|
|
*
|
|
* ResidualVM is the legal property of its developers, whose names
|
|
* are too numerous to list here. Please refer to the AUTHORS
|
|
* 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.
|
|
*
|
|
*/
|
|
|
|
#include "engines/myst3/archive.h"
|
|
#include "engines/myst3/directorysubentry.h"
|
|
|
|
#include "common/str.h"
|
|
#include "common/debug.h"
|
|
#include "common/file.h"
|
|
#include "common/memstream.h"
|
|
|
|
namespace Myst3 {
|
|
|
|
DirectorySubEntry::DirectorySubEntry(Archive *archive) :
|
|
_archive(archive) {
|
|
for (uint i = 0; i < 22; i++) {
|
|
_miscData[i] = 0;
|
|
}
|
|
}
|
|
|
|
void DirectorySubEntry::readFromStream(Common::SeekableReadStream &inStream) {
|
|
_offset = inStream.readUint32LE();
|
|
_size = inStream.readUint32LE();
|
|
_metadataSize = inStream.readUint16LE();
|
|
_face = inStream.readByte();
|
|
_type = static_cast<ResourceType>(inStream.readByte());
|
|
|
|
if (_type == kSpotItem || _type == kMenuSpotItem) {
|
|
_spotItemData.u = inStream.readUint32LE();
|
|
_spotItemData.v = inStream.readUint32LE();
|
|
} else if (_type == kMovie || _type == kMultitrackMovie) {
|
|
_videoData.v1.setValue(0, inStream.readSint32LE() * 0.000001f);
|
|
_videoData.v1.setValue(1, inStream.readSint32LE() * 0.000001f);
|
|
_videoData.v1.setValue(2, inStream.readSint32LE() * 0.000001f);
|
|
|
|
_videoData.v2.setValue(0, inStream.readSint32LE() * 0.000001f);
|
|
_videoData.v2.setValue(1, inStream.readSint32LE() * 0.000001f);
|
|
_videoData.v2.setValue(2, inStream.readSint32LE() * 0.000001f);
|
|
|
|
_videoData.u = inStream.readSint32LE();
|
|
_videoData.v = inStream.readSint32LE();
|
|
_videoData.width = inStream.readSint32LE();
|
|
_videoData.height = inStream.readSint32LE();
|
|
} else if (_type == kNumMetadata || _type == kTextMetadata) {
|
|
if (_metadataSize > 20) {
|
|
warning("Too much metadata, skipping");
|
|
inStream.skip(_metadataSize * sizeof(uint32));
|
|
return;
|
|
}
|
|
|
|
_miscData[0] = _offset;
|
|
_miscData[1] = _size;
|
|
|
|
for (uint i = 0; i < _metadataSize; i++)
|
|
_miscData[i + 2] = inStream.readUint32LE();
|
|
} else if (_metadataSize != 0) {
|
|
warning("Metadata not read for type %d, size %d", _type, _metadataSize);
|
|
inStream.skip(_metadataSize * sizeof(uint32));
|
|
}
|
|
}
|
|
|
|
void DirectorySubEntry::dump() {
|
|
debug("offset : %x size: %d padding : %d face : %d type : %d", _offset, _size, _metadataSize, _face, _type);
|
|
}
|
|
|
|
void DirectorySubEntry::dumpToFile(Common::SeekableReadStream &inStream, const char* room, uint16 index) {
|
|
char fileName[255];
|
|
|
|
switch (_type) {
|
|
case kNumMetadata:
|
|
case kTextMetadata:
|
|
return; // These types are pure metadata and can't be extracted
|
|
case kCubeFace:
|
|
case kSpotItem:
|
|
case kMenuSpotItem:
|
|
case kFrame:
|
|
sprintf(fileName, "dump/%s-%d-%d.jpg", room, index, _face);
|
|
break;
|
|
case kFaceMask:
|
|
sprintf(fileName, "dump/%s-%d-%d.mask", room, index, _face);
|
|
break;
|
|
case kMovie:
|
|
case kStillMovie:
|
|
case kDialogMovie:
|
|
case kMultitrackMovie:
|
|
sprintf(fileName, "dump/%s-%d.bik", room, index);
|
|
break;
|
|
default:
|
|
sprintf(fileName, "dump/%s-%d-%d.%d", room, index, _face, _type);
|
|
break;
|
|
}
|
|
|
|
|
|
debug("Extracted %s", fileName);
|
|
|
|
Common::DumpFile outFile;
|
|
if (!outFile.open(fileName))
|
|
error("Unable to open file '%s' for writing", fileName);
|
|
|
|
inStream.seek(_offset);
|
|
|
|
uint8 *buf = new uint8[_size];
|
|
|
|
inStream.read(buf, _size);
|
|
outFile.write(buf, _size);
|
|
|
|
delete[] buf;
|
|
|
|
outFile.close();
|
|
}
|
|
|
|
Common::MemoryReadStream *DirectorySubEntry::getData() const {
|
|
return _archive->dumpToMemory(_offset, _size);
|
|
}
|
|
|
|
uint32 DirectorySubEntry::getMiscData(uint index) const {
|
|
assert(index < 22);
|
|
|
|
return _miscData[index];
|
|
}
|
|
|
|
Common::String DirectorySubEntry::getTextData(uint index) const {
|
|
uint8 key = 35;
|
|
uint8 cnt = 0;
|
|
uint8 decrypted[89];
|
|
memset(decrypted, 0, sizeof(decrypted));
|
|
|
|
uint8 *out = &decrypted[0];
|
|
while (_miscData[cnt / 4] && cnt < 89) {
|
|
// XORed text stored in little endian 32 bit words
|
|
*out++ = (_miscData[cnt / 4] >> (8 * (3 - (cnt % 4)))) ^ key++;
|
|
cnt++;
|
|
}
|
|
|
|
// decrypted contains a null separated string array
|
|
// extract the wanted one
|
|
cnt = 0;
|
|
int i = 0;
|
|
Common::String text;
|
|
while (cnt <= index && i < 89) {
|
|
if (cnt == index)
|
|
text += decrypted[i];
|
|
|
|
if (!decrypted[i])
|
|
cnt++;
|
|
|
|
i++;
|
|
}
|
|
|
|
return text;
|
|
}
|
|
|
|
} // end of namespace Myst3
|