diff --git a/engines/sword1/compress_sword1.cpp b/engines/sword1/compress_sword1.cpp index 6b49f0d5..e454f8c1 100644 --- a/engines/sword1/compress_sword1.cpp +++ b/engines/sword1/compress_sword1.cpp @@ -311,14 +311,15 @@ MusicFile musicNames[TOTAL_TUNES] = { { "RM3D", false } }; -int16 *CompressSword1::uncompressSpeech(Common::File &clu, uint32 idx, uint32 cSize, uint32 *returnSize) { +int16 *CompressSword1::uncompressSpeech(Common::File &clu, uint32 idx, uint32 cSize, uint32 *returnSize, bool* ok) { if (_speechEndianness == UnknownEndian) { uint32 leSize, beSize; + bool leOk = false, beOk = false; _speechEndianness = LittleEndian; - int16* leData = uncompressSpeech(clu, idx, cSize, &leSize); + int16* leData = uncompressSpeech(clu, idx, cSize, &leSize, &leOk); _speechEndianness = BigEndian; - int16* beData = uncompressSpeech(clu, idx, cSize, &beSize); - _speechEndianness = guessEndianness(leData, leSize / 2, beData, beSize / 2); + int16* beData = uncompressSpeech(clu, idx, cSize, &beSize, &beOk); + _speechEndianness = guessEndianness(leData, leSize / 2, leOk, beData, beSize / 2, beOk); switch (_speechEndianness) { case LittleEndian: free(beData); @@ -350,6 +351,8 @@ int16 *CompressSword1::uncompressSpeech(Common::File &clu, uint32 idx, uint32 cS while ((READ_BE_UINT32(fBuf + headerPos) != 'data') && (headerPos < 100)) headerPos++; if (headerPos < 100) { + if (ok != 0) + *ok = true; resSize = READ_LE_UINT32(fBuf + headerPos + 4) >> 1; srcData = (int16 *)(fBuf + headerPos + 8); dstData = (int16 *)malloc(resSize * 2); @@ -367,18 +370,29 @@ int16 *CompressSword1::uncompressSpeech(Common::File &clu, uint32 idx, uint32 cS for (cnt = 0; cnt < (uint16)length && dstPos < resSize; cnt++) dstData[dstPos++] = srcData[srcPos]; srcPos++; + if (ok != 0 && cnt < (uint16)length) + *ok = false; } else { - if (dstPos + length > resSize) + if (dstPos + length > resSize) { length = resSize - dstPos; + if (ok != 0) + *ok = false; + } memcpy(dstData + dstPos, srcData + srcPos, length * 2); dstPos += length; srcPos += length; } } + // The ok flag is used when detecting endianness. If the correct endianness was used then decoding cSize samples + // should result in the expected resSize. But when using the wrong endianness this is likely not to be the case. + if (ok != 0 && (srcPos < cSize || dstPos < resSize)) + *ok = false; free(fBuf); *returnSize = resSize * 2; return dstData; } else { + if (ok != 0) + *ok = false; free(fBuf); error("Sound::uncompressSpeech(): DATA tag not found in wave header"); *returnSize = 0; @@ -386,7 +400,7 @@ int16 *CompressSword1::uncompressSpeech(Common::File &clu, uint32 idx, uint32 cS } } -CompressSword1::Endianness CompressSword1::guessEndianness(int16 *leData, uint32 leSize, int16 *beData, uint32 beSize) { +CompressSword1::Endianness CompressSword1::guessEndianness(int16 *leData, uint32 leSize, bool leOk, int16 *beData, uint32 beSize, bool beOk) { if (leData == NULL && beData == NULL) return UnknownEndian; else if (leData == NULL) @@ -394,6 +408,14 @@ CompressSword1::Endianness CompressSword1::guessEndianness(int16 *leData, uint32 else if (beData == NULL) return LittleEndian; + // Also decomding with the wrong endianness leads to wrong sizes when decrompressing the data. So if one of the two is wrong assume + // this indicates this was the wrong endianess. In the case when the two are wrong this indicate corrupetd data but try to recover + // from it anyway. + if (leOk && !beOk) + return LittleEndian; + else if (!leOk && beOk) + return BigEndian; + // Compute average of difference between two consecutive samples for both the given // data array and the byte swapped array. uint32 length = leSize > beSize ? beSize : leSize; diff --git a/engines/sword1/compress_sword1.h b/engines/sword1/compress_sword1.h index 7321d503..28f091af 100644 --- a/engines/sword1/compress_sword1.h +++ b/engines/sword1/compress_sword1.h @@ -42,7 +42,7 @@ class CompressSword1 : public CompressionTool { std::string _audioOuputFilename; - int16 *uncompressSpeech(Common::File &clu, uint32 idx, uint32 cSize, uint32 *returnSize); + int16 *uncompressSpeech(Common::File &clu, uint32 idx, uint32 cSize, uint32 *returnSize, bool* ok = 0); uint8 *convertData(uint8 *rawData, uint32 rawSize, uint32 *resSize); void convertClu(Common::File &clu, Common::File &cl3); void compressSpeech(const Common::Filename *inpath, const Common::Filename *outpath); @@ -50,7 +50,7 @@ class CompressSword1 : public CompressionTool { void checkFilesExist(bool checkSpeech, bool checkMusic, const Common::Filename *inpath); enum Endianness { BigEndian , LittleEndian , UnknownEndian } ; - Endianness guessEndianness(int16 *leData, uint32 leSize, int16 *beData, uint32 beSize); + Endianness guessEndianness(int16 *leData, uint32 leSize, bool leOk, int16 *beData, uint32 beSize, bool beOk); double endiannessHeuristicValue(int16* data, uint32 dataSize, uint32 maxSamples, Endianness dataEndianness); private: