[Scummvm-cvs-logs] scummvm-tools master -> ab8f6546a7a5dd06af1f6c3ebf68483603a95cf1
criezy
criezy at scummvm.org
Mon Jun 6 02:29:37 CEST 2016
This automated email contains information about 2 new commits which have been
pushed to the 'scummvm-tools' repo located at https://github.com/scummvm/scummvm-tools .
Summary:
fa809f5d48 SWORD1: Fix memory corruption when trying to guess file endianness
ab8f6546a7 SWORD1: Improve detection of the speech file endianness
Commit: fa809f5d48fbc70fb7cd991f04eddf513e95713c
https://github.com/scummvm/scummvm-tools/commit/fa809f5d48fbc70fb7cd991f04eddf513e95713c
Author: Thierry Crozat (criezy at scummvm.org)
Date: 2016-06-06T01:29:19+01:00
Commit Message:
SWORD1: Fix memory corruption when trying to guess file endianness
The issue was that it was trying both little and big endian to check
which one seemed to be the most likely, but with the wrong
endianness it could write data beyond the end of the allocated
memory when decompressing the speech data as it was using an
incorrect size. This commits adds sanity checks to avoid this.
Changed paths:
NEWS
engines/sword1/compress_sword1.cpp
diff --git a/NEWS b/NEWS
index edeb8ca..98a4e84 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,9 @@
For a more comprehensive changelog of the latest experimental code, see:
https://github.com/scummvm/scummvm-tools/commits/
+1.9.0 (YYYY-MM-DD)
+ - Fix random crashes in the tool to convert Broken Sword 1 speech files.
+
1.8.0 (2016-03-04)
- Add a tool to compress Tony Tough's ADP files.
- Add extraction and packing tools for The Prince and the Coward.
diff --git a/engines/sword1/compress_sword1.cpp b/engines/sword1/compress_sword1.cpp
index ef8bd73..6b49f0d 100644
--- a/engines/sword1/compress_sword1.cpp
+++ b/engines/sword1/compress_sword1.cpp
@@ -339,8 +339,8 @@ int16 *CompressSword1::uncompressSpeech(Common::File &clu, uint32 idx, uint32 cS
}
}
- uint32 resSize, srcPos;
- int16 *srcData, *dstData, *dstPos;
+ uint32 resSize, srcPos, dstPos;
+ int16 *srcData, *dstData;
uint32 headerPos = 0;
int16 length, cnt;
uint8 *fBuf = (uint8 *)malloc(cSize);
@@ -354,9 +354,9 @@ int16 *CompressSword1::uncompressSpeech(Common::File &clu, uint32 idx, uint32 cS
srcData = (int16 *)(fBuf + headerPos + 8);
dstData = (int16 *)malloc(resSize * 2);
srcPos = 0;
- dstPos = dstData;
+ dstPos = 0;
cSize = (cSize - (headerPos + 8)) / 2;
- while (srcPos < cSize) {
+ while (srcPos < cSize && dstPos < resSize) {
if (_speechEndianness == LittleEndian)
length = (int16)READ_LE_UINT16(srcData + srcPos);
else
@@ -364,11 +364,13 @@ int16 *CompressSword1::uncompressSpeech(Common::File &clu, uint32 idx, uint32 cS
srcPos++;
if (length < 0) {
length = -length;
- for (cnt = 0; cnt < (uint16)length; cnt++)
- *dstPos++ = srcData[srcPos];
+ for (cnt = 0; cnt < (uint16)length && dstPos < resSize; cnt++)
+ dstData[dstPos++] = srcData[srcPos];
srcPos++;
} else {
- memcpy(dstPos, srcData + srcPos, length * 2);
+ if (dstPos + length > resSize)
+ length = resSize - dstPos;
+ memcpy(dstData + dstPos, srcData + srcPos, length * 2);
dstPos += length;
srcPos += length;
}
Commit: ab8f6546a7a5dd06af1f6c3ebf68483603a95cf1
https://github.com/scummvm/scummvm-tools/commit/ab8f6546a7a5dd06af1f6c3ebf68483603a95cf1
Author: Thierry Crozat (criezy at scummvm.org)
Date: 2016-06-06T01:29:19+01:00
Commit Message:
SWORD1: Improve detection of the speech file endianness
Before trying an heuristic it simply checks if by decoding the given
amount of input samples we get the expected resource size. When
using the wrong endianness this is unlikely to be the case.
Changed paths:
engines/sword1/compress_sword1.cpp
engines/sword1/compress_sword1.h
diff --git a/engines/sword1/compress_sword1.cpp b/engines/sword1/compress_sword1.cpp
index 6b49f0d..e454f8c 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 7321d50..28f091a 100644
--- a/engines/sword1/compress_sword1.h
+++ b/engines/sword1/compress_sword1.h
@@ -42,7 +42,7 @@ protected:
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 @@ protected:
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:
More information about the Scummvm-git-logs
mailing list