aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engines/sci/resource.cpp22
-rw-r--r--engines/sci/resource_audio.cpp124
-rw-r--r--engines/sci/resource_intern.h24
3 files changed, 75 insertions, 95 deletions
diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp
index 91cceb5968..2f34f8f433 100644
--- a/engines/sci/resource.cpp
+++ b/engines/sci/resource.cpp
@@ -2013,20 +2013,7 @@ bool ResourceManager::validateResource(const ResourceId &resourceId, const Commo
void ResourceManager::addResource(ResourceId resId, ResourceSource *src, uint32 offset, uint32 size, const Common::String &sourceMapLocation) {
// Adding new resource only if it does not exist
if (_resMap.contains(resId) == false) {
- Common::SeekableReadStream *volumeFile = getVolumeFile(src);
- if (volumeFile == nullptr) {
- error("Could not open %s for reading", src->getLocationName().c_str());
- }
-
- if (validateResource(resId, sourceMapLocation, src->getLocationName(), offset, size, volumeFile->size())) {
- Resource *res = new Resource(this, resId);
- _resMap.setVal(resId, res);
- res->_source = src;
- res->_fileOffset = offset;
- res->_size = size;
- } else {
- _hasBadResources = true;
- }
+ updateResource(resId, src, offset, size, sourceMapLocation);
}
}
@@ -2048,6 +2035,13 @@ Resource *ResourceManager::updateResource(ResourceId resId, ResourceSource *src,
error("Could not open %s for reading", src->getLocationName().c_str());
}
+ AudioVolumeResourceSource *avSrc = dynamic_cast<AudioVolumeResourceSource *>(src);
+ if (avSrc != nullptr && !avSrc->relocateMapOffset(offset, size)) {
+ warning("Compressed volume %s does not contain a valid entry for %s (map offset %u)", src->getLocationName().c_str(), resId.toString().c_str(), offset);
+ _hasBadResources = true;
+ return res;
+ }
+
if (validateResource(resId, sourceMapLocation, src->getLocationName(), offset, size, volumeFile->size())) {
if (res == nullptr) {
res = new Resource(this, resId);
diff --git a/engines/sci/resource_audio.cpp b/engines/sci/resource_audio.cpp
index a5501cdb84..2cd157a631 100644
--- a/engines/sci/resource_audio.cpp
+++ b/engines/sci/resource_audio.cpp
@@ -36,7 +36,6 @@ AudioVolumeResourceSource::AudioVolumeResourceSource(ResourceManager *resMan, co
: VolumeResourceSource(name, map, volNum, kSourceAudioVolume) {
_audioCompressionType = 0;
- _audioCompressionOffsetMapping = NULL;
/*
* Check if this audio volume got compressed by our tool. If that is the
@@ -49,36 +48,37 @@ AudioVolumeResourceSource::AudioVolumeResourceSource(ResourceManager *resMan, co
return;
fileStream->seek(0, SEEK_SET);
- uint32 compressionType = fileStream->readUint32BE();
+ const uint32 compressionType = fileStream->readUint32BE();
switch (compressionType) {
case MKTAG('M','P','3',' '):
case MKTAG('O','G','G',' '):
case MKTAG('F','L','A','C'):
- // Detected a compressed audio volume
_audioCompressionType = compressionType;
- // Now read the whole offset mapping table for later usage
- int32 recordCount = fileStream->readUint32LE();
- if (!recordCount)
- error("compressed audio volume doesn't contain any entries");
- int32 *offsetMapping = new int32[(recordCount + 1) * 2];
- _audioCompressionOffsetMapping = offsetMapping;
- for (int recordNo = 0; recordNo < recordCount; recordNo++) {
- *offsetMapping++ = fileStream->readUint32LE();
- *offsetMapping++ = fileStream->readUint32LE();
+ const uint32 numEntries = fileStream->readUint32LE();
+ if (!numEntries) {
+ error("Compressed audio volume %s has no relocation table entries", name.c_str());
}
- // Put ending zero
- *offsetMapping++ = 0;
- *offsetMapping++ = fileStream->size();
+
+ CompressedTableEntry *lastEntry = nullptr;
+ for (uint i = 0; i < numEntries; ++i) {
+ CompressedTableEntry nextEntry;
+ const uint32 sourceOffset = fileStream->readUint32LE();
+ nextEntry.offset = fileStream->readUint32LE();
+ if (lastEntry != nullptr) {
+ lastEntry->size = nextEntry.offset - lastEntry->offset;
+ }
+
+ _compressedOffsets.setVal(sourceOffset, nextEntry);
+ lastEntry = &_compressedOffsets.getVal(sourceOffset);
+ }
+
+ lastEntry->size = fileStream->size() - lastEntry->offset;
}
if (_resourceFile)
delete fileStream;
}
-AudioVolumeResourceSource::~AudioVolumeResourceSource() {
- delete[] _audioCompressionOffsetMapping;
-}
-
bool Resource::loadFromWaveFile(Common::SeekableReadStream *file) {
byte *ptr = new byte[_size];
_data = ptr;
@@ -315,7 +315,7 @@ int ResourceManager::readAudioMapSCI11(IntMapResourceSource *map) {
Common::SeekableReadStream *fileStream = getVolumeFile(src);
if (!fileStream) {
- warning("Failed to open file stream for %s", mapResId.toString().c_str());
+ warning("Failed to open file stream for %s", src->getLocationName().c_str());
return SCI_ERROR_NO_RESOURCE_FILES_FOUND;
}
@@ -383,17 +383,21 @@ int ResourceManager::readAudioMapSCI11(IntMapResourceSource *map) {
offset = ptr.getUint32LE();
ptr += 4;
- // The size is not stored in the map and the entries have no order.
- // We need to dig into the audio resource in the volume to get the size.
- stream->seek(offset + 1);
- byte headerSize = stream->readByte();
- if (headerSize != 11 && headerSize != 12) {
- error("Unexpected header size in %s: should be 11 or 12, got %d", audioResId.toString().c_str(), headerSize);
- }
-
- stream->skip(7);
- uint32 size = stream->readUint32LE() + headerSize + 2;
+ uint32 size;
+ if (src->getAudioCompressionType() == 0) {
+ // The size is not stored in the map and the entries have no order.
+ // We need to dig into the audio resource in the volume to get the size.
+ stream->seek(offset + 1);
+ byte headerSize = stream->readByte();
+ if (headerSize != 11 && headerSize != 12) {
+ error("Unexpected header size in %s: should be 11 or 12, got %d", audioResId.toString().c_str(), headerSize);
+ }
+ stream->skip(7);
+ size = stream->readUint32LE() + headerSize + 2;
+ } else {
+ size = 0;
+ }
addResource(audioResId, src, offset, size, map->getLocationName());
}
} else {
@@ -406,7 +410,7 @@ int ResourceManager::readAudioMapSCI11(IntMapResourceSource *map) {
while (ptr != mapRes->cend()) {
uint32 n = ptr.getUint32BE();
- int syncSize = 0;
+ uint32 syncSize = 0;
ptr += 4;
if (n == 0xffffffff)
@@ -436,7 +440,7 @@ int ResourceManager::readAudioMapSCI11(IntMapResourceSource *map) {
if (g_sci->getGameId() == GID_KQ6 && (n & 0x40)) {
// This seems to define the size of raw lipsync data (at least
// in KQ6 CD Windows).
- int kq6HiresSyncSize = ptr.getUint16LE();
+ uint32 kq6HiresSyncSize = ptr.getUint16LE();
ptr += 2;
if (kq6HiresSyncSize > 0) {
@@ -924,52 +928,16 @@ void AudioVolumeResourceSource::loadResource(ResourceManager *resMan, Resource *
if (!fileStream)
return;
- if (_audioCompressionType) {
- // this file is compressed, so lookup our offset in the offset-translation table and get the new offset
- // also calculate the compressed size by using the next offset
- int32 *mappingTable = _audioCompressionOffsetMapping;
- int32 compressedOffset = 0;
-
- do {
- if (*mappingTable == res->_fileOffset) {
- mappingTable++;
- compressedOffset = *mappingTable;
- // Go to next compressed offset and use that to calculate size of compressed sample
- switch (res->getType()) {
- case kResourceTypeSync:
- case kResourceTypeSync36:
- case kResourceTypeRave:
- // we should already have a (valid) size
- break;
- default:
- mappingTable += 2;
- res->_size = *mappingTable - compressedOffset;
- }
- break;
- }
- mappingTable += 2;
- } while (*mappingTable);
-
- if (!compressedOffset)
- error("could not translate offset to compressed offset in audio volume");
- fileStream->seek(compressedOffset, SEEK_SET);
-
- switch (res->getType()) {
- case kResourceTypeAudio:
- case kResourceTypeAudio36:
- // Directly read the stream, compressed audio wont have resource type id and header size for SCI1.1
- res->loadFromAudioVolumeSCI1(fileStream);
- if (_resourceFile)
- delete fileStream;
- return;
- default:
- break;
- }
- } else {
- // original file, directly seek to given offset and get SCI1/SCI1.1 audio resource
- fileStream->seek(res->_fileOffset, SEEK_SET);
- }
- if (getSciVersion() < SCI_VERSION_1_1)
+ fileStream->seek(res->_fileOffset, SEEK_SET);
+
+ // For compressed audio, using loadFromAudioVolumeSCI1 is a hack to bypass
+ // the resource type checking in loadFromAudioVolumeSCI11 (since
+ // loadFromAudioVolumeSCI1 does nothing more than read raw data)
+ if (_audioCompressionType != 0 &&
+ (res->getType() == kResourceTypeAudio ||
+ res->getType() == kResourceTypeAudio36)) {
+ res->loadFromAudioVolumeSCI1(fileStream);
+ } else if (getSciVersion() < SCI_VERSION_1_1)
res->loadFromAudioVolumeSCI1(fileStream);
else
res->loadFromAudioVolumeSCI11(fileStream);
diff --git a/engines/sci/resource_intern.h b/engines/sci/resource_intern.h
index f198eddeb3..ea3e05661f 100644
--- a/engines/sci/resource_intern.h
+++ b/engines/sci/resource_intern.h
@@ -144,17 +144,35 @@ public:
class AudioVolumeResourceSource : public VolumeResourceSource {
protected:
+ struct CompressedTableEntry {
+ uint32 offset;
+ uint32 size;
+ };
+
uint32 _audioCompressionType;
- int32 *_audioCompressionOffsetMapping;
+ Common::HashMap<uint32, CompressedTableEntry> _compressedOffsets;
public:
AudioVolumeResourceSource(ResourceManager *resMan, const Common::String &name, ResourceSource *map, int volNum);
- virtual ~AudioVolumeResourceSource();
-
virtual void loadResource(ResourceManager *resMan, Resource *res);
virtual uint32 getAudioCompressionType() const;
+
+ bool relocateMapOffset(uint32 &offset, uint32 &size) const {
+ if (_audioCompressionType == 0) {
+ return true;
+ }
+
+ if (!_compressedOffsets.contains(offset)) {
+ return false;
+ }
+
+ const CompressedTableEntry &entry = _compressedOffsets.getVal(offset);
+ offset = entry.offset;
+ size = entry.size;
+ return true;
+ }
};
class ExtAudioMapResourceSource : public ResourceSource {