Skip to content

Commit

Permalink
SWORD1: Improve detection of the speech file endianness
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
criezy committed Jun 6, 2016
1 parent fa809f5 commit ab8f654
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 8 deletions.
34 changes: 28 additions & 6 deletions engines/sword1/compress_sword1.cpp
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand All @@ -367,33 +370,52 @@ 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;
return NULL;
}
}

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)
return BigEndian;
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;
Expand Down
4 changes: 2 additions & 2 deletions engines/sword1/compress_sword1.h
Expand Up @@ -42,15 +42,15 @@ 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);
void compressMusic(const Common::Filename *inpath, const Common::Filename *outpath);
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:
Expand Down

0 comments on commit ab8f654

Please sign in to comment.