diff options
-rw-r--r-- | engines/sci/resource.cpp | 22 | ||||
-rw-r--r-- | engines/sci/resource_audio.cpp | 124 | ||||
-rw-r--r-- | engines/sci/resource_intern.h | 24 |
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 { |