diff --git a/soundlib/Load_mod.cpp b/soundlib/Load_mod.cpp index 076e24c3a9c..5cc08f1aca1 100644 --- a/soundlib/Load_mod.cpp +++ b/soundlib/Load_mod.cpp @@ -324,6 +324,11 @@ struct MODSampleHeader + ((loopStart > length * 2) ? 1 : 0); } + bool HasDiskName() const + { + return (!memcmp(name, "st-", 3) || !memcmp(name, "ST-", 3)) && name[5] == ':'; + } + // Suggested threshold for rejecting invalid files based on cumulated score returned by GetInvalidByteScore static constexpr uint32 INVALID_BYTE_THRESHOLD = 40; @@ -1370,15 +1375,13 @@ static bool ValidateHeader(const M15FileHeaders &fileHeaders) // However, there are quite a few SoundTracker modules in the wild with random // characters. To still be able to distguish them from other formats, we just reject // files with *too* many bogus characters. Arbitrary threshold: 48 bogus characters in total - // or more than 11 invalid characters just in the title alone (just enough to make scramble_2.mod load). - uint32 invalidChars = CountInvalidChars(fileHeaders.songname); - if(invalidChars > 11) - { - return false; - } + // or more than 5 invalid characters just in the title alone + uint32 invalidCharsInTitle = CountInvalidChars(fileHeaders.songname); + uint32 invalidChars = invalidCharsInTitle; SmpLength totalSampleLen = 0; uint8 allVolumes = 0; + uint8 diskNameCount = 0; for(SAMPLEINDEX smp = 0; smp < 15; smp++) { @@ -1389,6 +1392,8 @@ static bool ValidateHeader(const M15FileHeaders &fileHeaders) // schmokk.mod has a non-zero value here but it should not be treated as finetune if(sampleHeader.finetune != 0) invalidChars += 16; + if(sampleHeader.HasDiskName()) + diskNameCount++; // Sanity checks - invalid character count adjusted for ata.mod (MD5 937b79b54026fa73a1a4d3597c26eace, SHA1 3322ca62258adb9e0ae8e9afe6e0c29d39add874) if(invalidChars > 48 @@ -1402,6 +1407,12 @@ static bool ValidateHeader(const M15FileHeaders &fileHeaders) allVolumes |= sampleHeader.volume; } + // scramble_2.mod has a lot of garbage in the song title, but it has lots of sample names starting with st-01, so we consider those to be more important than the garbage bytes. + if(invalidCharsInTitle > 5 && diskNameCount < 4) + { + return false; + } + // Reject any files with no (or only silent) samples at all, as this might just be a random binary file (e.g. ID3 tags with tons of padding) if(totalSampleLen == 0 || allVolumes == 0) { @@ -1507,7 +1518,7 @@ bool CSoundFile::ReadM15(FileReader &file, ModLoadingFlags loadFlags) totalSampleLen += mptSmp.nLength; - if(m_szNames[smp][0] && ((memcmp(m_szNames[smp].buf, "st-", 3) && memcmp(m_szNames[smp].buf, "ST-", 3)) || m_szNames[smp][5] != ':')) + if(m_szNames[smp][0] && sampleHeader.HasDiskName()) { // Ultimate Soundtracker 1.8 and D.O.C. SoundTracker IX always have sample names containing disk names. hasDiskNames = false;