Skip to content

Commit

Permalink
Merged revision(s) 20736 from trunk/OpenMPT:
Browse files Browse the repository at this point in the history
[Imp] STK: Allow romantic.stk to load, which has a sample longer than 74KB.
[Imp] STK: Also allow files to load that have garbage in the song title, but whose sample names are properly null-terminated non-empty ASCII strings. Fixes STK.Sharks-NewIntro.
........


git-svn-id: https://source.openmpt.org/svn/openmpt/branches/OpenMPT-1.31@20780 56274372-70c3-4bfc-bfc3-4c3a0b034d27
  • Loading branch information
sagamusix committed May 11, 2024
1 parent 11c8185 commit a889202
Showing 1 changed file with 39 additions and 7 deletions.
46 changes: 39 additions & 7 deletions soundlib/Load_mod.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1382,7 +1382,7 @@ bool CSoundFile::ReadMOD(FileReader &file, ModLoadingFlags loadFlags)


// Check if a name string is valid (i.e. doesn't contain binary garbage data)
static uint32 CountInvalidChars(const mpt::span<const char> name)
static uint32 CountInvalidChars(const mpt::span<const char> name) noexcept
{
uint32 invalidChars = 0;
for(int8 c : name) // char can be signed or unsigned
Expand All @@ -1395,6 +1395,34 @@ static uint32 CountInvalidChars(const mpt::span<const char> name)
}


enum class NameClassification
{
Empty,
ValidASCII,
Invalid,
};

// Check if a name is a valid null-terminated ASCII string with no garbage after the null terminator, or if it's empty
static NameClassification ClassifyName(const mpt::span<const char> name) noexcept
{
bool foundNull = false, foundNormal = false;
for(auto c : name)
{
if(c > 0 && c < ' ')
return NameClassification::Invalid;
if(c == 0)
foundNull = true;
else if(foundNull)
return NameClassification::Invalid;
else
foundNormal = true;
}
if(!foundNull)
return NameClassification::Invalid;
return foundNormal ? NameClassification::ValidASCII : NameClassification::Empty;
}


// We'll have to do some heuristic checks to find out whether this is an old Ultimate Soundtracker module
// or if it was made with the newer Soundtracker versions.
// Thanks for Fraggie for this information! (https://www.un4seen.com/forum/?topic=14471.msg100829#msg100829)
Expand Down Expand Up @@ -1433,7 +1461,8 @@ static bool ValidateHeader(const M15FileHeaders &fileHeaders)

SmpLength totalSampleLen = 0;
uint8 allVolumes = 0;
uint8 diskNameCount = 0;
uint8 validNameCount = 0;
bool invalidNames = false;

for(SAMPLEINDEX smp = 0; smp < 15; smp++)
{
Expand All @@ -1444,13 +1473,16 @@ 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++;
if(const auto nameType = ClassifyName(sampleHeader.name); nameType == NameClassification::ValidASCII)
validNameCount++;
else if(nameType == NameClassification::Invalid)
invalidNames = true;

// Sanity checks - invalid character count adjusted for ata.mod (MD5 937b79b54026fa73a1a4d3597c26eace, SHA1 3322ca62258adb9e0ae8e9afe6e0c29d39add874)
// Sample length adjusted for romantic.stk which has a (valid) sample of length 72222
if(invalidChars > 48
|| sampleHeader.volume > 64
|| sampleHeader.length > 32768)
|| sampleHeader.length > 37000)
{
return false;
}
Expand All @@ -1459,8 +1491,8 @@ 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)
// scramble_2.mod has a lot of garbage in the song title, but it has lots of properly-formatted sample names, so we consider those to be more important than the garbage bytes.
if(invalidCharsInTitle > 5 && (validNameCount < 4 || invalidNames))
{
return false;
}
Expand Down

0 comments on commit a889202

Please sign in to comment.