View Issue Details
| ID | Project | Category | View Status | Date Submitted | Last Update |
|---|---|---|---|---|---|
| 0000914 | OpenMPT | libopenmpt | public | 2017-01-24 10:39 | 2017-09-21 06:44 |
| Reporter | manx | Assigned To | manx | ||
| Priority | high | Severity | major | Reproducibility | always |
| Status | resolved | Resolution | fixed | ||
| Product Version | OpenMPT 1.27.00.* (old testing) | ||||
| Target Version | OpenMPT 1.27.01.00 / libopenmpt 0.3.1 (upgrade first) | Fixed in Version | OpenMPT 1.27.01.00 / libopenmpt 0.3.1 (upgrade first) | ||
| Summary | 0000914: split module format probing into separate TestFOO() static member functions | ||||
| Description | Split module format header probing into separate TestFOO() static member functions to allow for probing without creating a CSoundFile instance (which is rather slow) | ||||
| Tags | No tags attached. | ||||
| Attached Files | probe-refactor-v11.patch (107,955 bytes)
Index: soundlib/ContainerMMCMP.cpp
===================================================================
--- soundlib/ContainerMMCMP.cpp (revision 8886)
+++ soundlib/ContainerMMCMP.cpp (working copy)
@@ -13,6 +13,7 @@
#include "../common/FileReader.h"
#include "Container.h"
+#include "Sndfile.h"
#include <stdexcept>
@@ -144,6 +145,66 @@
}
+static bool ValidateHeader(const MMCMPFILEHEADER &mfh)
+//----------------------------------------------------
+{
+ if(std::memcmp(mfh.id, "ziRCONia", 8) != 0)
+ {
+ return false;
+ }
+ if(mfh.hdrsize != sizeof(MMCMPHEADER))
+ {
+ return false;
+ }
+ return true;
+}
+
+
+static bool ValidateHeader(const MMCMPHEADER &mmh)
+//------------------------------------------------
+{
+ if(mmh.nblocks == 0)
+ {
+ return false;
+ }
+ if(mmh.filesize == 0)
+ {
+ return false;
+ }
+ if(mmh.filesize > 0x80000000)
+ {
+ return false;
+ }
+ return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderMMCMP(MemoryFileReader file, const uint64 *pfilesize)
+//------------------------------------------------------------------------------------------------------
+{
+ MMCMPFILEHEADER mfh;
+ if(!file.ReadStruct(mfh))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(mfh))
+ {
+ return ProbeFailure;
+ }
+ MMCMPHEADER mmh;
+ if(!file.ReadStruct(mmh))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(mmh))
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
bool UnpackMMCMP(std::vector<ContainerItem> &containerItems, FileReader &file, ContainerLoadingFlags loadFlags)
//-------------------------------------------------------------------------------------------------------------
{
@@ -151,14 +212,23 @@
containerItems.clear();
MMCMPFILEHEADER mfh;
- if(!file.ReadStruct(mfh)) return false;
- if(std::memcmp(mfh.id, "ziRCONia", 8) != 0) return false;
- if(mfh.hdrsize != sizeof(MMCMPHEADER)) return false;
+ if(!file.ReadStruct(mfh))
+ {
+ return false;
+ }
+ if(!ValidateHeader(mfh))
+ {
+ return false;
+ }
MMCMPHEADER mmh;
- if(!file.ReadStruct(mmh)) return false;
- if(mmh.nblocks == 0) return false;
- if(mmh.filesize == 0) return false;
- if(mmh.filesize > 0x80000000) return false;
+ if(!file.ReadStruct(mmh))
+ {
+ return false;
+ }
+ if(!ValidateHeader(mmh))
+ {
+ return false;
+ }
if(loadFlags == ContainerOnlyVerifyHeader)
{
return true;
Index: soundlib/ContainerPP20.cpp
===================================================================
--- soundlib/ContainerPP20.cpp (revision 8886)
+++ soundlib/ContainerPP20.cpp (working copy)
@@ -13,6 +13,7 @@
#include "../common/FileReader.h"
#include "Container.h"
+#include "Sndfile.h"
#include <stdexcept>
@@ -115,6 +116,51 @@
}
+struct PP20header
+{
+ char magic[4]; // "PP20"
+ uint8be dummy[8]; // unknown
+ uint8be efficiency[4];
+};
+
+MPT_BINARY_STRUCT(PP20header, 16)
+
+
+static bool ValidateHeader(const PP20header &hdr)
+//-----------------------------------------------
+{
+ if(std::memcmp(hdr.magic, "PP20", 4) != 0)
+ {
+ return false;
+ }
+ if(hdr.efficiency[0] < 9 || hdr.efficiency[0] > 15
+ || hdr.efficiency[1] < 9 || hdr.efficiency[1] > 15
+ || hdr.efficiency[2] < 9 || hdr.efficiency[2] > 15
+ || hdr.efficiency[3] < 9 || hdr.efficiency[3] > 15)
+ {
+ return false;
+ }
+ return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderPP20(MemoryFileReader file, const uint64 *pfilesize)
+//-----------------------------------------------------------------------------------------------------
+{
+ PP20header hdr;
+ if(!file.ReadStruct(hdr))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(hdr))
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
bool UnpackPP20(std::vector<ContainerItem> &containerItems, FileReader &file, ContainerLoadingFlags loadFlags)
//------------------------------------------------------------------------------------------------------------
{
@@ -121,15 +167,15 @@
file.Rewind();
containerItems.clear();
- if(!file.ReadMagic("PP20")) return false;
- if(!file.CanRead(8)) return false;
- uint8 efficiency[4];
- file.ReadArray(efficiency);
- if(efficiency[0] < 9 || efficiency[0] > 15
- || efficiency[1] < 9 || efficiency[1] > 15
- || efficiency[2] < 9 || efficiency[2] > 15
- || efficiency[3] < 9 || efficiency[3] > 15)
+ PP20header hdr;
+ if(!file.ReadStruct(hdr))
+ {
return false;
+ }
+ if(!ValidateHeader(hdr))
+ {
+ return false;
+ }
if(loadFlags == ContainerOnlyVerifyHeader)
{
return true;
Index: soundlib/ContainerUMX.cpp
===================================================================
--- soundlib/ContainerUMX.cpp (revision 8886)
+++ soundlib/ContainerUMX.cpp (working copy)
@@ -12,11 +12,48 @@
#include "Loaders.h"
#include "UMXTools.h"
#include "Container.h"
+#include "Sndfile.h"
OPENMPT_NAMESPACE_BEGIN
+static bool ValidateHeader(const UMXFileHeader &fileHeader)
+//---------------------------------------------------------
+{
+ if(std::memcmp(fileHeader.magic, "\xC1\x83\x2A\x9E", 4)
+ || fileHeader.nameCount == 0
+ || fileHeader.exportCount == 0
+ || fileHeader.importCount == 0
+ )
+ {
+ return false;
+ }
+ return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderUMX(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ UMXFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ if(!FindUMXNameTableEntryMemory(file, fileHeader, "music"))
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
bool UnpackUMX(std::vector<ContainerItem> &containerItems, FileReader &file, ContainerLoadingFlags loadFlags)
//-----------------------------------------------------------------------------------------------------------
{
@@ -24,15 +61,14 @@
containerItems.clear();
UMXFileHeader fileHeader;
- if(!file.ReadStruct(fileHeader)
- || memcmp(fileHeader.magic, "\xC1\x83\x2A\x9E", 4)
- || fileHeader.nameCount == 0
- || fileHeader.exportCount == 0
- || fileHeader.importCount == 0
- )
+ if(!file.ReadStruct(fileHeader))
{
return false;
}
+ if(!ValidateHeader(fileHeader))
+ {
+ return false;
+ }
// Note that this can be a false positive, e.g. Unreal maps will have music and sound
// in their name table because they usually import such files. However, it spares us
Index: soundlib/ContainerXPK.cpp
===================================================================
--- soundlib/ContainerXPK.cpp (revision 8886)
+++ soundlib/ContainerXPK.cpp (working copy)
@@ -13,6 +13,7 @@
#include "../common/FileReader.h"
#include "Container.h"
+#include "Sndfile.h"
#include <stdexcept>
@@ -329,6 +330,68 @@
}
+static bool ValidateHeader(const XPKFILEHEADER &header)
+//-----------------------------------------------------
+{
+ if(std::memcmp(header.XPKF, "XPKF", 4) != 0)
+ {
+ return false;
+ }
+ if(std::memcmp(header.SQSH, "SQSH", 4) != 0)
+ {
+ return false;
+ }
+ if(header.SrcLen == 0)
+ {
+ return false;
+ }
+ if(header.DstLen == 0)
+ {
+ return false;
+ }
+ STATIC_ASSERT(sizeof(XPKFILEHEADER) >= 8);
+ if(header.SrcLen < (sizeof(XPKFILEHEADER) - 8))
+ {
+ return false;
+ }
+ return true;
+}
+
+
+static bool ValidateHeaderFileSize(const XPKFILEHEADER &header, uint64 filesize)
+//------------------------------------------------------------------------------
+{
+ if(filesize != header.SrcLen - 8)
+ {
+ return false;
+ }
+ return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderXPK(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ XPKFILEHEADER header;
+ if(!file.ReadStruct(header))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(header))
+ {
+ return ProbeFailure;
+ }
+ if(pfilesize)
+ {
+ if(!ValidateHeaderFileSize(header, *pfilesize))
+ {
+ return ProbeFailure;
+ }
+ }
+ return ProbeSuccess;
+}
+
+
bool UnpackXPK(std::vector<ContainerItem> &containerItems, FileReader &file, ContainerLoadingFlags loadFlags)
//-----------------------------------------------------------------------------------------------------------
{
@@ -336,19 +399,24 @@
containerItems.clear();
XPKFILEHEADER header;
- if(!file.ReadStruct(header)) return false;
- if(std::memcmp(header.XPKF, "XPKF", 4) != 0) return false;
- if(std::memcmp(header.SQSH, "SQSH", 4) != 0) return false;
- if(header.SrcLen == 0) return false;
- if(header.DstLen == 0) return false;
- STATIC_ASSERT(sizeof(XPKFILEHEADER) >= 8);
- if(header.SrcLen < (sizeof(XPKFILEHEADER) - 8)) return false;
+ if(!file.ReadStruct(header))
+ {
+ return false;
+ }
+ if(!ValidateHeader(header))
+ {
+ return false;
+ }
if(loadFlags == ContainerOnlyVerifyHeader)
{
return true;
}
- if(!file.CanRead(header.SrcLen - (sizeof(XPKFILEHEADER) - 8))) return false;
+ if(!file.CanRead(header.SrcLen - (sizeof(XPKFILEHEADER) - 8)))
+ {
+ return false;
+ }
+
containerItems.emplace_back();
containerItems.back().data_cache = mpt::make_unique<std::vector<char> >();
std::vector<char> & unpackedData = *(containerItems.back().data_cache);
Index: soundlib/Load_669.cpp
===================================================================
--- soundlib/Load_669.cpp (revision 8886)
+++ soundlib/Load_669.cpp (working copy)
@@ -62,14 +62,9 @@
MPT_BINARY_STRUCT(_669Sample, 25)
-bool CSoundFile::Read669(FileReader &file, ModLoadingFlags loadFlags)
-//-------------------------------------------------------------------
+static bool ValidateHeader(const _669FileHeader &fileHeader)
{
- _669FileHeader fileHeader;
-
- file.Rewind();
- if(!file.ReadStruct(fileHeader)
- || (memcmp(fileHeader.magic, "if", 2) && memcmp(fileHeader.magic, "JN", 2))
+ if((std::memcmp(fileHeader.magic, "if", 2) && std::memcmp(fileHeader.magic, "JN", 2))
|| fileHeader.samples > 64
|| fileHeader.restartPos >= 128
|| fileHeader.patterns > 128)
@@ -76,21 +71,68 @@
{
return false;
}
-
- for(size_t i = 0; i < CountOf(fileHeader.breaks); i++)
+ for(std::size_t i = 0; i < CountOf(fileHeader.breaks); i++)
{
if(fileHeader.orders[i] >= 128 && fileHeader.orders[i] < 0xFE)
+ {
return false;
+ }
if(fileHeader.orders[i] < 128 && fileHeader.tempoList[i] == 0)
+ {
return false;
+ }
if(fileHeader.breaks[i] >= 64)
+ {
return false;
+ }
}
+ return true;
+}
+
+static uint64 GetHeaderMinimumAdditionalSize(const _669FileHeader &fileHeader)
+//----------------------------------------------------------------------------
+{
+ return fileHeader.samples * sizeof(_669Sample) + fileHeader.patterns * 1536u;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeader669(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ _669FileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader));
+}
+
+
+bool CSoundFile::Read669(FileReader &file, ModLoadingFlags loadFlags)
+//-------------------------------------------------------------------
+{
+ _669FileHeader fileHeader;
+
+ file.Rewind();
+ if(!file.ReadStruct(fileHeader))
+ {
+ return false;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return false;
+ }
if(loadFlags == onlyVerifyHeader)
{
return true;
- } else if(!file.CanRead(fileHeader.samples * sizeof(_669Sample) + fileHeader.patterns * 1536u))
+ }
+
+ if(!file.CanRead(GetHeaderMinimumAdditionalSize(fileHeader)))
{
return false;
}
Index: soundlib/Load_amf.cpp
===================================================================
--- soundlib/Load_amf.cpp (revision 8886)
+++ soundlib/Load_amf.cpp (working copy)
@@ -80,6 +80,42 @@
MPT_BINARY_STRUCT(AMFFileHeader, 41)
+static bool ValidateHeader(const AsylumFileHeader &fileHeader)
+//------------------------------------------------------------
+{
+ if(std::memcmp(fileHeader.signature, "ASYLUM Music Format V1.0\0", 25)
+ || fileHeader.numSamples > 64
+ )
+ {
+ return false;
+ }
+ return true;
+}
+
+
+static uint64 GetHeaderMinimumAdditionalSize(const AsylumFileHeader &fileHeader)
+//------------------------------------------------------------------------------
+{
+ return 256 + 64 * sizeof(AsylumSampleHeader) + 64 * 4 * 8 * fileHeader.numPatterns;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderAMF_Asylum(MemoryFileReader file, const uint64 *pfilesize)
+//-----------------------------------------------------------------------------------------------------------
+{
+ AsylumFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader));
+}
+
+
bool CSoundFile::ReadAMF_Asylum(FileReader &file, ModLoadingFlags loadFlags)
//--------------------------------------------------------------------------
{
@@ -86,14 +122,16 @@
file.Rewind();
AsylumFileHeader fileHeader;
- if(!file.ReadStruct(fileHeader)
- || memcmp(fileHeader.signature, "ASYLUM Music Format V1.0\0", 25)
- || fileHeader.numSamples > 64
- || !file.CanRead(256 + 64 * sizeof(AsylumSampleHeader) + 64 * 4 * 8 * fileHeader.numPatterns))
+ if(!file.ReadStruct(fileHeader))
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(fileHeader))))
{
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
@@ -341,6 +379,37 @@
}
+static bool ValidateHeader(const AMFFileHeader &fileHeader)
+//---------------------------------------------------------
+{
+ if(std::memcmp(fileHeader.amf, "AMF", 3)
+ || fileHeader.version < 8 || fileHeader.version > 14
+ || ((fileHeader.numChannels < 1 || fileHeader.numChannels > 32) && fileHeader.version >= 10)
+ )
+ {
+ return false;
+ }
+ return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderAMF_DSMI(MemoryFileReader file, const uint64 *pfilesize)
+//---------------------------------------------------------------------------------------------------------
+{
+ AMFFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
bool CSoundFile::ReadAMF_DSMI(FileReader &file, ModLoadingFlags loadFlags)
//------------------------------------------------------------------------
{
@@ -347,14 +416,16 @@
file.Rewind();
AMFFileHeader fileHeader;
- if(!file.ReadStruct(fileHeader)
- || memcmp(fileHeader.amf, "AMF", 3)
- || fileHeader.version < 8 || fileHeader.version > 14
- || ((fileHeader.numChannels < 1 || fileHeader.numChannels > 32) && fileHeader.version >= 10))
+ if(!file.ReadStruct(fileHeader))
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ if(!ValidateHeader(fileHeader))
{
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
Index: soundlib/Load_ams.cpp
===================================================================
--- soundlib/Load_ams.cpp (revision 8886)
+++ soundlib/Load_ams.cpp (working copy)
@@ -332,21 +332,76 @@
MPT_BINARY_STRUCT(AMSSampleHeader, 17)
+static bool ValidateHeader(const AMSFileHeader &fileHeader)
+//---------------------------------------------------------
+{
+ if(fileHeader.versionHigh != 0x01)
+ {
+ return false;
+ }
+ return true;
+}
+
+
+static uint64 GetHeaderMinimumAdditionalSize(const AMSFileHeader &fileHeader)
+//---------------------------------------------------------------------------
+{
+ return fileHeader.extraSize + 3u + fileHeader.numSamps * (1u + sizeof(AMSSampleHeader)) + fileHeader.numOrds * 2u + fileHeader.numPats * 4u;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderAMS(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ if(!file.CanRead(7))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!file.ReadMagic("Extreme"))
+ {
+ return ProbeFailure;
+ }
+ AMSFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader));
+}
+
+
bool CSoundFile::ReadAMS(FileReader &file, ModLoadingFlags loadFlags)
//-------------------------------------------------------------------
{
file.Rewind();
+ if(!file.ReadMagic("Extreme"))
+ {
+ return false;
+ }
AMSFileHeader fileHeader;
- if(!file.ReadMagic("Extreme")
- || !file.ReadStruct(fileHeader)
- || !file.Skip(fileHeader.extraSize)
- || !file.CanRead(3u + fileHeader.numSamps * (1u + sizeof(AMSSampleHeader)) + fileHeader.numOrds * 2u + fileHeader.numPats * 4u)
- || fileHeader.versionHigh != 0x01)
+ if(!file.ReadStruct(fileHeader))
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ if(!ValidateHeader(fileHeader))
{
+ return false;
+ }
+ if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(fileHeader))))
+ {
+ return false;
+ }
+ if(!file.Skip(fileHeader.extraSize))
+ {
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
@@ -641,30 +696,90 @@
MPT_BINARY_STRUCT(AMS2Description, 11)
+static bool ValidateHeader(const AMS2FileHeader &fileHeader)
+//----------------------------------------------------------
+{
+ if(fileHeader.versionHigh != 2 || fileHeader.versionLow > 2)
+ {
+ return false;
+ }
+ return true;
+}
+
+
+static uint64 GetHeaderMinimumAdditionalSize(const AMS2FileHeader &fileHeader)
+//----------------------------------------------------------------------------
+{
+ return 36u + sizeof(AMS2Description) + fileHeader.numIns * 2u + fileHeader.numOrds * 2u + fileHeader.numPats * 4u;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderAMS2(MemoryFileReader file, const uint64 *pfilesize)
+//-----------------------------------------------------------------------------------------------------
+{
+ if(!file.CanRead(7))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!file.ReadMagic("AMShdr\x1A"))
+ {
+ return ProbeFailure;
+ }
+ if(!file.CanRead(1))
+ {
+ return ProbeWantMoreData;
+ }
+ const uint8 songNameLength = file.ReadUint8();
+ if(!file.Skip(songNameLength))
+ {
+ return ProbeWantMoreData;
+ }
+ AMS2FileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader));
+}
+
+
bool CSoundFile::ReadAMS2(FileReader &file, ModLoadingFlags loadFlags)
//--------------------------------------------------------------------
{
file.Rewind();
- AMS2FileHeader fileHeader;
if(!file.ReadMagic("AMShdr\x1A"))
{
return false;
}
-
- InitializeGlobals(MOD_TYPE_AMS2);
-
- if(!file.ReadSizedString<uint8le, mpt::String::spacePadded>(m_songName)
- || !file.ReadStruct(fileHeader)
- || fileHeader.versionHigh != 2 || fileHeader.versionLow > 2
- || !file.CanRead(36u + sizeof(AMS2Description) + fileHeader.numIns * 2u + fileHeader.numOrds * 2u + fileHeader.numPats * 4u))
+ if(!file.ReadSizedString<uint8le, mpt::String::spacePadded>(m_songName))
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ AMS2FileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
{
+ return false;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return false;
+ }
+ if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(fileHeader))))
+ {
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
+ InitializeGlobals(MOD_TYPE_AMS2);
+
m_nInstruments = fileHeader.numIns;
m_nChannels = 32;
SetupMODPanning(true);
Index: soundlib/Load_dbm.cpp
===================================================================
--- soundlib/Load_dbm.cpp (revision 8886)
+++ soundlib/Load_dbm.cpp (working copy)
@@ -293,19 +293,51 @@
}
+static bool ValidateHeader(const DBMFileHeader &fileHeader)
+//---------------------------------------------------------
+{
+ if(std::memcmp(fileHeader.dbm0, "DBM0", 4)
+ || fileHeader.trkVerHi > 3)
+ {
+ return false;
+ }
+ return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderDBM(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ DBMFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
bool CSoundFile::ReadDBM(FileReader &file, ModLoadingFlags loadFlags)
//-------------------------------------------------------------------
{
- DBMFileHeader fileHeader;
file.Rewind();
- if(!file.ReadStruct(fileHeader)
- || memcmp(fileHeader.dbm0, "DBM0", 4)
- || fileHeader.trkVerHi > 3)
+ DBMFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ if(!ValidateHeader(fileHeader))
{
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
Index: soundlib/Load_digi.cpp
===================================================================
--- soundlib/Load_digi.cpp (revision 8886)
+++ soundlib/Load_digi.cpp (working copy)
@@ -73,6 +73,36 @@
}
+static bool ValidateHeader(const DIGIFileHeader &fileHeader)
+{
+ if(std::memcmp(fileHeader.signature, "DIGI Booster module\0", 20)
+ || !fileHeader.numChannels
+ || fileHeader.numChannels > 8
+ || fileHeader.lastOrdIndex > 127)
+ {
+ return false;
+ }
+ return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderDIGI(MemoryFileReader file, const uint64 *pfilesize)
+//-----------------------------------------------------------------------------------------------------
+{
+ DIGIFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
bool CSoundFile::ReadDIGI(FileReader &file, ModLoadingFlags loadFlags)
//--------------------------------------------------------------------
{
@@ -79,15 +109,16 @@
file.Rewind();
DIGIFileHeader fileHeader;
- if(!file.ReadStruct(fileHeader)
- || memcmp(fileHeader.signature, "DIGI Booster module\0", 20)
- || !fileHeader.numChannels
- || fileHeader.numChannels > 8
- || fileHeader.lastOrdIndex > 127)
+ if(!file.ReadStruct(fileHeader))
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ if(!ValidateHeader(fileHeader))
{
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
Index: soundlib/Load_dmf.cpp
===================================================================
--- soundlib/Load_dmf.cpp (revision 8886)
+++ soundlib/Load_dmf.cpp (working copy)
@@ -887,18 +887,51 @@
}
+static bool ValidateHeader(const DMFFileHeader &fileHeader)
+//---------------------------------------------------------
+{
+ if(std::memcmp(fileHeader.signature, "DDMF", 4)
+ || !fileHeader.version || fileHeader.version > 10)
+ {
+ return false;
+ }
+ return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderDMF(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ DMFFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
bool CSoundFile::ReadDMF(FileReader &file, ModLoadingFlags loadFlags)
//-------------------------------------------------------------------
{
+ file.Rewind();
+
DMFFileHeader fileHeader;
- file.Rewind();
- if(!file.ReadStruct(fileHeader)
- || memcmp(fileHeader.signature, "DDMF", 4)
- || !fileHeader.version || fileHeader.version > 10)
+ if(!file.ReadStruct(fileHeader))
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ if(!ValidateHeader(fileHeader))
{
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
Index: soundlib/Load_dsm.cpp
===================================================================
--- soundlib/Load_dsm.cpp (revision 8886)
+++ soundlib/Load_dsm.cpp (working copy)
@@ -100,40 +100,100 @@
MPT_BINARY_STRUCT(DSMSampleHeader, 64)
-bool CSoundFile::ReadDSM(FileReader &file, ModLoadingFlags loadFlags)
-//-------------------------------------------------------------------
+struct DSMHeader
{
- file.Rewind();
+ char fileMagic0[4];
+ char fileMagic1[4];
+ char fileMagic2[4];
+};
- char fileMagic0[4], fileMagic1[4], fileMagic2[4];
- if(!file.ReadArray(fileMagic0)) return false;
- if(!file.ReadArray(fileMagic1)) return false;
- if(!file.ReadArray(fileMagic2)) return false;
+MPT_BINARY_STRUCT(DSMHeader, 12)
- if(!memcmp(fileMagic0, "RIFF", 4)
- && !memcmp(fileMagic2, "DSMF", 4))
+
+static bool ValidateHeader(const DSMHeader &fileHeader)
+//-----------------------------------------------------
+{
+ if(!std::memcmp(fileHeader.fileMagic0, "RIFF", 4)
+ && !std::memcmp(fileHeader.fileMagic2, "DSMF", 4))
{
// "Normal" DSM files with RIFF header
// <RIFF> <file size> <DSMF>
- } else if(!memcmp(fileMagic0, "DSMF", 4))
+ return true;
+ } else if(!std::memcmp(fileHeader.fileMagic0, "DSMF", 4))
{
// DSM files with alternative header
// <DSMF> <4 bytes, usually 4x NUL or RIFF> <file size> <4 bytes, usually DSMF but not always>
- file.Skip(4);
+ return true;
} else
{
return false;
}
+}
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderDSM(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ DSMHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ if(std::memcmp(fileHeader.fileMagic0, "DSMF", 4) == 0)
+ {
+ if(!file.Skip(4))
+ {
+ return ProbeWantMoreData;
+ }
+ }
DSMChunk chunkHeader;
+ if(!file.ReadStruct(chunkHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(std::memcmp(chunkHeader.magic, "SONG", 4))
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
- file.ReadStruct(chunkHeader);
+
+bool CSoundFile::ReadDSM(FileReader &file, ModLoadingFlags loadFlags)
+//-------------------------------------------------------------------
+{
+ file.Rewind();
+
+ DSMHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return false;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return false;
+ }
+ if(std::memcmp(fileHeader.fileMagic0, "DSMF", 4) == 0)
+ {
+ file.Skip(4);
+ }
+ DSMChunk chunkHeader;
+ if(!file.ReadStruct(chunkHeader))
+ {
+ return false;
+ }
// Technically, the song chunk could be anywhere in the file, but we're going to simplify
// things by not using a chunk header here and just expect it to be right at the beginning.
- if(memcmp(chunkHeader.magic, "SONG", 4))
+ if(std::memcmp(chunkHeader.magic, "SONG", 4))
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ if(loadFlags == onlyVerifyHeader)
{
return true;
}
Index: soundlib/Load_dtm.cpp
===================================================================
--- soundlib/Load_dtm.cpp (revision 8886)
+++ soundlib/Load_dtm.cpp (working copy)
@@ -181,6 +181,37 @@
MPT_BINARY_STRUCT(DTMText, 12)
+static bool ValidateHeader(const DTMFileHeader &fileHeader)
+//---------------------------------------------------------
+{
+ if(std::memcmp(fileHeader.magic, "D.T.", 4)
+ || fileHeader.headerSize < sizeof(fileHeader) - 8u
+ || fileHeader.headerSize > 256 // Excessively long song title?
+ || fileHeader.type != 0)
+ {
+ return false;
+ }
+ return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderDTM(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ DTMFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
bool CSoundFile::ReadDTM(FileReader &file, ModLoadingFlags loadFlags)
//-------------------------------------------------------------------
{
@@ -187,15 +218,16 @@
file.Rewind();
DTMFileHeader fileHeader;
- if(!file.ReadStruct(fileHeader)
- || memcmp(fileHeader.magic, "D.T.", 4)
- || fileHeader.headerSize < sizeof(fileHeader) - 8u
- || fileHeader.headerSize > 256 // Excessively long song title?
- || fileHeader.type != 0)
+ if(!file.ReadStruct(fileHeader))
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ if(!ValidateHeader(fileHeader))
{
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
Index: soundlib/Load_far.cpp
===================================================================
--- soundlib/Load_far.cpp (revision 8886)
+++ soundlib/Load_far.cpp (working copy)
@@ -102,6 +102,46 @@
MPT_BINARY_STRUCT(FARSampleHeader, 48)
+static bool ValidateHeader(const FARFileHeader &fileHeader)
+//---------------------------------------------------------
+{
+ if(std::memcmp(fileHeader.magic, "FAR\xFE", 4) != 0
+ || std::memcmp(fileHeader.eof, "\x0D\x0A\x1A", 3)
+ )
+ {
+ return false;
+ }
+ if(fileHeader.headerLength < sizeof(FARFileHeader))
+ {
+ return false;
+ }
+ return true;
+}
+
+
+static uint64 GetHeaderMinimumAdditionalSize(const FARFileHeader &fileHeader)
+//---------------------------------------------------------------------------
+{
+ return fileHeader.headerLength - sizeof(FARFileHeader);
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderFAR(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ FARFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader));
+}
+
+
bool CSoundFile::ReadFAR(FileReader &file, ModLoadingFlags loadFlags)
//-------------------------------------------------------------------
{
@@ -108,14 +148,20 @@
file.Rewind();
FARFileHeader fileHeader;
- if(!file.ReadStruct(fileHeader)
- || memcmp(fileHeader.magic, "FAR\xFE", 4) != 0
- || memcmp(fileHeader.eof, "\x0D\x0A\x1A", 3)
- || !file.LengthIsAtLeast(fileHeader.headerLength))
+ if(!file.ReadStruct(fileHeader))
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ if(!ValidateHeader(fileHeader))
{
+ return false;
+ }
+ if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(fileHeader))))
+ {
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
Index: soundlib/Load_gdm.cpp
===================================================================
--- soundlib/Load_gdm.cpp (revision 8886)
+++ soundlib/Load_gdm.cpp (working copy)
@@ -90,28 +90,61 @@
MPT_BINARY_STRUCT(GDMSampleHeader, 62)
-bool CSoundFile::ReadGDM(FileReader &file, ModLoadingFlags loadFlags)
-//-------------------------------------------------------------------
+static const MODTYPE gdmFormatOrigin[] =
{
- file.Rewind();
+ MOD_TYPE_NONE, MOD_TYPE_MOD, MOD_TYPE_MTM, MOD_TYPE_S3M, MOD_TYPE_669, MOD_TYPE_FAR, MOD_TYPE_ULT, MOD_TYPE_STM, MOD_TYPE_MED, MOD_TYPE_PSM
+};
- const MODTYPE gdmFormatOrigin[] =
- {
- MOD_TYPE_NONE, MOD_TYPE_MOD, MOD_TYPE_MTM, MOD_TYPE_S3M, MOD_TYPE_669, MOD_TYPE_FAR, MOD_TYPE_ULT, MOD_TYPE_STM, MOD_TYPE_MED, MOD_TYPE_PSM
- };
- GDMFileHeader fileHeader;
- if(!file.ReadStruct(fileHeader)
- || memcmp(fileHeader.magic, "GDM\xFE", 4)
+static bool ValidateHeader(const GDMFileHeader &fileHeader)
+//---------------------------------------------------------
+{
+ if(std::memcmp(fileHeader.magic, "GDM\xFE", 4)
|| fileHeader.dosEOF[0] != 13 || fileHeader.dosEOF[1] != 10 || fileHeader.dosEOF[2] != 26
- || memcmp(fileHeader.magic2, "GMFS", 4)
+ || std::memcmp(fileHeader.magic2, "GMFS", 4)
|| fileHeader.formatMajorVer != 1 || fileHeader.formatMinorVer != 0
- || fileHeader.originalFormat >= CountOf(gdmFormatOrigin)
+ || fileHeader.originalFormat >= mpt::size(gdmFormatOrigin)
|| fileHeader.originalFormat == 0)
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderGDM(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ GDMFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
{
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
+bool CSoundFile::ReadGDM(FileReader &file, ModLoadingFlags loadFlags)
+//-------------------------------------------------------------------
+{
+ file.Rewind();
+
+ GDMFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return false;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
Index: soundlib/Load_imf.cpp
===================================================================
--- soundlib/Load_imf.cpp (revision 8886)
+++ soundlib/Load_imf.cpp (working copy)
@@ -351,19 +351,84 @@
}
}
+
+static bool ValidateHeader(const IMFFileHeader &fileHeader)
+//---------------------------------------------------------
+{
+ if(std::memcmp(fileHeader.im10, "IM10", 4)
+ || fileHeader.ordNum > 256
+ || fileHeader.insNum >= MAX_INSTRUMENTS
+ )
+ {
+ return false;
+ }
+ bool channelFound = false;
+ for(uint8 chn = 0; chn < 32; chn++)
+ {
+ switch(fileHeader.channels[chn].status)
+ {
+ case 0: // enabled; don't worry about it
+ channelFound = true;
+ break;
+ case 1: // mute
+ channelFound = true;
+ break;
+ case 2: // disabled
+ // nothing
+ break;
+ default: // uhhhh.... freak out
+ return false;
+ }
+ }
+ if(!channelFound)
+ {
+ return false;
+ }
+ return true;
+}
+
+
+static uint64 GetHeaderMinimumAdditionalSize(const IMFFileHeader &fileHeader)
+//---------------------------------------------------------------------------
+{
+ MPT_UNREFERENCED_PARAMETER(fileHeader);
+ return 256;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderIMF(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ IMFFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader));
+}
+
+
bool CSoundFile::ReadIMF(FileReader &file, ModLoadingFlags loadFlags)
//-------------------------------------------------------------------
{
IMFFileHeader fileHeader;
file.Rewind();
- if(!file.ReadStruct(fileHeader)
- || memcmp(fileHeader.im10, "IM10", 4)
- || fileHeader.ordNum > 256
- || fileHeader.insNum >= MAX_INSTRUMENTS
- || !file.CanRead(256))
+ if(!file.ReadStruct(fileHeader))
{
return false;
}
+ if(!ValidateHeader(fileHeader))
+ {
+ return false;
+ }
+ if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(fileHeader))))
+ {
+ return false;
+ }
// Read channel configuration
std::bitset<32> ignoreChannels; // bit set for each channel that's completely disabled
@@ -397,7 +462,9 @@
if(!detectedChannels)
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+
+ if(loadFlags == onlyVerifyHeader)
{
return true;
}
Index: soundlib/Load_it.cpp
===================================================================
--- soundlib/Load_it.cpp (revision 8886)
+++ soundlib/Load_it.cpp (working copy)
@@ -402,6 +402,43 @@
}
+static bool ValidateHeader(const ITFileHeader &fileHeader)
+//--------------------------------------------------------
+{
+ if((std::memcmp(fileHeader.id, "IMPM", 4) && std::memcmp(fileHeader.id, "tpm.", 4))
+ || fileHeader.insnum > 0xFF
+ || fileHeader.smpnum >= MAX_SAMPLES
+ )
+ {
+ return false;
+ }
+ return true;
+}
+
+
+static uint64 GetHeaderMinimumAdditionalSize(const ITFileHeader &fileHeader)
+//--------------------------------------------------------------------------
+{
+ return fileHeader.ordnum + (fileHeader.insnum + fileHeader.smpnum + fileHeader.patnum) * 4;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderIT(MemoryFileReader file, const uint64 *pfilesize)
+//---------------------------------------------------------------------------------------------------
+{
+ ITFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader));
+}
+
+
bool CSoundFile::ReadIT(FileReader &file, ModLoadingFlags loadFlags)
//------------------------------------------------------------------
{
@@ -408,15 +445,20 @@
file.Rewind();
ITFileHeader fileHeader;
- if(!file.ReadStruct(fileHeader)
- || (memcmp(fileHeader.id, "IMPM", 4) && memcmp(fileHeader.id, "tpm.", 4))
- || fileHeader.insnum > 0xFF
- || fileHeader.smpnum >= MAX_SAMPLES
- || !file.CanRead(fileHeader.ordnum + (fileHeader.insnum + fileHeader.smpnum + fileHeader.patnum) * 4))
+ if(!file.ReadStruct(fileHeader))
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ if(!ValidateHeader(fileHeader))
{
+ return false;
+ }
+ if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(fileHeader))))
+ {
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
Index: soundlib/Load_itp.cpp
===================================================================
--- soundlib/Load_itp.cpp (revision 8886)
+++ soundlib/Load_itp.cpp (working copy)
@@ -60,6 +60,54 @@
MPT_BINARY_STRUCT(ITPModCommand, 6)
+struct ITPHeader
+{
+ uint32le magic;
+ uint32le version;
+};
+
+MPT_BINARY_STRUCT(ITPHeader, 8)
+
+
+static bool ValidateHeader(const ITPHeader &hdr)
+//----------------------------------------------
+{
+ if(hdr.magic != MAGIC4BE('.','i','t','p'))
+ {
+ return false;
+ }
+ if(hdr.version > 0x00000103 || hdr.version < 0x00000100)
+ {
+ return false;
+ }
+ return true;
+}
+
+
+static uint64 GetHeaderMinimumAdditionalSize(const ITPHeader &hdr)
+//----------------------------------------------------------------
+{
+ MPT_UNREFERENCED_PARAMETER(hdr);
+ return 12 + 4 + 24 + 4 - sizeof(ITPHeader);
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderITP(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ ITPHeader hdr;
+ if(!file.ReadStruct(hdr))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(hdr))
+ {
+ return ProbeFailure;
+ }
+ return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(hdr));
+}
+
+
bool CSoundFile::ReadITProject(FileReader &file, ModLoadingFlags loadFlags)
//-------------------------------------------------------------------------
{
@@ -81,22 +129,29 @@
ITP_ITPEMBEDIH = 0x40000, // Embed instrument headers in project file
};
- uint32 version, size;
-
file.Rewind();
- // Check file ID
- if(!file.CanRead(12 + 4 + 24 + 4)
- || file.ReadUint32LE() != MAGIC4BE('.','i','t','p') // Magic bytes
- || (version = file.ReadUint32LE()) > 0x00000103 // Format version
- || version < 0x00000100)
+ ITPHeader hdr;
+ if(!file.ReadStruct(hdr))
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ if(!ValidateHeader(hdr))
{
+ return false;
+ }
+ if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(hdr))))
+ {
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
+ uint32 version, size;
+ version = hdr.version;
+
InitializeGlobals(MOD_TYPE_IT);
m_playBehaviour.reset();
file.ReadSizedString<uint32le, mpt::String::maybeNullTerminated>(m_songName);
Index: soundlib/Load_mdl.cpp
===================================================================
--- soundlib/Load_mdl.cpp (revision 8886)
+++ soundlib/Load_mdl.cpp (working copy)
@@ -422,18 +422,50 @@
}
+static bool ValidateHeader(const MDLFileHeader &fileHeader)
+//---------------------------------------------------------
+{
+ if(std::memcmp(fileHeader.id, "DMDL", 4)
+ || fileHeader.version >= 0x20)
+ {
+ return false;
+ }
+ return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderMDL(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ MDLFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
bool CSoundFile::ReadMDL(FileReader &file, ModLoadingFlags loadFlags)
//-------------------------------------------------------------------
{
file.Rewind();
MDLFileHeader fileHeader;
- if(!file.ReadStruct(fileHeader)
- || memcmp(fileHeader.id, "DMDL", 4)
- || fileHeader.version >= 0x20)
+ if(!file.ReadStruct(fileHeader))
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ if(!ValidateHeader(fileHeader))
{
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
Index: soundlib/Load_med.cpp
===================================================================
--- soundlib/Load_med.cpp (revision 8886)
+++ soundlib/Load_med.cpp (working copy)
@@ -493,22 +493,68 @@
}
+static bool ValidateHeader(const MEDMODULEHEADER &pmmh)
+//-----------------------------------------------------
+{
+ if(std::memcmp(pmmh.id, "MMD", 3)
+ || pmmh.id[3] < '0' || pmmh.id[3] > '3'
+ || pmmh.song == 0
+ )
+ {
+ return false;
+ }
+ return true;
+}
+
+
+static uint64 GetHeaderMinimumAdditionalSize(const MEDMODULEHEADER &pmmh)
+//-----------------------------------------------------------------------
+{
+ MPT_UNREFERENCED_PARAMETER(pmmh);
+ return sizeof(MMD0SONGHEADER);
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderMED(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ MEDMODULEHEADER pmmh;
+ if(!file.ReadStruct(pmmh))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(pmmh))
+ {
+ return ProbeFailure;
+ }
+ return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(pmmh));
+}
+
+
bool CSoundFile::ReadMed(FileReader &file, ModLoadingFlags loadFlags)
//------------------------------------------------------------------
{
file.Rewind();
MEDMODULEHEADER pmmh;
- uint32 dwSong;
- if(!file.CanRead(512)
- || !file.ReadStruct(pmmh)
- || memcmp(pmmh.id, "MMD", 3)
- || pmmh.id[3] < '0' || pmmh.id[3] > '3'
- || (dwSong = pmmh.song) == 0
- || !file.LengthIsAtLeast(dwSong + sizeof(MMD0SONGHEADER)))
+ if(!file.ReadStruct(pmmh))
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ if(!ValidateHeader(pmmh))
{
+ return false;
+ }
+ if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(pmmh))))
+ {
+ return false;
+ }
+ const uint32 dwSong = pmmh.song;
+ if(!file.LengthIsAtLeast(dwSong + sizeof(MMD0SONGHEADER)))
+ {
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
Index: soundlib/Load_mo3.cpp
===================================================================
--- soundlib/Load_mo3.cpp (revision 8886)
+++ soundlib/Load_mo3.cpp (working copy)
@@ -691,26 +691,74 @@
#endif // MPT_WITH_VORBIS && MPT_WITH_VORBISFILE
+struct MO3ContainerHeader
+{
+ char magic[3]; // MO3
+ uint8le version;
+ uint32le musicSize;
+};
+MPT_BINARY_STRUCT(MO3ContainerHeader, 8)
+
+
+static bool ValidateHeader(const MO3ContainerHeader &containerHeader)
+//-------------------------------------------------------------------
+{
+ if(std::memcmp(containerHeader.magic, "MO3", 3))
+ {
+ return false;
+ }
+ if(containerHeader.musicSize <= sizeof(MO3FileHeader))
+ {
+ return false;
+ }
+ if(containerHeader.version > 5)
+ {
+ return false;
+ }
+ return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderMO3(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ MO3ContainerHeader containerHeader;
+ if(!file.ReadStruct(containerHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(containerHeader))
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
bool CSoundFile::ReadMO3(FileReader &file, ModLoadingFlags loadFlags)
//-------------------------------------------------------------------
{
file.Rewind();
- if(!file.CanRead(12) || !file.ReadMagic("MO3"))
+ MO3ContainerHeader containerHeader;
+ if(!file.ReadStruct(containerHeader))
{
return false;
}
- const uint8 version = file.ReadUint8();
- const uint32 musicSize = file.ReadUint32LE();
- if(musicSize <= sizeof(MO3FileHeader) || version > 5)
+ if(!ValidateHeader(containerHeader))
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ if(loadFlags == onlyVerifyHeader)
{
return true;
}
+ const uint8 version = containerHeader.version;
+ const uint32 musicSize = containerHeader.musicSize;
+
uint32 compressedSize = uint32_max;
if(version >= 5)
{
Index: soundlib/Load_mod.cpp
===================================================================
--- soundlib/Load_mod.cpp (revision 8886)
+++ soundlib/Load_mod.cpp (working copy)
@@ -653,20 +653,20 @@
}
-bool CSoundFile::ReadMod(FileReader &file, ModLoadingFlags loadFlags)
-//-------------------------------------------------------------------
+struct MODMagicResult
{
- char magic[4];
- if(!file.Seek(1080) || !file.ReadArray(magic))
- {
- return false;
- }
+ CHANNELINDEX m_nChannels = 4;
+ mpt::ustring m_madeWithTracker = mpt::ustring();
+ bool isNoiseTracker = false;
+ bool isStartrekker = false;
+ bool isGenericMultiChannel = false;
+ bool setMODVBlankTiming = false;
+};
- InitializeGlobals(MOD_TYPE_MOD);
- m_nChannels = 4;
- bool isNoiseTracker = false, isStartrekker = false, isGenericMultiChannel = false;
- // Check MOD Magic
+static bool CheckMODMagic(const char magic[4], MODMagicResult *result)
+{
+ MODMagicResult *r = result;
if(IsMagic(magic, "M.K.") // ProTracker and compatible
|| IsMagic(magic, "M!K!") // ProTracker (>64 patterns)
|| IsMagic(magic, "PATT") // ProTracker 3.6
@@ -673,66 +673,143 @@
|| IsMagic(magic, "NSMS") // kingdomofpleasure.mod by bee hunter
|| IsMagic(magic, "LARD")) // judgement_day_gvine.mod by 4-mat
{
- m_nChannels = 4;
- m_madeWithTracker = MPT_USTRING("Generic ProTracker or compatible");
+ if(r)
+ {
+ r->m_nChannels = 4;
+ r->m_madeWithTracker = MPT_USTRING("Generic ProTracker or compatible");
+ }
} else if(IsMagic(magic, "M&K!") // "His Master's Noise" musicdisk
|| IsMagic(magic, "FEST") // "His Master's Noise" musicdisk
|| IsMagic(magic, "N.T."))
{
- m_nChannels = 4;
- m_madeWithTracker = MPT_USTRING("NoiseTracker");
- isNoiseTracker = true;
+ if(r)
+ {
+ r->m_nChannels = 4;
+ r->m_madeWithTracker = MPT_USTRING("NoiseTracker");
+ r->isNoiseTracker = true;
+ }
} else if(IsMagic(magic, "OKTA")
|| IsMagic(magic, "OCTA"))
{
// Oktalyzer
- m_nChannels = 8;
- m_madeWithTracker = MPT_USTRING("Oktalyzer");
+ if(r)
+ {
+ r->m_nChannels = 8;
+ r->m_madeWithTracker = MPT_USTRING("Oktalyzer");
+ }
} else if(IsMagic(magic, "CD81")
|| IsMagic(magic, "CD61"))
{
// Octalyser on Atari STe/Falcon
- m_nChannels = magic[2] - '0';
- m_madeWithTracker = MPT_USTRING("Octalyser (Atari)");
+ if(r)
+ {
+ r->m_nChannels = magic[2] - '0';
+ r->m_madeWithTracker = MPT_USTRING("Octalyser (Atari)");
+ }
} else if(!memcmp(magic, "FA0", 3) && magic[3] >= '4' && magic[3] <= '8')
{
// Digital Tracker on Atari Falcon
- m_nChannels = magic[3] - '0';
- m_madeWithTracker = MPT_USTRING("Digital Tracker");
+ if(r)
+ {
+ r->m_nChannels = magic[3] - '0';
+ r->m_madeWithTracker = MPT_USTRING("Digital Tracker");
+ }
} else if((!memcmp(magic, "FLT", 3) || !memcmp(magic, "EXO", 3)) && magic[3] >= '4' && magic[3] <= '9')
{
// FLTx / EXOx - Startrekker by Exolon / Fairlight
- m_nChannels = magic[3] - '0';
- m_madeWithTracker = MPT_USTRING("Startrekker");
- isStartrekker = true;
- m_playBehaviour.set(kMODVBlankTiming);
+ if(r)
+ {
+ r->m_nChannels = magic[3] - '0';
+ r->m_madeWithTracker = MPT_USTRING("Startrekker");
+ r->isStartrekker = true;
+ r->setMODVBlankTiming = true;
+ }
} else if(magic[0] >= '1' && magic[0] <= '9' && !memcmp(magic + 1, "CHN", 3))
{
// xCHN - Many trackers
- m_nChannels = magic[0] - '0';
- m_madeWithTracker = MPT_USTRING("Generic MOD-compatible Tracker");
- isGenericMultiChannel = true;
+ if(r)
+ {
+ r->m_nChannels = magic[0] - '0';
+ r->m_madeWithTracker = MPT_USTRING("Generic MOD-compatible Tracker");
+ r->isGenericMultiChannel = true;
+ }
} else if(magic[0] >= '1' && magic[0] <= '9' && magic[1]>='0' && magic[1] <= '9'
&& (!memcmp(magic + 2, "CH", 2) || !memcmp(magic + 2, "CN", 2)))
{
// xxCN / xxCH - Many trackers
- m_nChannels = (magic[0] - '0') * 10 + magic[1] - '0';
- m_madeWithTracker = MPT_USTRING("Generic MOD-compatible Tracker");
- isGenericMultiChannel = true;
+ if(r)
+ {
+ r->m_nChannels = (magic[0] - '0') * 10 + magic[1] - '0';
+ r->m_madeWithTracker = MPT_USTRING("Generic MOD-compatible Tracker");
+ r->isGenericMultiChannel = true;
+ }
} else if(!memcmp(magic, "TDZ", 3) && magic[3] >= '4' && magic[3] <= '9')
{
// TDZx - TakeTracker
- m_nChannels = magic[3] - '0';
- m_madeWithTracker = MPT_USTRING("TakeTracker");
+ if(r)
+ {
+ r->m_nChannels = magic[3] - '0';
+ r->m_madeWithTracker = MPT_USTRING("TakeTracker");
+ }
} else
{
return false;
}
+ return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderMOD(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ if(!file.CanRead(1080 + 4))
+ {
+ return ProbeWantMoreData;
+ }
+ file.Seek(1080);
+ char magic[4];
+ file.ReadArray(magic);
+ if(!CheckMODMagic(magic, nullptr))
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
+bool CSoundFile::ReadMod(FileReader &file, ModLoadingFlags loadFlags)
+//-------------------------------------------------------------------
+{
+ char magic[4];
+ if(!file.Seek(1080) || !file.ReadArray(magic))
+ {
+ return false;
+ }
+
+ InitializeGlobals(MOD_TYPE_MOD);
+
+ MODMagicResult modMagicResult;
+ if(CheckMODMagic(magic, &modMagicResult))
+ {
+ return false;
+ }
+
if(loadFlags == onlyVerifyHeader)
{
return true;
}
+ m_nChannels = modMagicResult.m_nChannels;
+ m_madeWithTracker = modMagicResult.m_madeWithTracker;
+ bool isNoiseTracker = modMagicResult.isNoiseTracker;
+ bool isStartrekker = modMagicResult.isStartrekker;
+ bool isGenericMultiChannel = modMagicResult.isGenericMultiChannel;
+ if(modMagicResult.setMODVBlankTiming)
+ {
+ m_playBehaviour.set(kMODVBlankTiming);
+ }
+
LimitMax(m_nChannels, MAX_BASECHANNELS);
// Startrekker 8 channel mod (needs special treatment, see below)
@@ -1165,8 +1242,8 @@
// Check if a name string is valid (i.e. doesn't contain binary garbage data)
template<size_t N>
-static uint32 CountInvalidChars(char (&name)[N])
-//----------------------------------------------
+static uint32 CountInvalidChars(const char (&name)[N])
+//----------------------------------------------------
{
uint32 invalidChars = 0;
for(auto c : name)
@@ -1194,25 +1271,114 @@
};
-bool CSoundFile::ReadM15(FileReader &file, ModLoadingFlags loadFlags)
-//-------------------------------------------------------------------
+
+struct M15FileHeaders
{
- file.Rewind();
+ char songname[20];
+ MODSampleHeader sampleHeaders[15];
+ MODFileHeader fileHeader;
+};
- char songname[20];
- file.ReadArray(songname);
+MPT_BINARY_STRUCT(M15FileHeaders, 20 + 15 * 30 + 130)
+
+static bool ValidateHeader(const M15FileHeaders &fileHeaders)
+{
// In theory, sample and song names should only ever contain printable ASCII chars and null.
// 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: 20 bogus characters in total
// or more than 5 invalid characters just in the title alone.
- uint32 invalidChars = CountInvalidChars(songname);
- if(invalidChars > 5 || !file.CanRead(sizeof(MODSampleHeader) * 15 + sizeof(MODFileHeader)))
+ uint32 invalidChars = CountInvalidChars(fileHeaders.songname);
+ if(invalidChars > 5)
{
return false;
}
+ SmpLength totalSampleLen = 0;
+ uint8 allVolumes = 0;
+
+ for(SAMPLEINDEX smp = 0; smp < 15; smp++)
+ {
+ const MODSampleHeader &sampleHeader = fileHeaders.sampleHeaders[smp];
+
+ invalidChars += CountInvalidChars(sampleHeader.name);
+
+ // Sanity checks - invalid character count adjusted for ata.mod (MD5 937b79b54026fa73a1a4d3597c26eace, SHA1 3322ca62258adb9e0ae8e9afe6e0c29d39add874)
+ if(invalidChars > 48
+ || sampleHeader.volume > 64
+ || sampleHeader.finetune != 0
+ || sampleHeader.length > 32768)
+ {
+ return false;
+ }
+
+ totalSampleLen += sampleHeader.length;
+ allVolumes |= sampleHeader.volume;
+
+ }
+
+ // 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)
+ {
+ return false;
+ }
+
+ // Sanity check: No more than 128 positions. ST's GUI limits tempo to [1, 220].
+ // There are some mods with a tempo of 0 (explora3-death.mod) though, so ignore the lower limit.
+ if(fileHeaders.fileHeader.numOrders > 128 || fileHeaders.fileHeader.restartPos > 220)
+ {
+ return false;
+ }
+
+ for(uint8 ord : fileHeaders.fileHeader.orderList)
+ {
+ // Sanity check: 64 patterns max.
+ if(ord > 63)
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderM15(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ M15FileHeaders fileHeaders;
+ if(!file.ReadStruct(fileHeaders))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeaders))
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
+bool CSoundFile::ReadM15(FileReader &file, ModLoadingFlags loadFlags)
+//-------------------------------------------------------------------
+{
+ file.Rewind();
+
+ M15FileHeaders fileHeaders;
+ if(!file.ReadStruct(fileHeaders))
+ {
+ return false;
+ }
+ if(!ValidateHeader(fileHeaders))
+ {
+ return false;
+ }
+
+ char songname[20];
+ std::memcpy(songname, fileHeaders.songname, 20);
+
InitializeGlobals(MOD_TYPE_MOD);
m_playBehaviour.reset(kMODOneShotLoops);
m_playBehaviour.set(kMODIgnorePanning);
@@ -1223,26 +1389,15 @@
bool hasDiskNames = true;
SmpLength totalSampleLen = 0;
- uint8 allVolumes = 0;
m_nSamples = 15;
+ file.Seek(20);
for(SAMPLEINDEX smp = 1; smp <= 15; smp++)
{
MODSampleHeader sampleHeader;
ReadSample(file, sampleHeader, Samples[smp], m_szNames[smp], true);
- invalidChars += CountInvalidChars(sampleHeader.name);
- // Sanity checks - invalid character count adjusted for ata.mod (MD5 937b79b54026fa73a1a4d3597c26eace, SHA1 3322ca62258adb9e0ae8e9afe6e0c29d39add874)
- if(invalidChars > 48
- || sampleHeader.volume > 64
- || sampleHeader.finetune != 0
- || sampleHeader.length > 32768)
- {
- return false;
- }
-
totalSampleLen += Samples[smp].nLength;
- allVolumes |= sampleHeader.volume;
if(m_szNames[smp][0] && ((memcmp(m_szNames[smp], "st-", 3) && memcmp(m_szNames[smp], "ST-", 3)) || m_szNames[smp][5] != ':'))
{
@@ -1263,25 +1418,9 @@
minVersion = std::max(minVersion, MST1_00);
}
- // 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)
- return false;
-
MODFileHeader fileHeader;
file.ReadStruct(fileHeader);
- // Sanity check: No more than 128 positions. ST's GUI limits tempo to [1, 220].
- // There are some mods with a tempo of 0 (explora3-death.mod) though, so ignore the lower limit.
- if(fileHeader.numOrders > 128 || fileHeader.restartPos > 220)
- return false;
-
- for(uint8 ord : fileHeader.orderList)
- {
- // Sanity check: 64 patterns max.
- if(ord > 63)
- return false;
- }
-
ReadOrderFromArray(Order(), fileHeader.orderList);
PATTERNINDEX numPatterns = GetNumPatterns(file, Order(), fileHeader.numOrders, totalSampleLen, m_nChannels, false);
@@ -1578,6 +1717,55 @@
}
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderICE(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ if(!file.CanRead(1464 + 4))
+ {
+ return ProbeWantMoreData;
+ }
+ file.Seek(1464);
+ char magic[4];
+ file.ReadArray(magic);
+ if(!IsMagic(magic, "MTN\0") && !IsMagic(magic, "IT10"))
+ {
+ return ProbeFailure;
+ }
+ file.Seek(20);
+ uint32 invalidChars = 0;
+ for(SAMPLEINDEX smp = 1; smp <= 31; smp++)
+ {
+ MODSampleHeader sampleHeader;
+ if(!file.ReadStruct(sampleHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ invalidChars += CountInvalidChars(sampleHeader.name);
+ }
+ if(invalidChars > 256)
+ {
+ return ProbeFailure;
+ }
+ const uint8 numOrders = file.ReadUint8();
+ const uint8 numTracks = file.ReadUint8();
+ if(numOrders > 128)
+ {
+ return ProbeFailure;
+ }
+ uint8 tracks[128 * 4];
+ file.ReadArray(tracks);
+ for(auto track : tracks)
+ {
+ if(track > numTracks)
+ {
+ return ProbeFailure;
+ }
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
// SoundTracker 2.6 / Ice Tracker variation of the MOD format
// The only real difference to other SoundTracker formats is the way patterns are stored:
// Every pattern consists of four independent, re-usable tracks.
@@ -1596,11 +1784,15 @@
m_playBehaviour.set(kMODSampleSwap); // untested
if(IsMagic(magic, "MTN\0"))
+ {
m_madeWithTracker = MPT_USTRING("SoundTracker 2.6");
- else if(IsMagic(magic, "IT10"))
+ } else if(IsMagic(magic, "IT10"))
+ {
m_madeWithTracker = MPT_USTRING("Ice Tracker 1.0 / 1.1");
- else
+ } else
+ {
return false;
+ }
// Reading song title
file.Seek(0);
@@ -1622,7 +1814,9 @@
const uint8 numOrders = file.ReadUint8();
const uint8 numTracks = file.ReadUint8();
if(numOrders > 128)
+ {
return false;
+ }
uint8 tracks[128 * 4];
file.ReadArray(tracks);
@@ -1629,11 +1823,15 @@
for(auto track : tracks)
{
if(track > numTracks)
+ {
return false;
+ }
}
if(loadFlags == onlyVerifyHeader)
+ {
return true;
+ }
// Now we can be pretty sure that this is a valid MOD file. Set up default song settings.
m_nChannels = 4;
@@ -1731,6 +1929,48 @@
+struct PT36Header
+{
+ char magicFORM[4]; // "FORM"
+ uint8be dummy1[4];
+ char magicMODL[4]; // "MODL"
+};
+
+MPT_BINARY_STRUCT(PT36Header, 12);
+
+
+static bool ValidateHeader(const PT36Header &fileHeader)
+//------------------------------------------------------
+{
+ if(std::memcmp(fileHeader.magicFORM, "FORM", 4))
+ {
+ return false;
+ }
+ if(std::memcmp(fileHeader.magicMODL, "MODL", 4))
+ {
+ return false;
+ }
+ return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderPT36(MemoryFileReader file, const uint64 *pfilesize)
+//-----------------------------------------------------------------------------------------------------
+{
+ PT36Header fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
// ProTracker 3.6 version of the MOD format
// Basically just a normal ProTracker mod with different magic, wrapped in an IFF file.
// The "PTDT" chunk is passed to the normal MOD loader.
@@ -1738,16 +1978,20 @@
//--------------------------------------------------------------------
{
file.Rewind();
- if(!file.ReadMagic("FORM")
- || !file.Skip(4)
- || !file.ReadMagic("MODL"))
+
+ PT36Header fileHeader;
+ if(!file.ReadStruct(fileHeader))
{
return false;
}
-
+ if(!ValidateHeader(fileHeader))
+ {
+ return false;
+ }
+
bool ok = false, infoOk = false;
FileReader commentChunk;
- mpt::ustring version = MPT_USTRING("3.6");
+ mpt::ustring version;
PT36InfoChunk info;
MemsetZero(info);
@@ -1798,6 +2042,11 @@
break;
}
} while(file.ReadStruct(iffHead));
+
+ if(version.empty())
+ {
+ version = MPT_USTRING("3.6");
+ }
// both an info chunk and a module are required
if(ok && infoOk)
Index: soundlib/Load_mt2.cpp
===================================================================
--- soundlib/Load_mt2.cpp (revision 8886)
+++ soundlib/Load_mt2.cpp (working copy)
@@ -395,23 +395,66 @@
}
-bool CSoundFile::ReadMT2(FileReader &file, ModLoadingFlags loadFlags)
-//-------------------------------------------------------------------
+static bool ValidateHeader(const MT2FileHeader &fileHeader)
+//---------------------------------------------------------
{
- file.Rewind();
- MT2FileHeader fileHeader;
- if(!file.ReadStruct(fileHeader)
- || memcmp(fileHeader.signature, "MT20", 4)
+ if(std::memcmp(fileHeader.signature, "MT20", 4)
|| fileHeader.version < 0x200 || fileHeader.version >= 0x300
|| fileHeader.numChannels < 1 || fileHeader.numChannels > 64
|| fileHeader.numOrders > 256
|| fileHeader.numInstruments >= MAX_INSTRUMENTS
|| fileHeader.numSamples >= MAX_SAMPLES
- || !file.CanRead(256))
+ )
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ return true;
+}
+
+
+static uint64 GetHeaderMinimumAdditionalSize(const MT2FileHeader &fileHeader)
+//---------------------------------------------------------------------------
+{
+ MPT_UNREFERENCED_PARAMETER(fileHeader);
+ return 256;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderMT2(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ MT2FileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
{
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader));
+}
+
+
+bool CSoundFile::ReadMT2(FileReader &file, ModLoadingFlags loadFlags)
+//-------------------------------------------------------------------
+{
+ file.Rewind();
+ MT2FileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return false;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return false;
+ }
+ if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(fileHeader))))
+ {
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
Index: soundlib/Load_mtm.cpp
===================================================================
--- soundlib/Load_mtm.cpp (revision 8886)
+++ soundlib/Load_mtm.cpp (working copy)
@@ -75,23 +75,65 @@
MPT_BINARY_STRUCT(MTMSampleHeader, 37)
-bool CSoundFile::ReadMTM(FileReader &file, ModLoadingFlags loadFlags)
-//-------------------------------------------------------------------
+static bool ValidateHeader(const MTMFileHeader &fileHeader)
+//---------------------------------------------------------
{
- file.Rewind();
- MTMFileHeader fileHeader;
- if(!file.ReadStruct(fileHeader)
- || memcmp(fileHeader.id, "MTM", 3)
+ if(std::memcmp(fileHeader.id, "MTM", 3)
|| fileHeader.version >= 0x20
|| fileHeader.lastOrder > 127
|| fileHeader.beatsPerTrack > 64
|| fileHeader.numChannels > 32
|| fileHeader.numChannels == 0
- || !file.CanRead(sizeof(MTMSampleHeader) * fileHeader.numSamples + 128 + 192 * fileHeader.numTracks + 64 * (fileHeader.lastPattern + 1) + fileHeader.commentSize))
+ )
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ return true;
+}
+
+
+static uint64 GetHeaderMinimumAdditionalSize(const MTMFileHeader &fileHeader)
+//---------------------------------------------------------------------------
+{
+ return sizeof(MTMSampleHeader) * fileHeader.numSamples + 128 + 192 * fileHeader.numTracks + 64 * (fileHeader.lastPattern + 1) + fileHeader.commentSize;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderMTM(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ MTMFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
{
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader));
+}
+
+
+bool CSoundFile::ReadMTM(FileReader &file, ModLoadingFlags loadFlags)
+//-------------------------------------------------------------------
+{
+ file.Rewind();
+ MTMFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return false;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return false;
+ }
+ if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(fileHeader))))
+ {
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
Index: soundlib/Load_okt.cpp
===================================================================
--- soundlib/Load_okt.cpp (revision 8886)
+++ soundlib/Load_okt.cpp (working copy)
@@ -258,6 +258,35 @@
}
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderOKT(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ if(!file.CanRead(8))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!file.ReadMagic("OKTASONG"))
+ {
+ return ProbeFailure;
+ }
+ OktIffChunk iffHead;
+ if(!file.ReadStruct(iffHead))
+ {
+ return ProbeWantMoreData;
+ }
+ if(iffHead.chunksize == 0)
+ {
+ return ProbeFailure;
+ }
+ if((iffHead.signature & 0x7f7f7f7fu) != iffHead.signature) // ASCII?
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
bool CSoundFile::ReadOKT(FileReader &file, ModLoadingFlags loadFlags)
//-------------------------------------------------------------------
{
Index: soundlib/Load_plm.cpp
===================================================================
--- soundlib/Load_plm.cpp (revision 8886)
+++ soundlib/Load_plm.cpp (working copy)
@@ -83,6 +83,44 @@
MPT_BINARY_STRUCT(PLMOrderItem, 4)
+static bool ValidateHeader(const PLMFileHeader &fileHeader)
+//---------------------------------------------------------
+{
+ if(std::memcmp(fileHeader.magic, "PLM\x1A", 4)
+ || fileHeader.version != 0x10
+ || fileHeader.numChannels == 0 || fileHeader.numChannels > 32
+ || fileHeader.headerSize < sizeof(PLMFileHeader)
+ )
+ {
+ return false;
+ }
+ return true;
+}
+
+
+static uint64 GetHeaderMinimumAdditionalSize(const PLMFileHeader &fileHeader)
+//---------------------------------------------------------------------------
+{
+ return fileHeader.headerSize - sizeof(PLMFileHeader) + 4 * (fileHeader.numOrders + fileHeader.numPatterns + fileHeader.numSamples);
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderPLM(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ PLMFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader));
+}
+
+
bool CSoundFile::ReadPLM(FileReader &file, ModLoadingFlags loadFlags)
//-------------------------------------------------------------------
{
@@ -89,19 +127,28 @@
file.Rewind();
PLMFileHeader fileHeader;
- if(!file.ReadStruct(fileHeader)
- || memcmp(fileHeader.magic, "PLM\x1A", 4)
- || fileHeader.version != 0x10
- || fileHeader.numChannels == 0 || fileHeader.numChannels > 32
- || !file.Seek(fileHeader.headerSize)
- || !file.CanRead(4 * (fileHeader.numOrders + fileHeader.numPatterns + fileHeader.numSamples)))
+ if(!file.ReadStruct(fileHeader))
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ if(!ValidateHeader(fileHeader))
{
+ return false;
+ }
+ if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(fileHeader))))
+ {
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
+ if(!file.Seek(fileHeader.headerSize))
+ {
+ return false;
+ }
+
InitializeGlobals(MOD_TYPE_PLM);
InitializeChannels();
m_SongFlags = SONG_ITOLDEFFECTS;
Index: soundlib/Load_psm.cpp
===================================================================
--- soundlib/Load_psm.cpp (revision 8886)
+++ soundlib/Load_psm.cpp (working copy)
@@ -208,10 +208,51 @@
offset = 0;
}
return ConvertStrTo<uint16>(&patternID[offset]);
+}
+
+static bool ValidateHeader(const PSMFileHeader &fileHeader)
+//---------------------------------------------------------
+{
+ if(std::memcmp(fileHeader.formatID, "PSM ", 4)
+ || std::memcmp(fileHeader.fileInfoID, "FILE", 4))
+ {
+ return false;
+ }
+ return true;
}
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderPSM(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ PSMFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ PSMChunk chunkHeader;
+ if(!file.ReadStruct(chunkHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(chunkHeader.length == 0)
+ {
+ return ProbeFailure;
+ }
+ if((chunkHeader.id & 0x7f7f7f7fu) != chunkHeader.id) // ASCII?
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
bool CSoundFile::ReadPSM(FileReader &file, ModLoadingFlags loadFlags)
//-------------------------------------------------------------------
{
@@ -244,8 +285,7 @@
#endif // MPT_PSM_DECRYPT
// Check header
- if(memcmp(fileHeader.formatID, "PSM ", 4)
- || memcmp(fileHeader.fileInfoID, "FILE", 4))
+ if(!ValidateHeader(fileHeader))
{
return false;
}
@@ -1029,15 +1069,10 @@
MPT_BINARY_STRUCT(PSM16PatternHeader, 4)
-bool CSoundFile::ReadPSM16(FileReader &file, ModLoadingFlags loadFlags)
-//---------------------------------------------------------------------
+static bool ValidateHeader(const PSM16FileHeader &fileHeader)
+//-----------------------------------------------------------
{
- file.Rewind();
-
- // Is it a valid PSM16 file?
- PSM16FileHeader fileHeader;
- if(!file.ReadStruct(fileHeader)
- || memcmp(fileHeader.formatID, "PSM\xFE", 4)
+ if(std::memcmp(fileHeader.formatID, "PSM\xFE", 4)
|| fileHeader.lineEnd != 0x1A
|| (fileHeader.formatVersion != 0x10 && fileHeader.formatVersion != 0x01) // why is this sometimes 0x01?
|| fileHeader.patternVersion != 0 // 255ch pattern version not supported (did anyone use this?)
@@ -1047,8 +1082,45 @@
|| std::max(fileHeader.numChannelsPlay, fileHeader.numChannelsReal) == 0)
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderPSM16(MemoryFileReader file, const uint64 *pfilesize)
+//------------------------------------------------------------------------------------------------------
+{
+ PSM16FileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
{
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
+bool CSoundFile::ReadPSM16(FileReader &file, ModLoadingFlags loadFlags)
+//---------------------------------------------------------------------
+{
+ file.Rewind();
+
+ // Is it a valid PSM16 file?
+ PSM16FileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return false;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
Index: soundlib/Load_ptm.cpp
===================================================================
--- soundlib/Load_ptm.cpp (revision 8886)
+++ soundlib/Load_ptm.cpp (working copy)
@@ -104,14 +104,10 @@
MPT_BINARY_STRUCT(PTMSampleHeader, 80)
-bool CSoundFile::ReadPTM(FileReader &file, ModLoadingFlags loadFlags)
-//-------------------------------------------------------------------
+static bool ValidateHeader(const PTMFileHeader &fileHeader)
+//---------------------------------------------------------
{
- file.Rewind();
-
- PTMFileHeader fileHeader;
- if(!file.ReadStruct(fileHeader)
- || memcmp(fileHeader.magic, "PTMF", 4)
+ if(std::memcmp(fileHeader.magic, "PTMF", 4)
|| fileHeader.dosEOF != 26
|| fileHeader.versionHi > 2
|| fileHeader.flags != 0
@@ -120,11 +116,57 @@
|| !fileHeader.numOrders || fileHeader.numOrders > 256
|| !fileHeader.numSamples || fileHeader.numSamples > 255
|| !fileHeader.numPatterns || fileHeader.numPatterns > 128
- || !file.CanRead(fileHeader.numSamples * sizeof(PTMSampleHeader)))
+ )
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ return true;
+}
+
+
+static uint64 GetHeaderMinimumAdditionalSize(const PTMFileHeader &fileHeader)
+//---------------------------------------------------------------------------
+{
+ return fileHeader.numSamples * sizeof(PTMSampleHeader);
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderPTM(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ PTMFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
{
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader));
+}
+
+
+bool CSoundFile::ReadPTM(FileReader &file, ModLoadingFlags loadFlags)
+//-------------------------------------------------------------------
+{
+ file.Rewind();
+
+ PTMFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return false;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return false;
+ }
+ if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(fileHeader))))
+ {
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
Index: soundlib/Load_s3m.cpp
===================================================================
--- soundlib/Load_s3m.cpp (revision 8886)
+++ soundlib/Load_s3m.cpp (working copy)
@@ -172,6 +172,43 @@
};
+static bool ValidateHeader(const S3MFileHeader &fileHeader)
+//---------------------------------------------------------
+{
+ if(std::memcmp(fileHeader.magic, "SCRM", 4)
+ || fileHeader.fileType != S3MFileHeader::idS3MType
+ || (fileHeader.formatVersion != S3MFileHeader::oldVersion && fileHeader.formatVersion != S3MFileHeader::newVersion)
+ )
+ {
+ return false;
+ }
+ return true;
+}
+
+
+static uint64 GetHeaderMinimumAdditionalSize(const S3MFileHeader &fileHeader)
+//---------------------------------------------------------------------------
+{
+ return fileHeader.ordNum + (fileHeader.smpNum + fileHeader.patNum) * 2;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderS3M(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ S3MFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader));
+}
+
+
bool CSoundFile::ReadS3M(FileReader &file, ModLoadingFlags loadFlags)
//-------------------------------------------------------------------
{
@@ -179,15 +216,20 @@
// Is it a valid S3M file?
S3MFileHeader fileHeader;
- if(!file.ReadStruct(fileHeader)
- || !file.CanRead(fileHeader.ordNum + (fileHeader.smpNum + fileHeader.patNum) * 2)
- || memcmp(fileHeader.magic, "SCRM", 4)
- || fileHeader.fileType != S3MFileHeader::idS3MType
- || (fileHeader.formatVersion != S3MFileHeader::oldVersion && fileHeader.formatVersion != S3MFileHeader::newVersion))
+ if(!file.ReadStruct(fileHeader))
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ if(!ValidateHeader(fileHeader))
{
+ return false;
+ }
+ if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(fileHeader))))
+ {
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
Index: soundlib/Load_sfx.cpp
===================================================================
--- soundlib/Load_sfx.cpp (revision 8886)
+++ soundlib/Load_sfx.cpp (working copy)
@@ -96,6 +96,108 @@
return 0;
}
+
+static bool ValidateHeader(const SFXFileHeader &fileHeader)
+//---------------------------------------------------------
+{
+ if(fileHeader.numOrders > 128)
+ {
+ return false;
+ }
+ return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderSFX(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+
+ if(!file.CanRead(0x40))
+ {
+ return ProbeWantMoreData;
+ }
+ if(file.Seek(0x3c) && file.ReadMagic("SONG"))
+ {
+ file.Rewind();
+ for(SAMPLEINDEX smp = 0; smp < 15; smp++)
+ {
+ if(file.ReadUint32BE() > 131072)
+ {
+ return ProbeFailure;
+ }
+ }
+ file.Skip(4);
+ if(!file.CanRead(2))
+ {
+ return ProbeWantMoreData;
+ }
+ uint16 speed = file.ReadUint16BE();
+ if(speed < 178)
+ {
+ return ProbeFailure;
+ }
+ if(!file.CanRead(sizeof(SFXSampleHeader) * 15))
+ {
+ return ProbeWantMoreData;
+ }
+ file.Skip(sizeof(SFXSampleHeader) * 15);
+ SFXFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ return ProbeSuccess;
+ }
+
+ if(!file.CanRead(0x80))
+ {
+ return ProbeWantMoreData;
+ }
+ if(file.Seek(0x3c) && file.ReadMagic("SO31"))
+ {
+ file.Rewind();
+ for(SAMPLEINDEX smp = 0; smp < 31; smp++)
+ {
+ if(file.ReadUint32BE() > 131072)
+ {
+ return ProbeFailure;
+ }
+ }
+ file.Skip(4);
+ if(!file.CanRead(2))
+ {
+ return ProbeWantMoreData;
+ }
+ uint16 speed = file.ReadUint16BE();
+ if(speed < 178)
+ {
+ return ProbeFailure;
+ }
+ if(!file.CanRead(sizeof(SFXSampleHeader) * 31))
+ {
+ return ProbeWantMoreData;
+ }
+ file.Skip(sizeof(SFXSampleHeader) * 31);
+ SFXFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ return ProbeSuccess;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeFailure;
+}
+
+
bool CSoundFile::ReadSFX(FileReader &file, ModLoadingFlags loadFlags)
//-------------------------------------------------------------------
{
@@ -164,12 +266,18 @@
}
SFXFileHeader fileHeader;
- file.ReadStruct(fileHeader);
-
- if(fileHeader.numOrders > 128)
+ if(!file.ReadStruct(fileHeader))
+ {
return false;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return false;
+ }
if(loadFlags == onlyVerifyHeader)
+ {
return true;
+ }
PATTERNINDEX numPatterns = 0;
for(ORDERINDEX ord = 0; ord < fileHeader.numOrders; ord++)
Index: soundlib/Load_stm.cpp
===================================================================
--- soundlib/Load_stm.cpp (revision 8886)
+++ soundlib/Load_stm.cpp (working copy)
@@ -94,6 +94,49 @@
MPT_BINARY_STRUCT(STMPatternData, 4*64*4)
+static bool ValidateHeader(const STMFileHeader &fileHeader)
+//---------------------------------------------------------
+{
+ if(fileHeader.filetype != 2
+ || (fileHeader.dosEof != 0x1A && fileHeader.dosEof != 2) // ST2 ignores this, ST3 doesn't. putup10.stm / putup11.stm have dosEof = 2.
+ || fileHeader.verMajor != 2
+ || fileHeader.verMinor > 21 // ST3 only accepts 0, 10, 20 and 21
+ || fileHeader.globalVolume > 64
+ || (std::memcmp(fileHeader.trackername, "!Scream!", 8)
+ && std::memcmp(fileHeader.trackername, "BMOD2STM", 8)
+ && std::memcmp(fileHeader.trackername, "WUZAMOD!", 8))
+ )
+ {
+ return false;
+ }
+ return true;
+}
+
+
+static uint64 GetHeaderMinimumAdditionalSize(const STMFileHeader &fileHeader)
+//---------------------------------------------------------------------------
+{
+ MPT_UNREFERENCED_PARAMETER(fileHeader);
+ return 31 * sizeof(STMSampleHeader) + 128;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderSTM(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ STMFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader));
+}
+
+
bool CSoundFile::ReadSTM(FileReader &file, ModLoadingFlags loadFlags)
//-------------------------------------------------------------------
{
@@ -105,20 +148,20 @@
// After reviewing all STM files on ModLand and ModArchive, it was found that the
// case-insensitive comparison is most likely not necessary for any files in the wild.
STMFileHeader fileHeader;
- if(!file.ReadStruct(fileHeader)
- || fileHeader.filetype != 2
- || (fileHeader.dosEof != 0x1A && fileHeader.dosEof != 2) // ST2 ignores this, ST3 doesn't. putup10.stm / putup11.stm have dosEof = 2.
- || fileHeader.verMajor != 2
- || fileHeader.verMinor > 21 // ST3 only accepts 0, 10, 20 and 21
- || fileHeader.globalVolume > 64
- || (memcmp(fileHeader.trackername, "!Scream!", 8)
- && memcmp(fileHeader.trackername, "BMOD2STM", 8)
- && memcmp(fileHeader.trackername, "WUZAMOD!", 8))
- || !file.CanRead(31 * sizeof(STMSampleHeader) + 128))
+ if(!file.ReadStruct(fileHeader))
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ if(!ValidateHeader(fileHeader))
{
+ return false;
+ }
+ if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(fileHeader))))
+ {
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
Index: soundlib/Load_stp.cpp
===================================================================
--- soundlib/Load_stp.cpp (revision 8886)
+++ soundlib/Load_stp.cpp (working copy)
@@ -23,6 +23,7 @@
// File header (except for "STP3" magic)
struct STPFileHeader
{
+ char magic[4];
uint16be version;
uint8be numOrders;
uint8be patternLength;
@@ -38,7 +39,7 @@
uint16be sampleStructSize;
};
-MPT_BINARY_STRUCT(STPFileHeader, 200);
+MPT_BINARY_STRUCT(STPFileHeader, 204);
// Sample header (common part between all versions)
@@ -203,24 +204,57 @@
}
-bool CSoundFile::ReadSTP(FileReader &file, ModLoadingFlags loadFlags)
-//-------------------------------------------------------------------
+static bool ValidateHeader(const STPFileHeader &fileHeader)
+//---------------------------------------------------------
{
- file.Rewind();
- if(!file.ReadMagic("STP3"))
- return false;
-
- STPFileHeader fileHeader;
- if(!file.ReadStruct(fileHeader)
+ if(std::memcmp(fileHeader.magic, "STP3", 4)
|| fileHeader.version > 2
|| fileHeader.numOrders > 128
|| fileHeader.numSamples >= MAX_SAMPLES
|| fileHeader.timerCount == 0
|| fileHeader.midiCount != 50)
+ {
return false;
+ }
+ return true;
+}
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderSTP(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ STPFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
+bool CSoundFile::ReadSTP(FileReader &file, ModLoadingFlags loadFlags)
+//-------------------------------------------------------------------
+{
+ file.Rewind();
+
+ STPFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return false;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return false;
+ }
if(loadFlags == onlyVerifyHeader)
+ {
return true;
+ }
InitializeGlobals(MOD_TYPE_STP);
Index: soundlib/Load_ult.cpp
===================================================================
--- soundlib/Load_ult.cpp (revision 8886)
+++ soundlib/Load_ult.cpp (working copy)
@@ -336,21 +336,53 @@
};
+static bool ValidateHeader(const UltFileHeader &fileHeader)
+//---------------------------------------------------------
+{
+ if(fileHeader.version < '1'
+ || fileHeader.version > '4'
+ || std::memcmp(fileHeader.signature, "MAS_UTrack_V00", sizeof(fileHeader.signature))
+ )
+ {
+ return false;
+ }
+ return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderULT(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ UltFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
bool CSoundFile::ReadUlt(FileReader &file, ModLoadingFlags loadFlags)
//-------------------------------------------------------------------
{
file.Rewind();
+
UltFileHeader fileHeader;
-
- // Tracker ID
- if(!file.ReadStruct(fileHeader)
- || fileHeader.version < '1'
- || fileHeader.version > '4'
- || memcmp(fileHeader.signature, "MAS_UTrack_V00", sizeof(fileHeader.signature)) != 0)
+ if(!file.ReadStruct(fileHeader))
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ if(!ValidateHeader(fileHeader))
{
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
Index: soundlib/Load_xm.cpp
===================================================================
--- soundlib/Load_xm.cpp (revision 8886)
+++ soundlib/Load_xm.cpp (working copy)
@@ -262,6 +262,43 @@
DECLARE_FLAGSET(TrackerVersions)
+static bool ValidateHeader(const XMFileHeader &fileHeader)
+//--------------------------------------------------------
+{
+ if(fileHeader.channels == 0
+ || fileHeader.channels > MAX_BASECHANNELS
+ || std::memcmp(fileHeader.signature, "Extended Module: ", 17)
+ )
+ {
+ return false;
+ }
+ return true;
+}
+
+
+static uint64 GetHeaderMinimumAdditionalSize(const XMFileHeader &fileHeader)
+//--------------------------------------------------------------------------
+{
+ return fileHeader.orders + 4 * (fileHeader.patterns + fileHeader.instruments);
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderXM(MemoryFileReader file, const uint64 *pfilesize)
+//---------------------------------------------------------------------------------------------------
+{
+ XMFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader));
+}
+
+
bool CSoundFile::ReadXM(FileReader &file, ModLoadingFlags loadFlags)
//------------------------------------------------------------------
{
@@ -268,13 +305,17 @@
file.Rewind();
XMFileHeader fileHeader;
- if(!file.ReadStruct(fileHeader)
- || fileHeader.channels == 0
- || fileHeader.channels > MAX_BASECHANNELS
- || memcmp(fileHeader.signature, "Extended Module: ", 17)
- || !file.CanRead(fileHeader.orders + 4 * (fileHeader.patterns + fileHeader.instruments)))
+ if(!file.ReadStruct(fileHeader))
{
return false;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return false;
+ }
+ if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(fileHeader))))
+ {
+ return false;
} else if(loadFlags == onlyVerifyHeader)
{
return true;
Index: soundlib/Sndfile.cpp
===================================================================
--- soundlib/Sndfile.cpp (revision 8886)
+++ soundlib/Sndfile.cpp (working copy)
@@ -214,9 +214,113 @@
const std::size_t CSoundFile::ProbeRecommendedSize = 2048;
+CSoundFile::ProbeResult CSoundFile::ProbeAdditionalSize(MemoryFileReader &file, const uint64 *pfilesize, uint64 minimumAdditionalSize)
+//------------------------------------------------------------------------------------------------------------------------------------
+{
+ const uint64 availableFileSize = file.GetLength();
+ const uint64 fileSize = (pfilesize ? *pfilesize : file.GetLength());
+ //const uint64 validFileSize = std::min<uint64>(fileSize, ProbeRecommendedSize);
+ const uint64 goalSize = file.GetPosition() + minimumAdditionalSize;
+ //const uint64 goalMinimumSize = std::min<uint64>(goalSize, ProbeRecommendedSize);
+ if(pfilesize)
+ {
+ if(availableFileSize < std::min<uint64>(fileSize, ProbeRecommendedSize))
+ {
+ if(availableFileSize < goalSize)
+ {
+ return ProbeWantMoreData;
+ }
+ } else
+ {
+ if(fileSize < goalSize)
+ {
+ return ProbeFailure;
+ }
+ }
+ return ProbeSuccess;
+ }
+#if 0
+ if(!pfilesize)
+ {
+ if(fileSize < goalSize && fileSize < ProbeRecommendedSize)
+ {
+ return ProbeWantMoreData;
+ }
+ return ProbeSuccess;
+ }
+#else
+ return ProbeSuccess;
+#endif
+}
+
+
+#define MPT_DO_PROBE( storedResult , call ) \
+ MPT_DO { \
+ ProbeResult lastResult = call ; \
+ if(lastResult == ProbeSuccess) { \
+ return ProbeSuccess; \
+ } else if(lastResult == ProbeWantMoreData) { \
+ storedResult = ProbeWantMoreData; \
+ } \
+ } MPT_WHILE_0 \
+/**/
+
+
CSoundFile::ProbeResult CSoundFile::Probe(ProbeFlags flags, mpt::span<const mpt::byte> data, const uint64 *pfilesize)
//-------------------------------------------------------------------------------------------------------------------
{
+#if 1
+ ProbeResult result = ProbeFailure;
+ MemoryFileReader file(data);
+ if(flags & ProbeContainers)
+ {
+ MPT_DO_PROBE(result, ProbeFileHeaderMMCMP(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderPP20(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderUMX(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderXPK(file, pfilesize));
+ }
+ if(flags & ProbeModules)
+ {
+ MPT_DO_PROBE(result, ProbeFileHeader669(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderAM(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderAMF_Asylum(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderAMF_DSMI(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderAMS(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderAMS2(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderDBM(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderDTM(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderDIGI(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderDMF(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderDSM(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderFAR(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderGDM(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderICE(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderIMF(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderIT(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderITP(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderJ2B(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderM15(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderMDL(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderMED(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderMO3(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderMOD(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderMT2(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderMTM(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderOKT(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderPLM(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderPSM(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderPSM16(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderPT36(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderPTM(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderS3M(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderSFX(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderSTM(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderSTP(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderULT(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderXM(file, pfilesize));
+ }
+ return result;
+#else
uint64 filesize = 0;
if(pfilesize)
{
@@ -257,6 +361,7 @@
}
sndFile->Destroy();
return ProbeSuccess;
+#endif
}
Index: soundlib/Sndfile.h
===================================================================
--- soundlib/Sndfile.h (revision 8886)
+++ soundlib/Sndfile.h (working copy)
@@ -579,6 +579,8 @@
ProbeWantMoreData = -1
};
+ static ProbeResult ProbeAdditionalSize(MemoryFileReader &file, const uint64 *pfilesize, uint64 minimumAdditionalSize);
+
static ProbeResult Probe(ProbeFlags flags, mpt::span<const mpt::byte> data, const uint64 *pfilesize);
public:
@@ -670,6 +672,49 @@
bool InitChannel(CHANNELINDEX nChn);
void InitAmigaResampler();
+ static ProbeResult ProbeFileHeaderMMCMP(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderPP20(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderUMX(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderXPK(MemoryFileReader file, const uint64 *pfilesize);
+
+ static ProbeResult ProbeFileHeader669(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderAM(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderAMF_Asylum(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderAMF_DSMI(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderAMS(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderAMS2(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderDBM(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderDTM(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderDIGI(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderDMF(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderDSM(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderFAR(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderGDM(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderICE(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderIMF(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderIT(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderITP(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderJ2B(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderM15(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderMDL(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderMED(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderMO3(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderMOD(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderMT2(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderMTM(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderOKT(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderPLM(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderPSM(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderPSM16(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderPT36(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderPTM(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderS3M(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderSFX(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderSTM(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderSTP(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderULT(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderXM(MemoryFileReader file, const uint64 *pfilesize);
+
// Module Loaders
bool Read669(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadAM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
@@ -692,7 +737,6 @@
bool ReadM15(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadMDL(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadMed(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
- bool ReadMID(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadMO3(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadMod(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadMT2(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
@@ -708,9 +752,11 @@
bool ReadSTM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadSTP(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadUlt(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
+ bool ReadXM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
+
+ bool ReadMID(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadUAX(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadWav(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
- bool ReadXM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
static std::vector<const char *> GetSupportedExtensions(bool otherFormats);
static bool IsExtensionSupported(const char *ext); // UTF8, casing of ext is ignored
Index: soundlib/UMXTools.cpp
===================================================================
--- soundlib/UMXTools.cpp (revision 8886)
+++ soundlib/UMXTools.cpp (working copy)
@@ -17,8 +17,9 @@
// Read compressed unreal integers - similar to MIDI integers, but signed values are possible.
-int32 ReadUMXIndex(FileReader &chunk)
-//-----------------------------------
+template <typename Tfile>
+static int32 ReadUMXIndexImpl(Tfile &chunk)
+//-----------------------------------------
{
enum
{
@@ -55,10 +56,17 @@
return result;
}
+int32 ReadUMXIndex(FileReader &chunk)
+//-----------------------------------
+{
+ return ReadUMXIndexImpl(chunk);
+}
+
// Returns true if the given nme exists in the name table.
-bool FindUMXNameTableEntry(FileReader &file, const UMXFileHeader &fileHeader, const char *name)
-//---------------------------------------------------------------------------------------------
+template <typename TFile>
+static bool FindUMXNameTableEntryImpl(TFile &file, const UMXFileHeader &fileHeader, const char *name)
+//---------------------------------------------------------------------------------------------------
{
if(!name)
{
@@ -77,7 +85,7 @@
{
if(fileHeader.packageVersion >= 64)
{
- int32 length = ReadUMXIndex(file);
+ int32 length = ReadUMXIndexImpl(file);
if(length <= 0)
{
continue;
@@ -110,7 +118,19 @@
return result;
}
+bool FindUMXNameTableEntry(FileReader &file, const UMXFileHeader &fileHeader, const char *name)
+//---------------------------------------------------------------------------------------------
+{
+ return FindUMXNameTableEntryImpl(file, fileHeader, name);
+}
+bool FindUMXNameTableEntryMemory(MemoryFileReader &file, const UMXFileHeader &fileHeader, const char *name)
+//---------------------------------------------------------------------------------------------------------
+{
+ return FindUMXNameTableEntryImpl(file, fileHeader, name);
+}
+
+
// Read an entry from the name table.
std::string ReadUMXNameTableEntry(FileReader &chunk, uint16 packageVersion)
//-------------------------------------------------------------------------
Index: soundlib/UMXTools.h
===================================================================
--- soundlib/UMXTools.h (revision 8886)
+++ soundlib/UMXTools.h (working copy)
@@ -38,6 +38,9 @@
// Returns true if the given nme exists in the name table.
bool FindUMXNameTableEntry(FileReader &file, const UMXFileHeader &fileHeader, const char *name);
+// Returns true if the given nme exists in the name table.
+bool FindUMXNameTableEntryMemory(MemoryFileReader &file, const UMXFileHeader &fileHeader, const char *name);
+
// Read an entry from the name table.
std::string ReadUMXNameTableEntry(FileReader &chunk, uint16 packageVersion);
Index: soundlib/load_j2b.cpp
===================================================================
--- soundlib/load_j2b.cpp (revision 8886)
+++ soundlib/load_j2b.cpp (working copy)
@@ -615,6 +615,66 @@
}
+struct AMFFRiffChunkFormat
+{
+ uint32le format;
+};
+
+MPT_BINARY_STRUCT(AMFFRiffChunkFormat, 4)
+
+
+static bool ValidateHeader(const AMFFRiffChunk &fileHeader)
+//---------------------------------------------------------
+{
+ if(fileHeader.id != AMFFRiffChunk::idRIFF)
+ {
+ return false;
+ }
+ if(fileHeader.GetLength() < 8 + sizeof(AMFFMainChunk))
+ {
+ return false;
+ }
+ return true;
+}
+
+
+static bool ValidateHeader(const AMFFRiffChunkFormat &formatHeader)
+//-----------------------------------------------------------------
+{
+ if(formatHeader.format != AMFFRiffChunk::idAMFF || formatHeader.format != AMFFRiffChunk::idAM__)
+ {
+ return false;
+ }
+ return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderAM(MemoryFileReader file, const uint64 *pfilesize)
+//---------------------------------------------------------------------------------------------------
+{
+ AMFFRiffChunk fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ AMFFRiffChunkFormat formatHeader;
+ if(!file.ReadStruct(formatHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(formatHeader))
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
bool CSoundFile::ReadAM(FileReader &file, ModLoadingFlags loadFlags)
//------------------------------------------------------------------
{
@@ -624,15 +684,23 @@
{
return false;
}
-
- if(fileHeader.id != AMFFRiffChunk::idRIFF)
+ if(!ValidateHeader(fileHeader))
{
return false;
}
+ AMFFRiffChunkFormat formatHeader;
+ if(!file.ReadStruct(formatHeader))
+ {
+ return false;
+ }
+ if(!ValidateHeader(formatHeader))
+ {
+ return false;
+ }
bool isAM; // false: AMFF, true: AM
- uint32 format = file.ReadUint32LE();
+ uint32 format = formatHeader.format;
if(format == AMFFRiffChunk::idAMFF)
isAM = false; // "AMFF"
else if(format == AMFFRiffChunk::idAM__)
@@ -877,6 +945,64 @@
return true;
}
+
+static bool ValidateHeader(const J2BFileHeader &fileHeader)
+//---------------------------------------------------------
+{
+ if(std::memcmp(fileHeader.signature, "MUSE", 4)
+ || (fileHeader.deadbeaf != J2BFileHeader::magicDEADBEAF // 0xDEADBEAF (RIFF AM)
+ && fileHeader.deadbeaf != J2BFileHeader::magicDEADBABE) // 0xDEADBABE (RIFF AMFF)
+ )
+ {
+ return false;
+ }
+ if(fileHeader.packedLength == 0)
+ {
+ return false;
+ }
+ if(fileHeader.fileLength != fileHeader.packedLength + sizeof(J2BFileHeader))
+ {
+ return false;
+ }
+ return true;
+}
+
+
+static bool ValidateHeaderFileSize(const J2BFileHeader &fileHeader, uint64 filesize)
+//----------------------------------------------------------------------------------
+{
+ if(filesize != fileHeader.fileLength)
+ {
+ return false;
+ }
+ return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderJ2B(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ J2BFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ if(pfilesize)
+ {
+ if(!ValidateHeaderFileSize(fileHeader, *pfilesize))
+ {
+ return ProbeFailure;
+ }
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
bool CSoundFile::ReadJ2B(FileReader &file, ModLoadingFlags loadFlags)
//-------------------------------------------------------------------
{
@@ -891,17 +1017,21 @@
file.Rewind();
J2BFileHeader fileHeader;
- if(!file.ReadStruct(fileHeader)
- || memcmp(fileHeader.signature, "MUSE", 4)
- || (fileHeader.deadbeaf != J2BFileHeader::magicDEADBEAF // 0xDEADBEAF (RIFF AM)
- && fileHeader.deadbeaf != J2BFileHeader::magicDEADBABE) // 0xDEADBABE (RIFF AMFF)
- || fileHeader.fileLength != file.GetLength()
+ if(!file.ReadStruct(fileHeader))
+ {
+ return false;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return false;
+ }
+ if(fileHeader.fileLength != file.GetLength()
|| fileHeader.packedLength != file.BytesLeft()
- || fileHeader.packedLength == 0
)
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ if(loadFlags == onlyVerifyHeader)
{
return true;
}
probe-refactor-v18.patch (110,517 bytes)
Index: libopenmpt/libopenmpt_version.h
===================================================================
--- libopenmpt/libopenmpt_version.h (revision 8929)
+++ libopenmpt/libopenmpt_version.h (working copy)
@@ -21,7 +21,7 @@
/*! \brief libopenmpt patch version number */
#define OPENMPT_API_VERSION_PATCH 0
/*! \brief libopenmpt pre-release tag */
-#define OPENMPT_API_VERSION_PREREL "-pre.7"
+#define OPENMPT_API_VERSION_PREREL "-pre.8"
/*! \brief libopenmpt pre-release flag */
#define OPENMPT_API_VERSION_IS_PREREL 1
Index: libopenmpt/libopenmpt_version.mk
===================================================================
--- libopenmpt/libopenmpt_version.mk (revision 8929)
+++ libopenmpt/libopenmpt_version.mk (working copy)
@@ -1,7 +1,7 @@
LIBOPENMPT_VERSION_MAJOR=0
LIBOPENMPT_VERSION_MINOR=3
LIBOPENMPT_VERSION_PATCH=0
-LIBOPENMPT_VERSION_PREREL=-pre.7
+LIBOPENMPT_VERSION_PREREL=-pre.8
LIBOPENMPT_LTVER_CURRENT=1
LIBOPENMPT_LTVER_REVISION=0
Index: soundlib/ContainerMMCMP.cpp
===================================================================
--- soundlib/ContainerMMCMP.cpp (revision 8929)
+++ soundlib/ContainerMMCMP.cpp (working copy)
@@ -13,6 +13,7 @@
#include "../common/FileReader.h"
#include "Container.h"
+#include "Sndfile.h"
#include <stdexcept>
@@ -144,6 +145,66 @@
}
+static bool ValidateHeader(const MMCMPFILEHEADER &mfh)
+//----------------------------------------------------
+{
+ if(std::memcmp(mfh.id, "ziRCONia", 8) != 0)
+ {
+ return false;
+ }
+ if(mfh.hdrsize != sizeof(MMCMPHEADER))
+ {
+ return false;
+ }
+ return true;
+}
+
+
+static bool ValidateHeader(const MMCMPHEADER &mmh)
+//------------------------------------------------
+{
+ if(mmh.nblocks == 0)
+ {
+ return false;
+ }
+ if(mmh.filesize == 0)
+ {
+ return false;
+ }
+ if(mmh.filesize > 0x80000000)
+ {
+ return false;
+ }
+ return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderMMCMP(MemoryFileReader file, const uint64 *pfilesize)
+//------------------------------------------------------------------------------------------------------
+{
+ MMCMPFILEHEADER mfh;
+ if(!file.ReadStruct(mfh))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(mfh))
+ {
+ return ProbeFailure;
+ }
+ MMCMPHEADER mmh;
+ if(!file.ReadStruct(mmh))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(mmh))
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
bool UnpackMMCMP(std::vector<ContainerItem> &containerItems, FileReader &file, ContainerLoadingFlags loadFlags)
//-------------------------------------------------------------------------------------------------------------
{
@@ -151,14 +212,23 @@
containerItems.clear();
MMCMPFILEHEADER mfh;
- if(!file.ReadStruct(mfh)) return false;
- if(std::memcmp(mfh.id, "ziRCONia", 8) != 0) return false;
- if(mfh.hdrsize != sizeof(MMCMPHEADER)) return false;
+ if(!file.ReadStruct(mfh))
+ {
+ return false;
+ }
+ if(!ValidateHeader(mfh))
+ {
+ return false;
+ }
MMCMPHEADER mmh;
- if(!file.ReadStruct(mmh)) return false;
- if(mmh.nblocks == 0) return false;
- if(mmh.filesize == 0) return false;
- if(mmh.filesize > 0x80000000) return false;
+ if(!file.ReadStruct(mmh))
+ {
+ return false;
+ }
+ if(!ValidateHeader(mmh))
+ {
+ return false;
+ }
if(loadFlags == ContainerOnlyVerifyHeader)
{
return true;
Index: soundlib/ContainerPP20.cpp
===================================================================
--- soundlib/ContainerPP20.cpp (revision 8929)
+++ soundlib/ContainerPP20.cpp (working copy)
@@ -13,6 +13,7 @@
#include "../common/FileReader.h"
#include "Container.h"
+#include "Sndfile.h"
#include <stdexcept>
@@ -115,6 +116,50 @@
}
+struct PP20header
+{
+ char magic[4]; // "PP20"
+ uint8be efficiency[4];
+};
+
+MPT_BINARY_STRUCT(PP20header, 8)
+
+
+static bool ValidateHeader(const PP20header &hdr)
+//-----------------------------------------------
+{
+ if(std::memcmp(hdr.magic, "PP20", 4) != 0)
+ {
+ return false;
+ }
+ if(hdr.efficiency[0] < 9 || hdr.efficiency[0] > 15
+ || hdr.efficiency[1] < 9 || hdr.efficiency[1] > 15
+ || hdr.efficiency[2] < 9 || hdr.efficiency[2] > 15
+ || hdr.efficiency[3] < 9 || hdr.efficiency[3] > 15)
+ {
+ return false;
+ }
+ return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderPP20(MemoryFileReader file, const uint64 *pfilesize)
+//-----------------------------------------------------------------------------------------------------
+{
+ PP20header hdr;
+ if(!file.ReadStruct(hdr))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(hdr))
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
bool UnpackPP20(std::vector<ContainerItem> &containerItems, FileReader &file, ContainerLoadingFlags loadFlags)
//------------------------------------------------------------------------------------------------------------
{
@@ -121,20 +166,25 @@
file.Rewind();
containerItems.clear();
- if(!file.ReadMagic("PP20")) return false;
- if(!file.CanRead(8)) return false;
- uint8 efficiency[4];
- file.ReadArray(efficiency);
- if(efficiency[0] < 9 || efficiency[0] > 15
- || efficiency[1] < 9 || efficiency[1] > 15
- || efficiency[2] < 9 || efficiency[2] > 15
- || efficiency[3] < 9 || efficiency[3] > 15)
+ PP20header hdr;
+ if(!file.ReadStruct(hdr))
+ {
return false;
+ }
+ if(!ValidateHeader(hdr))
+ {
+ return false;
+ }
if(loadFlags == ContainerOnlyVerifyHeader)
{
return true;
}
+ if(!file.CanRead(4))
+ {
+ return false;
+ }
+
containerItems.emplace_back();
containerItems.back().data_cache = mpt::make_unique<std::vector<char> >();
std::vector<char> & unpackedData = *(containerItems.back().data_cache);
Index: soundlib/ContainerUMX.cpp
===================================================================
--- soundlib/ContainerUMX.cpp (revision 8929)
+++ soundlib/ContainerUMX.cpp (working copy)
@@ -12,11 +12,48 @@
#include "Loaders.h"
#include "UMXTools.h"
#include "Container.h"
+#include "Sndfile.h"
OPENMPT_NAMESPACE_BEGIN
+static bool ValidateHeader(const UMXFileHeader &fileHeader)
+//---------------------------------------------------------
+{
+ if(std::memcmp(fileHeader.magic, "\xC1\x83\x2A\x9E", 4)
+ || fileHeader.nameCount == 0
+ || fileHeader.exportCount == 0
+ || fileHeader.importCount == 0
+ )
+ {
+ return false;
+ }
+ return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderUMX(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ UMXFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ if(!FindUMXNameTableEntryMemory(file, fileHeader, "music"))
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
bool UnpackUMX(std::vector<ContainerItem> &containerItems, FileReader &file, ContainerLoadingFlags loadFlags)
//-----------------------------------------------------------------------------------------------------------
{
@@ -24,15 +61,14 @@
containerItems.clear();
UMXFileHeader fileHeader;
- if(!file.ReadStruct(fileHeader)
- || memcmp(fileHeader.magic, "\xC1\x83\x2A\x9E", 4)
- || fileHeader.nameCount == 0
- || fileHeader.exportCount == 0
- || fileHeader.importCount == 0
- )
+ if(!file.ReadStruct(fileHeader))
{
return false;
}
+ if(!ValidateHeader(fileHeader))
+ {
+ return false;
+ }
// Note that this can be a false positive, e.g. Unreal maps will have music and sound
// in their name table because they usually import such files. However, it spares us
Index: soundlib/ContainerXPK.cpp
===================================================================
--- soundlib/ContainerXPK.cpp (revision 8929)
+++ soundlib/ContainerXPK.cpp (working copy)
@@ -13,6 +13,7 @@
#include "../common/FileReader.h"
#include "Container.h"
+#include "Sndfile.h"
#include <stdexcept>
@@ -329,6 +330,68 @@
}
+static bool ValidateHeader(const XPKFILEHEADER &header)
+//-----------------------------------------------------
+{
+ if(std::memcmp(header.XPKF, "XPKF", 4) != 0)
+ {
+ return false;
+ }
+ if(std::memcmp(header.SQSH, "SQSH", 4) != 0)
+ {
+ return false;
+ }
+ if(header.SrcLen == 0)
+ {
+ return false;
+ }
+ if(header.DstLen == 0)
+ {
+ return false;
+ }
+ MPT_STATIC_ASSERT(sizeof(XPKFILEHEADER) >= 8);
+ if(header.SrcLen < (sizeof(XPKFILEHEADER) - 8))
+ {
+ return false;
+ }
+ return true;
+}
+
+
+static bool ValidateHeaderFileSize(const XPKFILEHEADER &header, uint64 filesize)
+//------------------------------------------------------------------------------
+{
+ if(filesize < header.SrcLen - 8)
+ {
+ return false;
+ }
+ return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderXPK(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ XPKFILEHEADER header;
+ if(!file.ReadStruct(header))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(header))
+ {
+ return ProbeFailure;
+ }
+ if(pfilesize)
+ {
+ if(!ValidateHeaderFileSize(header, *pfilesize))
+ {
+ return ProbeFailure;
+ }
+ }
+ return ProbeSuccess;
+}
+
+
bool UnpackXPK(std::vector<ContainerItem> &containerItems, FileReader &file, ContainerLoadingFlags loadFlags)
//-----------------------------------------------------------------------------------------------------------
{
@@ -336,19 +399,24 @@
containerItems.clear();
XPKFILEHEADER header;
- if(!file.ReadStruct(header)) return false;
- if(std::memcmp(header.XPKF, "XPKF", 4) != 0) return false;
- if(std::memcmp(header.SQSH, "SQSH", 4) != 0) return false;
- if(header.SrcLen == 0) return false;
- if(header.DstLen == 0) return false;
- STATIC_ASSERT(sizeof(XPKFILEHEADER) >= 8);
- if(header.SrcLen < (sizeof(XPKFILEHEADER) - 8)) return false;
+ if(!file.ReadStruct(header))
+ {
+ return false;
+ }
+ if(!ValidateHeader(header))
+ {
+ return false;
+ }
if(loadFlags == ContainerOnlyVerifyHeader)
{
return true;
}
- if(!file.CanRead(header.SrcLen - (sizeof(XPKFILEHEADER) - 8))) return false;
+ if(!file.CanRead(header.SrcLen - (sizeof(XPKFILEHEADER) - 8)))
+ {
+ return false;
+ }
+
containerItems.emplace_back();
containerItems.back().data_cache = mpt::make_unique<std::vector<char> >();
std::vector<char> & unpackedData = *(containerItems.back().data_cache);
Index: soundlib/Load_669.cpp
===================================================================
--- soundlib/Load_669.cpp (revision 8929)
+++ soundlib/Load_669.cpp (working copy)
@@ -62,14 +62,9 @@
MPT_BINARY_STRUCT(_669Sample, 25)
-bool CSoundFile::Read669(FileReader &file, ModLoadingFlags loadFlags)
-//-------------------------------------------------------------------
+static bool ValidateHeader(const _669FileHeader &fileHeader)
{
- _669FileHeader fileHeader;
-
- file.Rewind();
- if(!file.ReadStruct(fileHeader)
- || (memcmp(fileHeader.magic, "if", 2) && memcmp(fileHeader.magic, "JN", 2))
+ if((std::memcmp(fileHeader.magic, "if", 2) && std::memcmp(fileHeader.magic, "JN", 2))
|| fileHeader.samples > 64
|| fileHeader.restartPos >= 128
|| fileHeader.patterns > 128)
@@ -76,21 +71,68 @@
{
return false;
}
-
- for(size_t i = 0; i < CountOf(fileHeader.breaks); i++)
+ for(std::size_t i = 0; i < CountOf(fileHeader.breaks); i++)
{
if(fileHeader.orders[i] >= 128 && fileHeader.orders[i] < 0xFE)
+ {
return false;
+ }
if(fileHeader.orders[i] < 128 && fileHeader.tempoList[i] == 0)
+ {
return false;
+ }
if(fileHeader.breaks[i] >= 64)
+ {
return false;
+ }
}
+ return true;
+}
+
+static uint64 GetHeaderMinimumAdditionalSize(const _669FileHeader &fileHeader)
+//----------------------------------------------------------------------------
+{
+ return fileHeader.samples * sizeof(_669Sample) + fileHeader.patterns * 1536u;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeader669(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ _669FileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader));
+}
+
+
+bool CSoundFile::Read669(FileReader &file, ModLoadingFlags loadFlags)
+//-------------------------------------------------------------------
+{
+ _669FileHeader fileHeader;
+
+ file.Rewind();
+ if(!file.ReadStruct(fileHeader))
+ {
+ return false;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return false;
+ }
if(loadFlags == onlyVerifyHeader)
{
return true;
- } else if(!file.CanRead(fileHeader.samples * sizeof(_669Sample) + fileHeader.patterns * 1536u))
+ }
+
+ if(!file.CanRead(GetHeaderMinimumAdditionalSize(fileHeader)))
{
return false;
}
Index: soundlib/Load_amf.cpp
===================================================================
--- soundlib/Load_amf.cpp (revision 8929)
+++ soundlib/Load_amf.cpp (working copy)
@@ -80,6 +80,42 @@
MPT_BINARY_STRUCT(AMFFileHeader, 41)
+static bool ValidateHeader(const AsylumFileHeader &fileHeader)
+//------------------------------------------------------------
+{
+ if(std::memcmp(fileHeader.signature, "ASYLUM Music Format V1.0\0", 25)
+ || fileHeader.numSamples > 64
+ )
+ {
+ return false;
+ }
+ return true;
+}
+
+
+static uint64 GetHeaderMinimumAdditionalSize(const AsylumFileHeader &fileHeader)
+//------------------------------------------------------------------------------
+{
+ return 256 + 64 * sizeof(AsylumSampleHeader) + 64 * 4 * 8 * fileHeader.numPatterns;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderAMF_Asylum(MemoryFileReader file, const uint64 *pfilesize)
+//-----------------------------------------------------------------------------------------------------------
+{
+ AsylumFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader));
+}
+
+
bool CSoundFile::ReadAMF_Asylum(FileReader &file, ModLoadingFlags loadFlags)
//--------------------------------------------------------------------------
{
@@ -86,14 +122,20 @@
file.Rewind();
AsylumFileHeader fileHeader;
- if(!file.ReadStruct(fileHeader)
- || memcmp(fileHeader.signature, "ASYLUM Music Format V1.0\0", 25)
- || fileHeader.numSamples > 64
- || !file.CanRead(256 + 64 * sizeof(AsylumSampleHeader) + 64 * 4 * 8 * fileHeader.numPatterns))
+ if(!file.ReadStruct(fileHeader))
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ if(!ValidateHeader(fileHeader))
{
+ return false;
+ }
+ if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(fileHeader))))
+ {
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
@@ -341,6 +383,37 @@
}
+static bool ValidateHeader(const AMFFileHeader &fileHeader)
+//---------------------------------------------------------
+{
+ if(std::memcmp(fileHeader.amf, "AMF", 3)
+ || fileHeader.version < 8 || fileHeader.version > 14
+ || ((fileHeader.numChannels < 1 || fileHeader.numChannels > 32) && fileHeader.version >= 10)
+ )
+ {
+ return false;
+ }
+ return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderAMF_DSMI(MemoryFileReader file, const uint64 *pfilesize)
+//---------------------------------------------------------------------------------------------------------
+{
+ AMFFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
bool CSoundFile::ReadAMF_DSMI(FileReader &file, ModLoadingFlags loadFlags)
//------------------------------------------------------------------------
{
@@ -347,14 +420,16 @@
file.Rewind();
AMFFileHeader fileHeader;
- if(!file.ReadStruct(fileHeader)
- || memcmp(fileHeader.amf, "AMF", 3)
- || fileHeader.version < 8 || fileHeader.version > 14
- || ((fileHeader.numChannels < 1 || fileHeader.numChannels > 32) && fileHeader.version >= 10))
+ if(!file.ReadStruct(fileHeader))
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ if(!ValidateHeader(fileHeader))
{
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
Index: soundlib/Load_ams.cpp
===================================================================
--- soundlib/Load_ams.cpp (revision 8929)
+++ soundlib/Load_ams.cpp (working copy)
@@ -332,21 +332,76 @@
MPT_BINARY_STRUCT(AMSSampleHeader, 17)
+static bool ValidateHeader(const AMSFileHeader &fileHeader)
+//---------------------------------------------------------
+{
+ if(fileHeader.versionHigh != 0x01)
+ {
+ return false;
+ }
+ return true;
+}
+
+
+static uint64 GetHeaderMinimumAdditionalSize(const AMSFileHeader &fileHeader)
+//---------------------------------------------------------------------------
+{
+ return fileHeader.extraSize + 3u + fileHeader.numSamps * (1u + sizeof(AMSSampleHeader)) + fileHeader.numOrds * 2u + fileHeader.numPats * 4u;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderAMS(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ if(!file.CanRead(7))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!file.ReadMagic("Extreme"))
+ {
+ return ProbeFailure;
+ }
+ AMSFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader));
+}
+
+
bool CSoundFile::ReadAMS(FileReader &file, ModLoadingFlags loadFlags)
//-------------------------------------------------------------------
{
file.Rewind();
+ if(!file.ReadMagic("Extreme"))
+ {
+ return false;
+ }
AMSFileHeader fileHeader;
- if(!file.ReadMagic("Extreme")
- || !file.ReadStruct(fileHeader)
- || !file.Skip(fileHeader.extraSize)
- || !file.CanRead(3u + fileHeader.numSamps * (1u + sizeof(AMSSampleHeader)) + fileHeader.numOrds * 2u + fileHeader.numPats * 4u)
- || fileHeader.versionHigh != 0x01)
+ if(!file.ReadStruct(fileHeader))
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ if(!ValidateHeader(fileHeader))
{
+ return false;
+ }
+ if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(fileHeader))))
+ {
+ return false;
+ }
+ if(!file.Skip(fileHeader.extraSize))
+ {
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
@@ -641,30 +696,90 @@
MPT_BINARY_STRUCT(AMS2Description, 11)
+static bool ValidateHeader(const AMS2FileHeader &fileHeader)
+//----------------------------------------------------------
+{
+ if(fileHeader.versionHigh != 2 || fileHeader.versionLow > 2)
+ {
+ return false;
+ }
+ return true;
+}
+
+
+static uint64 GetHeaderMinimumAdditionalSize(const AMS2FileHeader &fileHeader)
+//----------------------------------------------------------------------------
+{
+ return 36u + sizeof(AMS2Description) + fileHeader.numIns * 2u + fileHeader.numOrds * 2u + fileHeader.numPats * 4u;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderAMS2(MemoryFileReader file, const uint64 *pfilesize)
+//-----------------------------------------------------------------------------------------------------
+{
+ if(!file.CanRead(7))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!file.ReadMagic("AMShdr\x1A"))
+ {
+ return ProbeFailure;
+ }
+ if(!file.CanRead(1))
+ {
+ return ProbeWantMoreData;
+ }
+ const uint8 songNameLength = file.ReadUint8();
+ if(!file.Skip(songNameLength))
+ {
+ return ProbeWantMoreData;
+ }
+ AMS2FileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader));
+}
+
+
bool CSoundFile::ReadAMS2(FileReader &file, ModLoadingFlags loadFlags)
//--------------------------------------------------------------------
{
file.Rewind();
- AMS2FileHeader fileHeader;
if(!file.ReadMagic("AMShdr\x1A"))
{
return false;
}
-
- InitializeGlobals(MOD_TYPE_AMS2);
-
- if(!file.ReadSizedString<uint8le, mpt::String::spacePadded>(m_songName)
- || !file.ReadStruct(fileHeader)
- || fileHeader.versionHigh != 2 || fileHeader.versionLow > 2
- || !file.CanRead(36u + sizeof(AMS2Description) + fileHeader.numIns * 2u + fileHeader.numOrds * 2u + fileHeader.numPats * 4u))
+ if(!file.ReadSizedString<uint8le, mpt::String::spacePadded>(m_songName))
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ AMS2FileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
{
+ return false;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return false;
+ }
+ if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(fileHeader))))
+ {
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
+ InitializeGlobals(MOD_TYPE_AMS2);
+
m_nInstruments = fileHeader.numIns;
m_nChannels = 32;
SetupMODPanning(true);
Index: soundlib/Load_dbm.cpp
===================================================================
--- soundlib/Load_dbm.cpp (revision 8929)
+++ soundlib/Load_dbm.cpp (working copy)
@@ -293,19 +293,51 @@
}
+static bool ValidateHeader(const DBMFileHeader &fileHeader)
+//---------------------------------------------------------
+{
+ if(std::memcmp(fileHeader.dbm0, "DBM0", 4)
+ || fileHeader.trkVerHi > 3)
+ {
+ return false;
+ }
+ return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderDBM(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ DBMFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
bool CSoundFile::ReadDBM(FileReader &file, ModLoadingFlags loadFlags)
//-------------------------------------------------------------------
{
- DBMFileHeader fileHeader;
file.Rewind();
- if(!file.ReadStruct(fileHeader)
- || memcmp(fileHeader.dbm0, "DBM0", 4)
- || fileHeader.trkVerHi > 3)
+ DBMFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ if(!ValidateHeader(fileHeader))
{
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
Index: soundlib/Load_digi.cpp
===================================================================
--- soundlib/Load_digi.cpp (revision 8929)
+++ soundlib/Load_digi.cpp (working copy)
@@ -73,6 +73,36 @@
}
+static bool ValidateHeader(const DIGIFileHeader &fileHeader)
+{
+ if(std::memcmp(fileHeader.signature, "DIGI Booster module\0", 20)
+ || !fileHeader.numChannels
+ || fileHeader.numChannels > 8
+ || fileHeader.lastOrdIndex > 127)
+ {
+ return false;
+ }
+ return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderDIGI(MemoryFileReader file, const uint64 *pfilesize)
+//-----------------------------------------------------------------------------------------------------
+{
+ DIGIFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
bool CSoundFile::ReadDIGI(FileReader &file, ModLoadingFlags loadFlags)
//--------------------------------------------------------------------
{
@@ -79,15 +109,16 @@
file.Rewind();
DIGIFileHeader fileHeader;
- if(!file.ReadStruct(fileHeader)
- || memcmp(fileHeader.signature, "DIGI Booster module\0", 20)
- || !fileHeader.numChannels
- || fileHeader.numChannels > 8
- || fileHeader.lastOrdIndex > 127)
+ if(!file.ReadStruct(fileHeader))
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ if(!ValidateHeader(fileHeader))
{
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
Index: soundlib/Load_dmf.cpp
===================================================================
--- soundlib/Load_dmf.cpp (revision 8929)
+++ soundlib/Load_dmf.cpp (working copy)
@@ -887,18 +887,51 @@
}
+static bool ValidateHeader(const DMFFileHeader &fileHeader)
+//---------------------------------------------------------
+{
+ if(std::memcmp(fileHeader.signature, "DDMF", 4)
+ || !fileHeader.version || fileHeader.version > 10)
+ {
+ return false;
+ }
+ return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderDMF(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ DMFFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
bool CSoundFile::ReadDMF(FileReader &file, ModLoadingFlags loadFlags)
//-------------------------------------------------------------------
{
+ file.Rewind();
+
DMFFileHeader fileHeader;
- file.Rewind();
- if(!file.ReadStruct(fileHeader)
- || memcmp(fileHeader.signature, "DDMF", 4)
- || !fileHeader.version || fileHeader.version > 10)
+ if(!file.ReadStruct(fileHeader))
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ if(!ValidateHeader(fileHeader))
{
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
Index: soundlib/Load_dsm.cpp
===================================================================
--- soundlib/Load_dsm.cpp (revision 8929)
+++ soundlib/Load_dsm.cpp (working copy)
@@ -100,40 +100,100 @@
MPT_BINARY_STRUCT(DSMSampleHeader, 64)
-bool CSoundFile::ReadDSM(FileReader &file, ModLoadingFlags loadFlags)
-//-------------------------------------------------------------------
+struct DSMHeader
{
- file.Rewind();
+ char fileMagic0[4];
+ char fileMagic1[4];
+ char fileMagic2[4];
+};
- char fileMagic0[4], fileMagic1[4], fileMagic2[4];
- if(!file.ReadArray(fileMagic0)) return false;
- if(!file.ReadArray(fileMagic1)) return false;
- if(!file.ReadArray(fileMagic2)) return false;
+MPT_BINARY_STRUCT(DSMHeader, 12)
- if(!memcmp(fileMagic0, "RIFF", 4)
- && !memcmp(fileMagic2, "DSMF", 4))
+
+static bool ValidateHeader(const DSMHeader &fileHeader)
+//-----------------------------------------------------
+{
+ if(!std::memcmp(fileHeader.fileMagic0, "RIFF", 4)
+ && !std::memcmp(fileHeader.fileMagic2, "DSMF", 4))
{
// "Normal" DSM files with RIFF header
// <RIFF> <file size> <DSMF>
- } else if(!memcmp(fileMagic0, "DSMF", 4))
+ return true;
+ } else if(!std::memcmp(fileHeader.fileMagic0, "DSMF", 4))
{
// DSM files with alternative header
// <DSMF> <4 bytes, usually 4x NUL or RIFF> <file size> <4 bytes, usually DSMF but not always>
- file.Skip(4);
+ return true;
} else
{
return false;
}
+}
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderDSM(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ DSMHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ if(std::memcmp(fileHeader.fileMagic0, "DSMF", 4) == 0)
+ {
+ if(!file.Skip(4))
+ {
+ return ProbeWantMoreData;
+ }
+ }
DSMChunk chunkHeader;
+ if(!file.ReadStruct(chunkHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(std::memcmp(chunkHeader.magic, "SONG", 4))
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
- file.ReadStruct(chunkHeader);
+
+bool CSoundFile::ReadDSM(FileReader &file, ModLoadingFlags loadFlags)
+//-------------------------------------------------------------------
+{
+ file.Rewind();
+
+ DSMHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return false;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return false;
+ }
+ if(std::memcmp(fileHeader.fileMagic0, "DSMF", 4) == 0)
+ {
+ file.Skip(4);
+ }
+ DSMChunk chunkHeader;
+ if(!file.ReadStruct(chunkHeader))
+ {
+ return false;
+ }
// Technically, the song chunk could be anywhere in the file, but we're going to simplify
// things by not using a chunk header here and just expect it to be right at the beginning.
- if(memcmp(chunkHeader.magic, "SONG", 4))
+ if(std::memcmp(chunkHeader.magic, "SONG", 4))
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ if(loadFlags == onlyVerifyHeader)
{
return true;
}
Index: soundlib/Load_dtm.cpp
===================================================================
--- soundlib/Load_dtm.cpp (revision 8929)
+++ soundlib/Load_dtm.cpp (working copy)
@@ -181,6 +181,37 @@
MPT_BINARY_STRUCT(DTMText, 12)
+static bool ValidateHeader(const DTMFileHeader &fileHeader)
+//---------------------------------------------------------
+{
+ if(std::memcmp(fileHeader.magic, "D.T.", 4)
+ || fileHeader.headerSize < sizeof(fileHeader) - 8u
+ || fileHeader.headerSize > 256 // Excessively long song title?
+ || fileHeader.type != 0)
+ {
+ return false;
+ }
+ return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderDTM(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ DTMFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
bool CSoundFile::ReadDTM(FileReader &file, ModLoadingFlags loadFlags)
//-------------------------------------------------------------------
{
@@ -187,15 +218,16 @@
file.Rewind();
DTMFileHeader fileHeader;
- if(!file.ReadStruct(fileHeader)
- || memcmp(fileHeader.magic, "D.T.", 4)
- || fileHeader.headerSize < sizeof(fileHeader) - 8u
- || fileHeader.headerSize > 256 // Excessively long song title?
- || fileHeader.type != 0)
+ if(!file.ReadStruct(fileHeader))
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ if(!ValidateHeader(fileHeader))
{
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
Index: soundlib/Load_far.cpp
===================================================================
--- soundlib/Load_far.cpp (revision 8929)
+++ soundlib/Load_far.cpp (working copy)
@@ -102,6 +102,46 @@
MPT_BINARY_STRUCT(FARSampleHeader, 48)
+static bool ValidateHeader(const FARFileHeader &fileHeader)
+//---------------------------------------------------------
+{
+ if(std::memcmp(fileHeader.magic, "FAR\xFE", 4) != 0
+ || std::memcmp(fileHeader.eof, "\x0D\x0A\x1A", 3)
+ )
+ {
+ return false;
+ }
+ if(fileHeader.headerLength < sizeof(FARFileHeader))
+ {
+ return false;
+ }
+ return true;
+}
+
+
+static uint64 GetHeaderMinimumAdditionalSize(const FARFileHeader &fileHeader)
+//---------------------------------------------------------------------------
+{
+ return fileHeader.headerLength - sizeof(FARFileHeader);
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderFAR(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ FARFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader));
+}
+
+
bool CSoundFile::ReadFAR(FileReader &file, ModLoadingFlags loadFlags)
//-------------------------------------------------------------------
{
@@ -108,14 +148,20 @@
file.Rewind();
FARFileHeader fileHeader;
- if(!file.ReadStruct(fileHeader)
- || memcmp(fileHeader.magic, "FAR\xFE", 4) != 0
- || memcmp(fileHeader.eof, "\x0D\x0A\x1A", 3)
- || !file.LengthIsAtLeast(fileHeader.headerLength))
+ if(!file.ReadStruct(fileHeader))
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ if(!ValidateHeader(fileHeader))
{
+ return false;
+ }
+ if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(fileHeader))))
+ {
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
Index: soundlib/Load_gdm.cpp
===================================================================
--- soundlib/Load_gdm.cpp (revision 8929)
+++ soundlib/Load_gdm.cpp (working copy)
@@ -90,28 +90,61 @@
MPT_BINARY_STRUCT(GDMSampleHeader, 62)
-bool CSoundFile::ReadGDM(FileReader &file, ModLoadingFlags loadFlags)
-//-------------------------------------------------------------------
+static const MODTYPE gdmFormatOrigin[] =
{
- file.Rewind();
+ MOD_TYPE_NONE, MOD_TYPE_MOD, MOD_TYPE_MTM, MOD_TYPE_S3M, MOD_TYPE_669, MOD_TYPE_FAR, MOD_TYPE_ULT, MOD_TYPE_STM, MOD_TYPE_MED, MOD_TYPE_PSM
+};
- const MODTYPE gdmFormatOrigin[] =
- {
- MOD_TYPE_NONE, MOD_TYPE_MOD, MOD_TYPE_MTM, MOD_TYPE_S3M, MOD_TYPE_669, MOD_TYPE_FAR, MOD_TYPE_ULT, MOD_TYPE_STM, MOD_TYPE_MED, MOD_TYPE_PSM
- };
- GDMFileHeader fileHeader;
- if(!file.ReadStruct(fileHeader)
- || memcmp(fileHeader.magic, "GDM\xFE", 4)
+static bool ValidateHeader(const GDMFileHeader &fileHeader)
+//---------------------------------------------------------
+{
+ if(std::memcmp(fileHeader.magic, "GDM\xFE", 4)
|| fileHeader.dosEOF[0] != 13 || fileHeader.dosEOF[1] != 10 || fileHeader.dosEOF[2] != 26
- || memcmp(fileHeader.magic2, "GMFS", 4)
+ || std::memcmp(fileHeader.magic2, "GMFS", 4)
|| fileHeader.formatMajorVer != 1 || fileHeader.formatMinorVer != 0
- || fileHeader.originalFormat >= CountOf(gdmFormatOrigin)
+ || fileHeader.originalFormat >= mpt::size(gdmFormatOrigin)
|| fileHeader.originalFormat == 0)
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderGDM(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ GDMFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
{
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
+bool CSoundFile::ReadGDM(FileReader &file, ModLoadingFlags loadFlags)
+//-------------------------------------------------------------------
+{
+ file.Rewind();
+
+ GDMFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return false;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
Index: soundlib/Load_imf.cpp
===================================================================
--- soundlib/Load_imf.cpp (revision 8929)
+++ soundlib/Load_imf.cpp (working copy)
@@ -351,19 +351,84 @@
}
}
+
+static bool ValidateHeader(const IMFFileHeader &fileHeader)
+//---------------------------------------------------------
+{
+ if(std::memcmp(fileHeader.im10, "IM10", 4)
+ || fileHeader.ordNum > 256
+ || fileHeader.insNum >= MAX_INSTRUMENTS
+ )
+ {
+ return false;
+ }
+ bool channelFound = false;
+ for(uint8 chn = 0; chn < 32; chn++)
+ {
+ switch(fileHeader.channels[chn].status)
+ {
+ case 0: // enabled; don't worry about it
+ channelFound = true;
+ break;
+ case 1: // mute
+ channelFound = true;
+ break;
+ case 2: // disabled
+ // nothing
+ break;
+ default: // uhhhh.... freak out
+ return false;
+ }
+ }
+ if(!channelFound)
+ {
+ return false;
+ }
+ return true;
+}
+
+
+static uint64 GetHeaderMinimumAdditionalSize(const IMFFileHeader &fileHeader)
+//---------------------------------------------------------------------------
+{
+ MPT_UNREFERENCED_PARAMETER(fileHeader);
+ return 256;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderIMF(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ IMFFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader));
+}
+
+
bool CSoundFile::ReadIMF(FileReader &file, ModLoadingFlags loadFlags)
//-------------------------------------------------------------------
{
IMFFileHeader fileHeader;
file.Rewind();
- if(!file.ReadStruct(fileHeader)
- || memcmp(fileHeader.im10, "IM10", 4)
- || fileHeader.ordNum > 256
- || fileHeader.insNum >= MAX_INSTRUMENTS
- || !file.CanRead(256))
+ if(!file.ReadStruct(fileHeader))
{
return false;
}
+ if(!ValidateHeader(fileHeader))
+ {
+ return false;
+ }
+ if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(fileHeader))))
+ {
+ return false;
+ }
// Read channel configuration
std::bitset<32> ignoreChannels; // bit set for each channel that's completely disabled
@@ -397,7 +462,9 @@
if(!detectedChannels)
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+
+ if(loadFlags == onlyVerifyHeader)
{
return true;
}
Index: soundlib/Load_it.cpp
===================================================================
--- soundlib/Load_it.cpp (revision 8929)
+++ soundlib/Load_it.cpp (working copy)
@@ -402,6 +402,43 @@
}
+static bool ValidateHeader(const ITFileHeader &fileHeader)
+//--------------------------------------------------------
+{
+ if((std::memcmp(fileHeader.id, "IMPM", 4) && std::memcmp(fileHeader.id, "tpm.", 4))
+ || fileHeader.insnum > 0xFF
+ || fileHeader.smpnum >= MAX_SAMPLES
+ )
+ {
+ return false;
+ }
+ return true;
+}
+
+
+static uint64 GetHeaderMinimumAdditionalSize(const ITFileHeader &fileHeader)
+//--------------------------------------------------------------------------
+{
+ return fileHeader.ordnum + (fileHeader.insnum + fileHeader.smpnum + fileHeader.patnum) * 4;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderIT(MemoryFileReader file, const uint64 *pfilesize)
+//---------------------------------------------------------------------------------------------------
+{
+ ITFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader));
+}
+
+
bool CSoundFile::ReadIT(FileReader &file, ModLoadingFlags loadFlags)
//------------------------------------------------------------------
{
@@ -408,15 +445,20 @@
file.Rewind();
ITFileHeader fileHeader;
- if(!file.ReadStruct(fileHeader)
- || (memcmp(fileHeader.id, "IMPM", 4) && memcmp(fileHeader.id, "tpm.", 4))
- || fileHeader.insnum > 0xFF
- || fileHeader.smpnum >= MAX_SAMPLES
- || !file.CanRead(fileHeader.ordnum + (fileHeader.insnum + fileHeader.smpnum + fileHeader.patnum) * 4))
+ if(!file.ReadStruct(fileHeader))
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ if(!ValidateHeader(fileHeader))
{
+ return false;
+ }
+ if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(fileHeader))))
+ {
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
Index: soundlib/Load_itp.cpp
===================================================================
--- soundlib/Load_itp.cpp (revision 8929)
+++ soundlib/Load_itp.cpp (working copy)
@@ -60,6 +60,54 @@
MPT_BINARY_STRUCT(ITPModCommand, 6)
+struct ITPHeader
+{
+ uint32le magic;
+ uint32le version;
+};
+
+MPT_BINARY_STRUCT(ITPHeader, 8)
+
+
+static bool ValidateHeader(const ITPHeader &hdr)
+//----------------------------------------------
+{
+ if(hdr.magic != MAGIC4BE('.','i','t','p'))
+ {
+ return false;
+ }
+ if(hdr.version > 0x00000103 || hdr.version < 0x00000100)
+ {
+ return false;
+ }
+ return true;
+}
+
+
+static uint64 GetHeaderMinimumAdditionalSize(const ITPHeader &hdr)
+//----------------------------------------------------------------
+{
+ MPT_UNREFERENCED_PARAMETER(hdr);
+ return 12 + 4 + 24 + 4 - sizeof(ITPHeader);
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderITP(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ ITPHeader hdr;
+ if(!file.ReadStruct(hdr))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(hdr))
+ {
+ return ProbeFailure;
+ }
+ return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(hdr));
+}
+
+
bool CSoundFile::ReadITProject(FileReader &file, ModLoadingFlags loadFlags)
//-------------------------------------------------------------------------
{
@@ -81,22 +129,29 @@
ITP_ITPEMBEDIH = 0x40000, // Embed instrument headers in project file
};
- uint32 version, size;
-
file.Rewind();
- // Check file ID
- if(!file.CanRead(12 + 4 + 24 + 4)
- || file.ReadUint32LE() != MAGIC4BE('.','i','t','p') // Magic bytes
- || (version = file.ReadUint32LE()) > 0x00000103 // Format version
- || version < 0x00000100)
+ ITPHeader hdr;
+ if(!file.ReadStruct(hdr))
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ if(!ValidateHeader(hdr))
{
+ return false;
+ }
+ if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(hdr))))
+ {
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
+ uint32 version, size;
+ version = hdr.version;
+
InitializeGlobals(MOD_TYPE_IT);
m_playBehaviour.reset();
file.ReadSizedString<uint32le, mpt::String::maybeNullTerminated>(m_songName);
Index: soundlib/Load_mdl.cpp
===================================================================
--- soundlib/Load_mdl.cpp (revision 8929)
+++ soundlib/Load_mdl.cpp (working copy)
@@ -422,18 +422,50 @@
}
+static bool ValidateHeader(const MDLFileHeader &fileHeader)
+//---------------------------------------------------------
+{
+ if(std::memcmp(fileHeader.id, "DMDL", 4)
+ || fileHeader.version >= 0x20)
+ {
+ return false;
+ }
+ return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderMDL(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ MDLFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
bool CSoundFile::ReadMDL(FileReader &file, ModLoadingFlags loadFlags)
//-------------------------------------------------------------------
{
file.Rewind();
MDLFileHeader fileHeader;
- if(!file.ReadStruct(fileHeader)
- || memcmp(fileHeader.id, "DMDL", 4)
- || fileHeader.version >= 0x20)
+ if(!file.ReadStruct(fileHeader))
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ if(!ValidateHeader(fileHeader))
{
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
Index: soundlib/Load_med.cpp
===================================================================
--- soundlib/Load_med.cpp (revision 8929)
+++ soundlib/Load_med.cpp (working copy)
@@ -493,22 +493,68 @@
}
+static bool ValidateHeader(const MEDMODULEHEADER &pmmh)
+//-----------------------------------------------------
+{
+ if(std::memcmp(pmmh.id, "MMD", 3)
+ || pmmh.id[3] < '0' || pmmh.id[3] > '3'
+ || pmmh.song == 0
+ )
+ {
+ return false;
+ }
+ return true;
+}
+
+
+static uint64 GetHeaderMinimumAdditionalSize(const MEDMODULEHEADER &pmmh)
+//-----------------------------------------------------------------------
+{
+ MPT_UNREFERENCED_PARAMETER(pmmh);
+ return sizeof(MMD0SONGHEADER);
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderMED(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ MEDMODULEHEADER pmmh;
+ if(!file.ReadStruct(pmmh))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(pmmh))
+ {
+ return ProbeFailure;
+ }
+ return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(pmmh));
+}
+
+
bool CSoundFile::ReadMed(FileReader &file, ModLoadingFlags loadFlags)
//------------------------------------------------------------------
{
file.Rewind();
MEDMODULEHEADER pmmh;
- uint32 dwSong;
- if(!file.CanRead(512)
- || !file.ReadStruct(pmmh)
- || memcmp(pmmh.id, "MMD", 3)
- || pmmh.id[3] < '0' || pmmh.id[3] > '3'
- || (dwSong = pmmh.song) == 0
- || !file.LengthIsAtLeast(dwSong + sizeof(MMD0SONGHEADER)))
+ if(!file.ReadStruct(pmmh))
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ if(!ValidateHeader(pmmh))
{
+ return false;
+ }
+ if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(pmmh))))
+ {
+ return false;
+ }
+ const uint32 dwSong = pmmh.song;
+ if(!file.LengthIsAtLeast(dwSong + sizeof(MMD0SONGHEADER)))
+ {
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
Index: soundlib/Load_mo3.cpp
===================================================================
--- soundlib/Load_mo3.cpp (revision 8929)
+++ soundlib/Load_mo3.cpp (working copy)
@@ -691,26 +691,74 @@
#endif // MPT_WITH_VORBIS && MPT_WITH_VORBISFILE
+struct MO3ContainerHeader
+{
+ char magic[3]; // MO3
+ uint8le version;
+ uint32le musicSize;
+};
+MPT_BINARY_STRUCT(MO3ContainerHeader, 8)
+
+
+static bool ValidateHeader(const MO3ContainerHeader &containerHeader)
+//-------------------------------------------------------------------
+{
+ if(std::memcmp(containerHeader.magic, "MO3", 3))
+ {
+ return false;
+ }
+ if(containerHeader.musicSize <= sizeof(MO3FileHeader))
+ {
+ return false;
+ }
+ if(containerHeader.version > 5)
+ {
+ return false;
+ }
+ return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderMO3(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ MO3ContainerHeader containerHeader;
+ if(!file.ReadStruct(containerHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(containerHeader))
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
bool CSoundFile::ReadMO3(FileReader &file, ModLoadingFlags loadFlags)
//-------------------------------------------------------------------
{
file.Rewind();
- if(!file.CanRead(12) || !file.ReadMagic("MO3"))
+ MO3ContainerHeader containerHeader;
+ if(!file.ReadStruct(containerHeader))
{
return false;
}
- const uint8 version = file.ReadUint8();
- const uint32 musicSize = file.ReadUint32LE();
- if(musicSize <= sizeof(MO3FileHeader) || version > 5)
+ if(!ValidateHeader(containerHeader))
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ if(loadFlags == onlyVerifyHeader)
{
return true;
}
+ const uint8 version = containerHeader.version;
+ const uint32 musicSize = containerHeader.musicSize;
+
uint32 compressedSize = uint32_max;
if(version >= 5)
{
Index: soundlib/Load_mod.cpp
===================================================================
--- soundlib/Load_mod.cpp (revision 8929)
+++ soundlib/Load_mod.cpp (working copy)
@@ -654,20 +654,20 @@
}
-bool CSoundFile::ReadMod(FileReader &file, ModLoadingFlags loadFlags)
-//-------------------------------------------------------------------
+struct MODMagicResult
{
- char magic[4];
- if(!file.Seek(1080) || !file.ReadArray(magic))
- {
- return false;
- }
+ CHANNELINDEX m_nChannels = 4;
+ mpt::ustring m_madeWithTracker = mpt::ustring();
+ bool isNoiseTracker = false;
+ bool isStartrekker = false;
+ bool isGenericMultiChannel = false;
+ bool setMODVBlankTiming = false;
+};
- InitializeGlobals(MOD_TYPE_MOD);
- m_nChannels = 4;
- bool isNoiseTracker = false, isStartrekker = false, isGenericMultiChannel = false;
- // Check MOD Magic
+static bool CheckMODMagic(const char magic[4], MODMagicResult *result)
+{
+ MODMagicResult *r = result;
if(IsMagic(magic, "M.K.") // ProTracker and compatible
|| IsMagic(magic, "M!K!") // ProTracker (>64 patterns)
|| IsMagic(magic, "PATT") // ProTracker 3.6
@@ -674,66 +674,143 @@
|| IsMagic(magic, "NSMS") // kingdomofpleasure.mod by bee hunter
|| IsMagic(magic, "LARD")) // judgement_day_gvine.mod by 4-mat
{
- m_nChannels = 4;
- m_madeWithTracker = MPT_USTRING("Generic ProTracker or compatible");
+ if(r)
+ {
+ r->m_nChannels = 4;
+ r->m_madeWithTracker = MPT_USTRING("Generic ProTracker or compatible");
+ }
} else if(IsMagic(magic, "M&K!") // "His Master's Noise" musicdisk
|| IsMagic(magic, "FEST") // "His Master's Noise" musicdisk
|| IsMagic(magic, "N.T."))
{
- m_nChannels = 4;
- m_madeWithTracker = MPT_USTRING("NoiseTracker");
- isNoiseTracker = true;
+ if(r)
+ {
+ r->m_nChannels = 4;
+ r->m_madeWithTracker = MPT_USTRING("NoiseTracker");
+ r->isNoiseTracker = true;
+ }
} else if(IsMagic(magic, "OKTA")
|| IsMagic(magic, "OCTA"))
{
// Oktalyzer
- m_nChannels = 8;
- m_madeWithTracker = MPT_USTRING("Oktalyzer");
+ if(r)
+ {
+ r->m_nChannels = 8;
+ r->m_madeWithTracker = MPT_USTRING("Oktalyzer");
+ }
} else if(IsMagic(magic, "CD81")
|| IsMagic(magic, "CD61"))
{
// Octalyser on Atari STe/Falcon
- m_nChannels = magic[2] - '0';
- m_madeWithTracker = MPT_USTRING("Octalyser (Atari)");
+ if(r)
+ {
+ r->m_nChannels = magic[2] - '0';
+ r->m_madeWithTracker = MPT_USTRING("Octalyser (Atari)");
+ }
} else if(!memcmp(magic, "FA0", 3) && magic[3] >= '4' && magic[3] <= '8')
{
// Digital Tracker on Atari Falcon
- m_nChannels = magic[3] - '0';
- m_madeWithTracker = MPT_USTRING("Digital Tracker");
+ if(r)
+ {
+ r->m_nChannels = magic[3] - '0';
+ r->m_madeWithTracker = MPT_USTRING("Digital Tracker");
+ }
} else if((!memcmp(magic, "FLT", 3) || !memcmp(magic, "EXO", 3)) && magic[3] >= '4' && magic[3] <= '9')
{
// FLTx / EXOx - Startrekker by Exolon / Fairlight
- m_nChannels = magic[3] - '0';
- m_madeWithTracker = MPT_USTRING("Startrekker");
- isStartrekker = true;
- m_playBehaviour.set(kMODVBlankTiming);
+ if(r)
+ {
+ r->m_nChannels = magic[3] - '0';
+ r->m_madeWithTracker = MPT_USTRING("Startrekker");
+ r->isStartrekker = true;
+ r->setMODVBlankTiming = true;
+ }
} else if(magic[0] >= '1' && magic[0] <= '9' && !memcmp(magic + 1, "CHN", 3))
{
// xCHN - Many trackers
- m_nChannels = magic[0] - '0';
- m_madeWithTracker = MPT_USTRING("Generic MOD-compatible Tracker");
- isGenericMultiChannel = true;
+ if(r)
+ {
+ r->m_nChannels = magic[0] - '0';
+ r->m_madeWithTracker = MPT_USTRING("Generic MOD-compatible Tracker");
+ r->isGenericMultiChannel = true;
+ }
} else if(magic[0] >= '1' && magic[0] <= '9' && magic[1]>='0' && magic[1] <= '9'
&& (!memcmp(magic + 2, "CH", 2) || !memcmp(magic + 2, "CN", 2)))
{
// xxCN / xxCH - Many trackers
- m_nChannels = (magic[0] - '0') * 10 + magic[1] - '0';
- m_madeWithTracker = MPT_USTRING("Generic MOD-compatible Tracker");
- isGenericMultiChannel = true;
+ if(r)
+ {
+ r->m_nChannels = (magic[0] - '0') * 10 + magic[1] - '0';
+ r->m_madeWithTracker = MPT_USTRING("Generic MOD-compatible Tracker");
+ r->isGenericMultiChannel = true;
+ }
} else if(!memcmp(magic, "TDZ", 3) && magic[3] >= '4' && magic[3] <= '9')
{
// TDZx - TakeTracker
- m_nChannels = magic[3] - '0';
- m_madeWithTracker = MPT_USTRING("TakeTracker");
+ if(r)
+ {
+ r->m_nChannels = magic[3] - '0';
+ r->m_madeWithTracker = MPT_USTRING("TakeTracker");
+ }
} else
{
return false;
}
+ return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderMOD(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ if(!file.CanRead(1080 + 4))
+ {
+ return ProbeWantMoreData;
+ }
+ file.Seek(1080);
+ char magic[4];
+ file.ReadArray(magic);
+ if(!CheckMODMagic(magic, nullptr))
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
+bool CSoundFile::ReadMod(FileReader &file, ModLoadingFlags loadFlags)
+//-------------------------------------------------------------------
+{
+ char magic[4];
+ if(!file.Seek(1080) || !file.ReadArray(magic))
+ {
+ return false;
+ }
+
+ InitializeGlobals(MOD_TYPE_MOD);
+
+ MODMagicResult modMagicResult;
+ if(!CheckMODMagic(magic, &modMagicResult))
+ {
+ return false;
+ }
+
if(loadFlags == onlyVerifyHeader)
{
return true;
}
+ m_nChannels = modMagicResult.m_nChannels;
+ m_madeWithTracker = modMagicResult.m_madeWithTracker;
+ bool isNoiseTracker = modMagicResult.isNoiseTracker;
+ bool isStartrekker = modMagicResult.isStartrekker;
+ bool isGenericMultiChannel = modMagicResult.isGenericMultiChannel;
+ if(modMagicResult.setMODVBlankTiming)
+ {
+ m_playBehaviour.set(kMODVBlankTiming);
+ }
+
LimitMax(m_nChannels, MAX_BASECHANNELS);
// Startrekker 8 channel mod (needs special treatment, see below)
@@ -1166,8 +1243,8 @@
// Check if a name string is valid (i.e. doesn't contain binary garbage data)
template<size_t N>
-static uint32 CountInvalidChars(char (&name)[N])
-//----------------------------------------------
+static uint32 CountInvalidChars(const char (&name)[N])
+//----------------------------------------------------
{
uint32 invalidChars = 0;
for(auto c : name)
@@ -1195,25 +1272,127 @@
};
-bool CSoundFile::ReadM15(FileReader &file, ModLoadingFlags loadFlags)
-//-------------------------------------------------------------------
+
+struct M15FileHeaders
{
- file.Rewind();
+ char songname[20];
+ MODSampleHeader sampleHeaders[15];
+ MODFileHeader fileHeader;
+};
- char songname[20];
- file.ReadArray(songname);
+MPT_BINARY_STRUCT(M15FileHeaders, 20 + 15 * 30 + 130)
+
+static bool ValidateHeader(const M15FileHeaders &fileHeaders)
+{
// In theory, sample and song names should only ever contain printable ASCII chars and null.
// 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: 20 bogus characters in total
// or more than 5 invalid characters just in the title alone.
- uint32 invalidChars = CountInvalidChars(songname);
- if(invalidChars > 5 || !file.CanRead(sizeof(MODSampleHeader) * 15 + sizeof(MODFileHeader)))
+ uint32 invalidChars = CountInvalidChars(fileHeaders.songname);
+ if(invalidChars > 5)
{
return false;
}
+ SmpLength totalSampleLen = 0;
+ uint8 allVolumes = 0;
+
+ for(SAMPLEINDEX smp = 0; smp < 15; smp++)
+ {
+ const MODSampleHeader &sampleHeader = fileHeaders.sampleHeaders[smp];
+
+ invalidChars += CountInvalidChars(sampleHeader.name);
+
+ // Sanity checks - invalid character count adjusted for ata.mod (MD5 937b79b54026fa73a1a4d3597c26eace, SHA1 3322ca62258adb9e0ae8e9afe6e0c29d39add874)
+ if(invalidChars > 48
+ || sampleHeader.volume > 64
+ || sampleHeader.finetune != 0
+ || sampleHeader.length > 32768)
+ {
+ return false;
+ }
+
+ totalSampleLen += sampleHeader.length;
+ allVolumes |= sampleHeader.volume;
+
+ }
+
+ // 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)
+ {
+ return false;
+ }
+
+ // Sanity check: No more than 128 positions. ST's GUI limits tempo to [1, 220].
+ // There are some mods with a tempo of 0 (explora3-death.mod) though, so ignore the lower limit.
+ if(fileHeaders.fileHeader.numOrders > 128 || fileHeaders.fileHeader.restartPos > 220)
+ {
+ return false;
+ }
+
+ for(uint8 ord : fileHeaders.fileHeader.orderList)
+ {
+ // Sanity check: 64 patterns max.
+ if(ord > 63)
+ {
+ return false;
+ }
+ }
+
+ bool allPatternsNull = true;
+ for(uint8 pat : fileHeaders.fileHeader.orderList)
+ {
+ if(pat != 0 && pat < 128)
+ {
+ allPatternsNull = false;
+ }
+ }
+ if(fileHeaders.fileHeader.restartPos == 0 && fileHeaders.fileHeader.numOrders == 0 && allPatternsNull)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderM15(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ M15FileHeaders fileHeaders;
+ if(!file.ReadStruct(fileHeaders))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeaders))
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
+bool CSoundFile::ReadM15(FileReader &file, ModLoadingFlags loadFlags)
+//-------------------------------------------------------------------
+{
+ file.Rewind();
+
+ M15FileHeaders fileHeaders;
+ if(!file.ReadStruct(fileHeaders))
+ {
+ return false;
+ }
+ if(!ValidateHeader(fileHeaders))
+ {
+ return false;
+ }
+
+ char songname[20];
+ std::memcpy(songname, fileHeaders.songname, 20);
+
InitializeGlobals(MOD_TYPE_MOD);
m_playBehaviour.reset(kMODOneShotLoops);
m_playBehaviour.set(kMODIgnorePanning);
@@ -1224,26 +1403,15 @@
bool hasDiskNames = true;
SmpLength totalSampleLen = 0;
- uint8 allVolumes = 0;
m_nSamples = 15;
+ file.Seek(20);
for(SAMPLEINDEX smp = 1; smp <= 15; smp++)
{
MODSampleHeader sampleHeader;
ReadSample(file, sampleHeader, Samples[smp], m_szNames[smp], true);
- invalidChars += CountInvalidChars(sampleHeader.name);
- // Sanity checks - invalid character count adjusted for ata.mod (MD5 937b79b54026fa73a1a4d3597c26eace, SHA1 3322ca62258adb9e0ae8e9afe6e0c29d39add874)
- if(invalidChars > 48
- || sampleHeader.volume > 64
- || sampleHeader.finetune != 0
- || sampleHeader.length > 32768)
- {
- return false;
- }
-
totalSampleLen += Samples[smp].nLength;
- allVolumes |= sampleHeader.volume;
if(m_szNames[smp][0] && ((memcmp(m_szNames[smp], "st-", 3) && memcmp(m_szNames[smp], "ST-", 3)) || m_szNames[smp][5] != ':'))
{
@@ -1264,36 +1432,22 @@
minVersion = std::max(minVersion, MST1_00);
}
- // 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)
- return false;
-
MODFileHeader fileHeader;
file.ReadStruct(fileHeader);
- // Sanity check: No more than 128 positions. ST's GUI limits tempo to [1, 220].
- // There are some mods with a tempo of 0 (explora3-death.mod) though, so ignore the lower limit.
- if(fileHeader.numOrders > 128 || fileHeader.restartPos > 220)
- return false;
+ ReadOrderFromArray(Order(), fileHeader.orderList);
+ PATTERNINDEX numPatterns = GetNumPatterns(file, Order(), fileHeader.numOrders, totalSampleLen, m_nChannels, false);
- for(uint8 ord : fileHeader.orderList)
+ // Most likely just a file with lots of NULs at the start
+ if(fileHeader.restartPos == 0 && fileHeader.numOrders == 0 && numPatterns <= 1)
{
- // Sanity check: 64 patterns max.
- if(ord > 63)
- return false;
+ return false;
}
- ReadOrderFromArray(Order(), fileHeader.orderList);
- PATTERNINDEX numPatterns = GetNumPatterns(file, Order(), fileHeader.numOrders, totalSampleLen, m_nChannels, false);
-
// Let's see if the file is too small (including some overhead for broken files like sll7.mod or ghostbus.mod)
if(file.BytesLeft() + 65536 < numPatterns * 64u * 4u + totalSampleLen)
return false;
- // Most likely just a file with lots of NULs at the start
- if(fileHeader.restartPos == 0 && fileHeader.numOrders == 0 && numPatterns <= 1)
- return false;
-
if(loadFlags == onlyVerifyHeader)
return true;
@@ -1579,6 +1733,55 @@
}
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderICE(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ if(!file.CanRead(1464 + 4))
+ {
+ return ProbeWantMoreData;
+ }
+ file.Seek(1464);
+ char magic[4];
+ file.ReadArray(magic);
+ if(!IsMagic(magic, "MTN\0") && !IsMagic(magic, "IT10"))
+ {
+ return ProbeFailure;
+ }
+ file.Seek(20);
+ uint32 invalidChars = 0;
+ for(SAMPLEINDEX smp = 1; smp <= 31; smp++)
+ {
+ MODSampleHeader sampleHeader;
+ if(!file.ReadStruct(sampleHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ invalidChars += CountInvalidChars(sampleHeader.name);
+ }
+ if(invalidChars > 256)
+ {
+ return ProbeFailure;
+ }
+ const uint8 numOrders = file.ReadUint8();
+ const uint8 numTracks = file.ReadUint8();
+ if(numOrders > 128)
+ {
+ return ProbeFailure;
+ }
+ uint8 tracks[128 * 4];
+ file.ReadArray(tracks);
+ for(auto track : tracks)
+ {
+ if(track > numTracks)
+ {
+ return ProbeFailure;
+ }
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
// SoundTracker 2.6 / Ice Tracker variation of the MOD format
// The only real difference to other SoundTracker formats is the way patterns are stored:
// Every pattern consists of four independent, re-usable tracks.
@@ -1597,11 +1800,15 @@
m_playBehaviour.set(kMODSampleSwap); // untested
if(IsMagic(magic, "MTN\0"))
+ {
m_madeWithTracker = MPT_USTRING("SoundTracker 2.6");
- else if(IsMagic(magic, "IT10"))
+ } else if(IsMagic(magic, "IT10"))
+ {
m_madeWithTracker = MPT_USTRING("Ice Tracker 1.0 / 1.1");
- else
+ } else
+ {
return false;
+ }
// Reading song title
file.Seek(0);
@@ -1623,7 +1830,9 @@
const uint8 numOrders = file.ReadUint8();
const uint8 numTracks = file.ReadUint8();
if(numOrders > 128)
+ {
return false;
+ }
uint8 tracks[128 * 4];
file.ReadArray(tracks);
@@ -1630,11 +1839,15 @@
for(auto track : tracks)
{
if(track > numTracks)
+ {
return false;
+ }
}
if(loadFlags == onlyVerifyHeader)
+ {
return true;
+ }
// Now we can be pretty sure that this is a valid MOD file. Set up default song settings.
m_nChannels = 4;
@@ -1732,6 +1945,48 @@
+struct PT36Header
+{
+ char magicFORM[4]; // "FORM"
+ uint8be dummy1[4];
+ char magicMODL[4]; // "MODL"
+};
+
+MPT_BINARY_STRUCT(PT36Header, 12);
+
+
+static bool ValidateHeader(const PT36Header &fileHeader)
+//------------------------------------------------------
+{
+ if(std::memcmp(fileHeader.magicFORM, "FORM", 4))
+ {
+ return false;
+ }
+ if(std::memcmp(fileHeader.magicMODL, "MODL", 4))
+ {
+ return false;
+ }
+ return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderPT36(MemoryFileReader file, const uint64 *pfilesize)
+//-----------------------------------------------------------------------------------------------------
+{
+ PT36Header fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
// ProTracker 3.6 version of the MOD format
// Basically just a normal ProTracker mod with different magic, wrapped in an IFF file.
// The "PTDT" chunk is passed to the normal MOD loader.
@@ -1739,16 +1994,20 @@
//--------------------------------------------------------------------
{
file.Rewind();
- if(!file.ReadMagic("FORM")
- || !file.Skip(4)
- || !file.ReadMagic("MODL"))
+
+ PT36Header fileHeader;
+ if(!file.ReadStruct(fileHeader))
{
return false;
}
-
+ if(!ValidateHeader(fileHeader))
+ {
+ return false;
+ }
+
bool ok = false, infoOk = false;
FileReader commentChunk;
- mpt::ustring version = MPT_USTRING("3.6");
+ mpt::ustring version;
PT36InfoChunk info;
MemsetZero(info);
@@ -1799,6 +2058,11 @@
break;
}
} while(file.ReadStruct(iffHead));
+
+ if(version.empty())
+ {
+ version = MPT_USTRING("3.6");
+ }
// both an info chunk and a module are required
if(ok && infoOk)
Index: soundlib/Load_mt2.cpp
===================================================================
--- soundlib/Load_mt2.cpp (revision 8929)
+++ soundlib/Load_mt2.cpp (working copy)
@@ -395,23 +395,66 @@
}
-bool CSoundFile::ReadMT2(FileReader &file, ModLoadingFlags loadFlags)
-//-------------------------------------------------------------------
+static bool ValidateHeader(const MT2FileHeader &fileHeader)
+//---------------------------------------------------------
{
- file.Rewind();
- MT2FileHeader fileHeader;
- if(!file.ReadStruct(fileHeader)
- || memcmp(fileHeader.signature, "MT20", 4)
+ if(std::memcmp(fileHeader.signature, "MT20", 4)
|| fileHeader.version < 0x200 || fileHeader.version >= 0x300
|| fileHeader.numChannels < 1 || fileHeader.numChannels > 64
|| fileHeader.numOrders > 256
|| fileHeader.numInstruments >= MAX_INSTRUMENTS
|| fileHeader.numSamples >= MAX_SAMPLES
- || !file.CanRead(256))
+ )
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ return true;
+}
+
+
+static uint64 GetHeaderMinimumAdditionalSize(const MT2FileHeader &fileHeader)
+//---------------------------------------------------------------------------
+{
+ MPT_UNREFERENCED_PARAMETER(fileHeader);
+ return 256;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderMT2(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ MT2FileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
{
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader));
+}
+
+
+bool CSoundFile::ReadMT2(FileReader &file, ModLoadingFlags loadFlags)
+//-------------------------------------------------------------------
+{
+ file.Rewind();
+ MT2FileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return false;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return false;
+ }
+ if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(fileHeader))))
+ {
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
Index: soundlib/Load_mtm.cpp
===================================================================
--- soundlib/Load_mtm.cpp (revision 8929)
+++ soundlib/Load_mtm.cpp (working copy)
@@ -75,23 +75,65 @@
MPT_BINARY_STRUCT(MTMSampleHeader, 37)
-bool CSoundFile::ReadMTM(FileReader &file, ModLoadingFlags loadFlags)
-//-------------------------------------------------------------------
+static bool ValidateHeader(const MTMFileHeader &fileHeader)
+//---------------------------------------------------------
{
- file.Rewind();
- MTMFileHeader fileHeader;
- if(!file.ReadStruct(fileHeader)
- || memcmp(fileHeader.id, "MTM", 3)
+ if(std::memcmp(fileHeader.id, "MTM", 3)
|| fileHeader.version >= 0x20
|| fileHeader.lastOrder > 127
|| fileHeader.beatsPerTrack > 64
|| fileHeader.numChannels > 32
|| fileHeader.numChannels == 0
- || !file.CanRead(sizeof(MTMSampleHeader) * fileHeader.numSamples + 128 + 192 * fileHeader.numTracks + 64 * (fileHeader.lastPattern + 1) + fileHeader.commentSize))
+ )
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ return true;
+}
+
+
+static uint64 GetHeaderMinimumAdditionalSize(const MTMFileHeader &fileHeader)
+//---------------------------------------------------------------------------
+{
+ return sizeof(MTMSampleHeader) * fileHeader.numSamples + 128 + 192 * fileHeader.numTracks + 64 * (fileHeader.lastPattern + 1) + fileHeader.commentSize;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderMTM(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ MTMFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
{
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader));
+}
+
+
+bool CSoundFile::ReadMTM(FileReader &file, ModLoadingFlags loadFlags)
+//-------------------------------------------------------------------
+{
+ file.Rewind();
+ MTMFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return false;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return false;
+ }
+ if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(fileHeader))))
+ {
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
Index: soundlib/Load_okt.cpp
===================================================================
--- soundlib/Load_okt.cpp (revision 8929)
+++ soundlib/Load_okt.cpp (working copy)
@@ -258,6 +258,35 @@
}
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderOKT(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ if(!file.CanRead(8))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!file.ReadMagic("OKTASONG"))
+ {
+ return ProbeFailure;
+ }
+ OktIffChunk iffHead;
+ if(!file.ReadStruct(iffHead))
+ {
+ return ProbeWantMoreData;
+ }
+ if(iffHead.chunksize == 0)
+ {
+ return ProbeFailure;
+ }
+ if((iffHead.signature & 0x7f7f7f7fu) != iffHead.signature) // ASCII?
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
bool CSoundFile::ReadOKT(FileReader &file, ModLoadingFlags loadFlags)
//-------------------------------------------------------------------
{
Index: soundlib/Load_plm.cpp
===================================================================
--- soundlib/Load_plm.cpp (revision 8929)
+++ soundlib/Load_plm.cpp (working copy)
@@ -83,6 +83,44 @@
MPT_BINARY_STRUCT(PLMOrderItem, 4)
+static bool ValidateHeader(const PLMFileHeader &fileHeader)
+//---------------------------------------------------------
+{
+ if(std::memcmp(fileHeader.magic, "PLM\x1A", 4)
+ || fileHeader.version != 0x10
+ || fileHeader.numChannels == 0 || fileHeader.numChannels > 32
+ || fileHeader.headerSize < sizeof(PLMFileHeader)
+ )
+ {
+ return false;
+ }
+ return true;
+}
+
+
+static uint64 GetHeaderMinimumAdditionalSize(const PLMFileHeader &fileHeader)
+//---------------------------------------------------------------------------
+{
+ return fileHeader.headerSize - sizeof(PLMFileHeader) + 4 * (fileHeader.numOrders + fileHeader.numPatterns + fileHeader.numSamples);
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderPLM(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ PLMFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader));
+}
+
+
bool CSoundFile::ReadPLM(FileReader &file, ModLoadingFlags loadFlags)
//-------------------------------------------------------------------
{
@@ -89,19 +127,28 @@
file.Rewind();
PLMFileHeader fileHeader;
- if(!file.ReadStruct(fileHeader)
- || memcmp(fileHeader.magic, "PLM\x1A", 4)
- || fileHeader.version != 0x10
- || fileHeader.numChannels == 0 || fileHeader.numChannels > 32
- || !file.Seek(fileHeader.headerSize)
- || !file.CanRead(4 * (fileHeader.numOrders + fileHeader.numPatterns + fileHeader.numSamples)))
+ if(!file.ReadStruct(fileHeader))
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ if(!ValidateHeader(fileHeader))
{
+ return false;
+ }
+ if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(fileHeader))))
+ {
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
+ if(!file.Seek(fileHeader.headerSize))
+ {
+ return false;
+ }
+
InitializeGlobals(MOD_TYPE_PLM);
InitializeChannels();
m_SongFlags = SONG_ITOLDEFFECTS;
Index: soundlib/Load_psm.cpp
===================================================================
--- soundlib/Load_psm.cpp (revision 8929)
+++ soundlib/Load_psm.cpp (working copy)
@@ -208,10 +208,51 @@
offset = 0;
}
return ConvertStrTo<uint16>(&patternID[offset]);
+}
+
+static bool ValidateHeader(const PSMFileHeader &fileHeader)
+//---------------------------------------------------------
+{
+ if(std::memcmp(fileHeader.formatID, "PSM ", 4)
+ || std::memcmp(fileHeader.fileInfoID, "FILE", 4))
+ {
+ return false;
+ }
+ return true;
}
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderPSM(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ PSMFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ PSMChunk chunkHeader;
+ if(!file.ReadStruct(chunkHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(chunkHeader.length == 0)
+ {
+ return ProbeFailure;
+ }
+ if((chunkHeader.id & 0x7f7f7f7fu) != chunkHeader.id) // ASCII?
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
bool CSoundFile::ReadPSM(FileReader &file, ModLoadingFlags loadFlags)
//-------------------------------------------------------------------
{
@@ -244,8 +285,7 @@
#endif // MPT_PSM_DECRYPT
// Check header
- if(memcmp(fileHeader.formatID, "PSM ", 4)
- || memcmp(fileHeader.fileInfoID, "FILE", 4))
+ if(!ValidateHeader(fileHeader))
{
return false;
}
@@ -1029,15 +1069,10 @@
MPT_BINARY_STRUCT(PSM16PatternHeader, 4)
-bool CSoundFile::ReadPSM16(FileReader &file, ModLoadingFlags loadFlags)
-//---------------------------------------------------------------------
+static bool ValidateHeader(const PSM16FileHeader &fileHeader)
+//-----------------------------------------------------------
{
- file.Rewind();
-
- // Is it a valid PSM16 file?
- PSM16FileHeader fileHeader;
- if(!file.ReadStruct(fileHeader)
- || memcmp(fileHeader.formatID, "PSM\xFE", 4)
+ if(std::memcmp(fileHeader.formatID, "PSM\xFE", 4)
|| fileHeader.lineEnd != 0x1A
|| (fileHeader.formatVersion != 0x10 && fileHeader.formatVersion != 0x01) // why is this sometimes 0x01?
|| fileHeader.patternVersion != 0 // 255ch pattern version not supported (did anyone use this?)
@@ -1047,8 +1082,45 @@
|| std::max(fileHeader.numChannelsPlay, fileHeader.numChannelsReal) == 0)
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderPSM16(MemoryFileReader file, const uint64 *pfilesize)
+//------------------------------------------------------------------------------------------------------
+{
+ PSM16FileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
{
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
+bool CSoundFile::ReadPSM16(FileReader &file, ModLoadingFlags loadFlags)
+//---------------------------------------------------------------------
+{
+ file.Rewind();
+
+ // Is it a valid PSM16 file?
+ PSM16FileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return false;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
Index: soundlib/Load_ptm.cpp
===================================================================
--- soundlib/Load_ptm.cpp (revision 8929)
+++ soundlib/Load_ptm.cpp (working copy)
@@ -104,14 +104,10 @@
MPT_BINARY_STRUCT(PTMSampleHeader, 80)
-bool CSoundFile::ReadPTM(FileReader &file, ModLoadingFlags loadFlags)
-//-------------------------------------------------------------------
+static bool ValidateHeader(const PTMFileHeader &fileHeader)
+//---------------------------------------------------------
{
- file.Rewind();
-
- PTMFileHeader fileHeader;
- if(!file.ReadStruct(fileHeader)
- || memcmp(fileHeader.magic, "PTMF", 4)
+ if(std::memcmp(fileHeader.magic, "PTMF", 4)
|| fileHeader.dosEOF != 26
|| fileHeader.versionHi > 2
|| fileHeader.flags != 0
@@ -120,11 +116,57 @@
|| !fileHeader.numOrders || fileHeader.numOrders > 256
|| !fileHeader.numSamples || fileHeader.numSamples > 255
|| !fileHeader.numPatterns || fileHeader.numPatterns > 128
- || !file.CanRead(fileHeader.numSamples * sizeof(PTMSampleHeader)))
+ )
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ return true;
+}
+
+
+static uint64 GetHeaderMinimumAdditionalSize(const PTMFileHeader &fileHeader)
+//---------------------------------------------------------------------------
+{
+ return fileHeader.numSamples * sizeof(PTMSampleHeader);
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderPTM(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ PTMFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
{
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader));
+}
+
+
+bool CSoundFile::ReadPTM(FileReader &file, ModLoadingFlags loadFlags)
+//-------------------------------------------------------------------
+{
+ file.Rewind();
+
+ PTMFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return false;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return false;
+ }
+ if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(fileHeader))))
+ {
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
Index: soundlib/Load_s3m.cpp
===================================================================
--- soundlib/Load_s3m.cpp (revision 8929)
+++ soundlib/Load_s3m.cpp (working copy)
@@ -172,6 +172,43 @@
};
+static bool ValidateHeader(const S3MFileHeader &fileHeader)
+//---------------------------------------------------------
+{
+ if(std::memcmp(fileHeader.magic, "SCRM", 4)
+ || fileHeader.fileType != S3MFileHeader::idS3MType
+ || (fileHeader.formatVersion != S3MFileHeader::oldVersion && fileHeader.formatVersion != S3MFileHeader::newVersion)
+ )
+ {
+ return false;
+ }
+ return true;
+}
+
+
+static uint64 GetHeaderMinimumAdditionalSize(const S3MFileHeader &fileHeader)
+//---------------------------------------------------------------------------
+{
+ return fileHeader.ordNum + (fileHeader.smpNum + fileHeader.patNum) * 2;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderS3M(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ S3MFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader));
+}
+
+
bool CSoundFile::ReadS3M(FileReader &file, ModLoadingFlags loadFlags)
//-------------------------------------------------------------------
{
@@ -179,15 +216,20 @@
// Is it a valid S3M file?
S3MFileHeader fileHeader;
- if(!file.ReadStruct(fileHeader)
- || !file.CanRead(fileHeader.ordNum + (fileHeader.smpNum + fileHeader.patNum) * 2)
- || memcmp(fileHeader.magic, "SCRM", 4)
- || fileHeader.fileType != S3MFileHeader::idS3MType
- || (fileHeader.formatVersion != S3MFileHeader::oldVersion && fileHeader.formatVersion != S3MFileHeader::newVersion))
+ if(!file.ReadStruct(fileHeader))
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ if(!ValidateHeader(fileHeader))
{
+ return false;
+ }
+ if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(fileHeader))))
+ {
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
Index: soundlib/Load_sfx.cpp
===================================================================
--- soundlib/Load_sfx.cpp (revision 8929)
+++ soundlib/Load_sfx.cpp (working copy)
@@ -96,6 +96,87 @@
return 0;
}
+
+static bool ValidateHeader(const SFXFileHeader &fileHeader)
+//---------------------------------------------------------
+{
+ if(fileHeader.numOrders > 128)
+ {
+ return false;
+ }
+ return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderSFX(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ SAMPLEINDEX numSamples = 0;
+ if(numSamples == 0)
+ {
+ file.Rewind();
+ if(!file.CanRead(0x40))
+ {
+ return ProbeWantMoreData;
+ }
+ if(file.Seek(0x3c) && file.ReadMagic("SONG"))
+ {
+ numSamples = 15;
+ }
+ }
+ if(numSamples == 0)
+ {
+ file.Rewind();
+ if(!file.CanRead(0x80))
+ {
+ return ProbeWantMoreData;
+ }
+ if(file.Seek(0x7c) && file.ReadMagic("SO31"))
+ {
+ numSamples = 31;
+ }
+ }
+ if(numSamples == 0)
+ {
+ return ProbeFailure;
+ }
+ file.Rewind();
+ for(SAMPLEINDEX smp = 0; smp < numSamples; smp++)
+ {
+ if(file.ReadUint32BE() > 131072)
+ {
+ return ProbeFailure;
+ }
+ }
+ file.Skip(4);
+ if(!file.CanRead(2))
+ {
+ return ProbeWantMoreData;
+ }
+ uint16 speed = file.ReadUint16BE();
+ if(speed < 178)
+ {
+ return ProbeFailure;
+ }
+ if(!file.CanRead(sizeof(SFXSampleHeader) * numSamples))
+ {
+ return ProbeWantMoreData;
+ }
+ file.Skip(sizeof(SFXSampleHeader) * numSamples);
+ SFXFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
bool CSoundFile::ReadSFX(FileReader &file, ModLoadingFlags loadFlags)
//-------------------------------------------------------------------
{
@@ -164,12 +245,18 @@
}
SFXFileHeader fileHeader;
- file.ReadStruct(fileHeader);
-
- if(fileHeader.numOrders > 128)
+ if(!file.ReadStruct(fileHeader))
+ {
return false;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return false;
+ }
if(loadFlags == onlyVerifyHeader)
+ {
return true;
+ }
PATTERNINDEX numPatterns = 0;
for(ORDERINDEX ord = 0; ord < fileHeader.numOrders; ord++)
Index: soundlib/Load_stm.cpp
===================================================================
--- soundlib/Load_stm.cpp (revision 8929)
+++ soundlib/Load_stm.cpp (working copy)
@@ -94,6 +94,49 @@
MPT_BINARY_STRUCT(STMPatternData, 4*64*4)
+static bool ValidateHeader(const STMFileHeader &fileHeader)
+//---------------------------------------------------------
+{
+ if(fileHeader.filetype != 2
+ || (fileHeader.dosEof != 0x1A && fileHeader.dosEof != 2) // ST2 ignores this, ST3 doesn't. putup10.stm / putup11.stm have dosEof = 2.
+ || fileHeader.verMajor != 2
+ || fileHeader.verMinor > 21 // ST3 only accepts 0, 10, 20 and 21
+ || fileHeader.globalVolume > 64
+ || (std::memcmp(fileHeader.trackername, "!Scream!", 8)
+ && std::memcmp(fileHeader.trackername, "BMOD2STM", 8)
+ && std::memcmp(fileHeader.trackername, "WUZAMOD!", 8))
+ )
+ {
+ return false;
+ }
+ return true;
+}
+
+
+static uint64 GetHeaderMinimumAdditionalSize(const STMFileHeader &fileHeader)
+//---------------------------------------------------------------------------
+{
+ MPT_UNREFERENCED_PARAMETER(fileHeader);
+ return 31 * sizeof(STMSampleHeader) + 128;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderSTM(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ STMFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader));
+}
+
+
bool CSoundFile::ReadSTM(FileReader &file, ModLoadingFlags loadFlags)
//-------------------------------------------------------------------
{
@@ -105,20 +148,20 @@
// After reviewing all STM files on ModLand and ModArchive, it was found that the
// case-insensitive comparison is most likely not necessary for any files in the wild.
STMFileHeader fileHeader;
- if(!file.ReadStruct(fileHeader)
- || fileHeader.filetype != 2
- || (fileHeader.dosEof != 0x1A && fileHeader.dosEof != 2) // ST2 ignores this, ST3 doesn't. putup10.stm / putup11.stm have dosEof = 2.
- || fileHeader.verMajor != 2
- || fileHeader.verMinor > 21 // ST3 only accepts 0, 10, 20 and 21
- || fileHeader.globalVolume > 64
- || (memcmp(fileHeader.trackername, "!Scream!", 8)
- && memcmp(fileHeader.trackername, "BMOD2STM", 8)
- && memcmp(fileHeader.trackername, "WUZAMOD!", 8))
- || !file.CanRead(31 * sizeof(STMSampleHeader) + 128))
+ if(!file.ReadStruct(fileHeader))
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ if(!ValidateHeader(fileHeader))
{
+ return false;
+ }
+ if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(fileHeader))))
+ {
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
Index: soundlib/Load_stp.cpp
===================================================================
--- soundlib/Load_stp.cpp (revision 8929)
+++ soundlib/Load_stp.cpp (working copy)
@@ -23,6 +23,7 @@
// File header (except for "STP3" magic)
struct STPFileHeader
{
+ char magic[4];
uint16be version;
uint8be numOrders;
uint8be patternLength;
@@ -38,7 +39,7 @@
uint16be sampleStructSize;
};
-MPT_BINARY_STRUCT(STPFileHeader, 200);
+MPT_BINARY_STRUCT(STPFileHeader, 204);
// Sample header (common part between all versions)
@@ -203,24 +204,57 @@
}
-bool CSoundFile::ReadSTP(FileReader &file, ModLoadingFlags loadFlags)
-//-------------------------------------------------------------------
+static bool ValidateHeader(const STPFileHeader &fileHeader)
+//---------------------------------------------------------
{
- file.Rewind();
- if(!file.ReadMagic("STP3"))
- return false;
-
- STPFileHeader fileHeader;
- if(!file.ReadStruct(fileHeader)
+ if(std::memcmp(fileHeader.magic, "STP3", 4)
|| fileHeader.version > 2
|| fileHeader.numOrders > 128
|| fileHeader.numSamples >= MAX_SAMPLES
|| fileHeader.timerCount == 0
|| fileHeader.midiCount != 50)
+ {
return false;
+ }
+ return true;
+}
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderSTP(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ STPFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
+bool CSoundFile::ReadSTP(FileReader &file, ModLoadingFlags loadFlags)
+//-------------------------------------------------------------------
+{
+ file.Rewind();
+
+ STPFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return false;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return false;
+ }
if(loadFlags == onlyVerifyHeader)
+ {
return true;
+ }
InitializeGlobals(MOD_TYPE_STP);
Index: soundlib/Load_ult.cpp
===================================================================
--- soundlib/Load_ult.cpp (revision 8929)
+++ soundlib/Load_ult.cpp (working copy)
@@ -336,21 +336,53 @@
};
+static bool ValidateHeader(const UltFileHeader &fileHeader)
+//---------------------------------------------------------
+{
+ if(fileHeader.version < '1'
+ || fileHeader.version > '4'
+ || std::memcmp(fileHeader.signature, "MAS_UTrack_V00", sizeof(fileHeader.signature))
+ )
+ {
+ return false;
+ }
+ return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderULT(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ UltFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
bool CSoundFile::ReadUlt(FileReader &file, ModLoadingFlags loadFlags)
//-------------------------------------------------------------------
{
file.Rewind();
+
UltFileHeader fileHeader;
-
- // Tracker ID
- if(!file.ReadStruct(fileHeader)
- || fileHeader.version < '1'
- || fileHeader.version > '4'
- || memcmp(fileHeader.signature, "MAS_UTrack_V00", sizeof(fileHeader.signature)) != 0)
+ if(!file.ReadStruct(fileHeader))
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ if(!ValidateHeader(fileHeader))
{
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
Index: soundlib/Load_xm.cpp
===================================================================
--- soundlib/Load_xm.cpp (revision 8929)
+++ soundlib/Load_xm.cpp (working copy)
@@ -262,6 +262,43 @@
DECLARE_FLAGSET(TrackerVersions)
+static bool ValidateHeader(const XMFileHeader &fileHeader)
+//--------------------------------------------------------
+{
+ if(fileHeader.channels == 0
+ || fileHeader.channels > MAX_BASECHANNELS
+ || std::memcmp(fileHeader.signature, "Extended Module: ", 17)
+ )
+ {
+ return false;
+ }
+ return true;
+}
+
+
+static uint64 GetHeaderMinimumAdditionalSize(const XMFileHeader &fileHeader)
+//--------------------------------------------------------------------------
+{
+ return fileHeader.orders + 4 * (fileHeader.patterns + fileHeader.instruments);
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderXM(MemoryFileReader file, const uint64 *pfilesize)
+//---------------------------------------------------------------------------------------------------
+{
+ XMFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader));
+}
+
+
bool CSoundFile::ReadXM(FileReader &file, ModLoadingFlags loadFlags)
//------------------------------------------------------------------
{
@@ -268,13 +305,17 @@
file.Rewind();
XMFileHeader fileHeader;
- if(!file.ReadStruct(fileHeader)
- || fileHeader.channels == 0
- || fileHeader.channels > MAX_BASECHANNELS
- || memcmp(fileHeader.signature, "Extended Module: ", 17)
- || !file.CanRead(fileHeader.orders + 4 * (fileHeader.patterns + fileHeader.instruments)))
+ if(!file.ReadStruct(fileHeader))
{
return false;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return false;
+ }
+ if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(fileHeader))))
+ {
+ return false;
} else if(loadFlags == onlyVerifyHeader)
{
return true;
Index: soundlib/Sndfile.cpp
===================================================================
--- soundlib/Sndfile.cpp (revision 8929)
+++ soundlib/Sndfile.cpp (working copy)
@@ -211,12 +211,141 @@
}
+CSoundFile::ProbeResult CSoundFile::ProbeAdditionalSize(MemoryFileReader &file, const uint64 *pfilesize, uint64 minimumAdditionalSize)
+//------------------------------------------------------------------------------------------------------------------------------------
+{
+ const uint64 availableFileSize = file.GetLength();
+ const uint64 fileSize = (pfilesize ? *pfilesize : file.GetLength());
+ //const uint64 validFileSize = std::min<uint64>(fileSize, ProbeRecommendedSize);
+ const uint64 goalSize = file.GetPosition() + minimumAdditionalSize;
+ //const uint64 goalMinimumSize = std::min<uint64>(goalSize, ProbeRecommendedSize);
+ if(pfilesize)
+ {
+ if(availableFileSize < std::min<uint64>(fileSize, ProbeRecommendedSize))
+ {
+ if(availableFileSize < goalSize)
+ {
+ return ProbeWantMoreData;
+ }
+ } else
+ {
+ if(fileSize < goalSize)
+ {
+ return ProbeFailure;
+ }
+ }
+ return ProbeSuccess;
+ }
+#if 0
+ if(!pfilesize)
+ {
+ if(fileSize < goalSize && fileSize < ProbeRecommendedSize)
+ {
+ return ProbeWantMoreData;
+ }
+ return ProbeSuccess;
+ }
+#else
+ return ProbeSuccess;
+#endif
+}
+
+
const std::size_t CSoundFile::ProbeRecommendedSize = PROBE_RECOMMENDED_SIZE;
+#define MPT_DO_PROBE( storedResult , call ) \
+ MPT_DO { \
+ ProbeResult lastResult = call ; \
+ if(lastResult == ProbeSuccess) { \
+ return ProbeSuccess; \
+ } else if(lastResult == ProbeWantMoreData) { \
+ storedResult = ProbeWantMoreData; \
+ } \
+ } MPT_WHILE_0 \
+/**/
+
+
CSoundFile::ProbeResult CSoundFile::Probe(ProbeFlags flags, mpt::span<const mpt::byte> data, const uint64 *pfilesize)
//-------------------------------------------------------------------------------------------------------------------
{
+#if 1
+ ProbeResult result = ProbeFailure;
+ if(pfilesize && (*pfilesize < data.size()))
+ {
+ throw std::out_of_range("");
+ }
+ if(!data.data())
+ {
+ throw std::invalid_argument("");
+ }
+ MemoryFileReader file(data);
+ if(flags & ProbeContainers)
+ {
+ MPT_DO_PROBE(result, ProbeFileHeaderMMCMP(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderPP20(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderUMX(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderXPK(file, pfilesize));
+ }
+ if(flags & ProbeModules)
+ {
+ MPT_DO_PROBE(result, ProbeFileHeader669(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderAM(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderAMF_Asylum(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderAMF_DSMI(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderAMS(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderAMS2(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderDBM(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderDTM(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderDIGI(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderDMF(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderDSM(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderFAR(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderGDM(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderICE(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderIMF(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderIT(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderITP(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderJ2B(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderM15(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderMDL(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderMED(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderMO3(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderMOD(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderMT2(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderMTM(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderOKT(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderPLM(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderPSM(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderPSM16(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderPT36(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderPTM(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderS3M(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderSFX(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderSTM(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderSTP(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderULT(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderXM(file, pfilesize));
+ }
+ if(pfilesize)
+ {
+ if((result == ProbeWantMoreData) && (mpt::saturate_cast<std::size_t>(*pfilesize) <= data.size()))
+ {
+ // If the prober wants more data but we already reached EOF,
+ // probing must fail.
+ result = ProbeFailure;
+ }
+ } else
+ {
+ if((result == ProbeWantMoreData) && (data.size() >= ProbeRecommendedSize))
+ {
+ // If the prober wants more daat but we already provided the recommended required maximum,
+ // just return success as this is th ebest we can do for the suggestesd probing size.
+ result = ProbeSuccess;
+ }
+ }
+ return result;
+#else
uint64 filesize = 0;
if(pfilesize)
{
@@ -257,6 +386,7 @@
}
sndFile->Destroy();
return ProbeSuccess;
+#endif
}
Index: soundlib/Sndfile.h
===================================================================
--- soundlib/Sndfile.h (revision 8929)
+++ soundlib/Sndfile.h (working copy)
@@ -581,6 +581,8 @@
ProbeWantMoreData = -1
};
+ static ProbeResult ProbeAdditionalSize(MemoryFileReader &file, const uint64 *pfilesize, uint64 minimumAdditionalSize);
+
static ProbeResult Probe(ProbeFlags flags, mpt::span<const mpt::byte> data, const uint64 *pfilesize);
public:
@@ -672,6 +674,49 @@
bool InitChannel(CHANNELINDEX nChn);
void InitAmigaResampler();
+ static ProbeResult ProbeFileHeaderMMCMP(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderPP20(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderUMX(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderXPK(MemoryFileReader file, const uint64 *pfilesize);
+
+ static ProbeResult ProbeFileHeader669(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderAM(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderAMF_Asylum(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderAMF_DSMI(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderAMS(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderAMS2(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderDBM(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderDTM(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderDIGI(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderDMF(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderDSM(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderFAR(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderGDM(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderICE(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderIMF(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderIT(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderITP(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderJ2B(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderM15(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderMDL(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderMED(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderMO3(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderMOD(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderMT2(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderMTM(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderOKT(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderPLM(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderPSM(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderPSM16(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderPT36(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderPTM(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderS3M(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderSFX(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderSTM(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderSTP(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderULT(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderXM(MemoryFileReader file, const uint64 *pfilesize);
+
// Module Loaders
bool Read669(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadAM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
@@ -694,7 +739,6 @@
bool ReadM15(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadMDL(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadMed(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
- bool ReadMID(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadMO3(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadMod(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadMT2(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
@@ -710,9 +754,11 @@
bool ReadSTM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadSTP(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadUlt(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
+ bool ReadXM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
+
+ bool ReadMID(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadUAX(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadWav(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
- bool ReadXM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
static std::vector<const char *> GetSupportedExtensions(bool otherFormats);
static bool IsExtensionSupported(const char *ext); // UTF8, casing of ext is ignored
Index: soundlib/UMXTools.cpp
===================================================================
--- soundlib/UMXTools.cpp (revision 8929)
+++ soundlib/UMXTools.cpp (working copy)
@@ -17,8 +17,9 @@
// Read compressed unreal integers - similar to MIDI integers, but signed values are possible.
-int32 ReadUMXIndex(FileReader &chunk)
-//-----------------------------------
+template <typename Tfile>
+static int32 ReadUMXIndexImpl(Tfile &chunk)
+//-----------------------------------------
{
enum
{
@@ -55,10 +56,17 @@
return result;
}
+int32 ReadUMXIndex(FileReader &chunk)
+//-----------------------------------
+{
+ return ReadUMXIndexImpl(chunk);
+}
+
// Returns true if the given nme exists in the name table.
-bool FindUMXNameTableEntry(FileReader &file, const UMXFileHeader &fileHeader, const char *name)
-//---------------------------------------------------------------------------------------------
+template <typename TFile>
+static bool FindUMXNameTableEntryImpl(TFile &file, const UMXFileHeader &fileHeader, const char *name)
+//---------------------------------------------------------------------------------------------------
{
if(!name)
{
@@ -77,7 +85,7 @@
{
if(fileHeader.packageVersion >= 64)
{
- int32 length = ReadUMXIndex(file);
+ int32 length = ReadUMXIndexImpl(file);
if(length <= 0)
{
continue;
@@ -110,7 +118,19 @@
return result;
}
+bool FindUMXNameTableEntry(FileReader &file, const UMXFileHeader &fileHeader, const char *name)
+//---------------------------------------------------------------------------------------------
+{
+ return FindUMXNameTableEntryImpl(file, fileHeader, name);
+}
+bool FindUMXNameTableEntryMemory(MemoryFileReader &file, const UMXFileHeader &fileHeader, const char *name)
+//---------------------------------------------------------------------------------------------------------
+{
+ return FindUMXNameTableEntryImpl(file, fileHeader, name);
+}
+
+
// Read an entry from the name table.
std::string ReadUMXNameTableEntry(FileReader &chunk, uint16 packageVersion)
//-------------------------------------------------------------------------
Index: soundlib/UMXTools.h
===================================================================
--- soundlib/UMXTools.h (revision 8929)
+++ soundlib/UMXTools.h (working copy)
@@ -38,6 +38,9 @@
// Returns true if the given nme exists in the name table.
bool FindUMXNameTableEntry(FileReader &file, const UMXFileHeader &fileHeader, const char *name);
+// Returns true if the given nme exists in the name table.
+bool FindUMXNameTableEntryMemory(MemoryFileReader &file, const UMXFileHeader &fileHeader, const char *name);
+
// Read an entry from the name table.
std::string ReadUMXNameTableEntry(FileReader &chunk, uint16 packageVersion);
Index: soundlib/load_j2b.cpp
===================================================================
--- soundlib/load_j2b.cpp (revision 8929)
+++ soundlib/load_j2b.cpp (working copy)
@@ -615,6 +615,66 @@
}
+struct AMFFRiffChunkFormat
+{
+ uint32le format;
+};
+
+MPT_BINARY_STRUCT(AMFFRiffChunkFormat, 4)
+
+
+static bool ValidateHeader(const AMFFRiffChunk &fileHeader)
+//---------------------------------------------------------
+{
+ if(fileHeader.id != AMFFRiffChunk::idRIFF)
+ {
+ return false;
+ }
+ if(fileHeader.GetLength() < 8 + sizeof(AMFFMainChunk))
+ {
+ return false;
+ }
+ return true;
+}
+
+
+static bool ValidateHeader(const AMFFRiffChunkFormat &formatHeader)
+//-----------------------------------------------------------------
+{
+ if(formatHeader.format != AMFFRiffChunk::idAMFF || formatHeader.format != AMFFRiffChunk::idAM__)
+ {
+ return false;
+ }
+ return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderAM(MemoryFileReader file, const uint64 *pfilesize)
+//---------------------------------------------------------------------------------------------------
+{
+ AMFFRiffChunk fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ AMFFRiffChunkFormat formatHeader;
+ if(!file.ReadStruct(formatHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(formatHeader))
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
bool CSoundFile::ReadAM(FileReader &file, ModLoadingFlags loadFlags)
//------------------------------------------------------------------
{
@@ -624,15 +684,23 @@
{
return false;
}
-
- if(fileHeader.id != AMFFRiffChunk::idRIFF)
+ if(!ValidateHeader(fileHeader))
{
return false;
}
+ AMFFRiffChunkFormat formatHeader;
+ if(!file.ReadStruct(formatHeader))
+ {
+ return false;
+ }
+ if(!ValidateHeader(formatHeader))
+ {
+ return false;
+ }
bool isAM; // false: AMFF, true: AM
- uint32 format = file.ReadUint32LE();
+ uint32 format = formatHeader.format;
if(format == AMFFRiffChunk::idAMFF)
isAM = false; // "AMFF"
else if(format == AMFFRiffChunk::idAM__)
@@ -877,6 +945,64 @@
return true;
}
+
+static bool ValidateHeader(const J2BFileHeader &fileHeader)
+//---------------------------------------------------------
+{
+ if(std::memcmp(fileHeader.signature, "MUSE", 4)
+ || (fileHeader.deadbeaf != J2BFileHeader::magicDEADBEAF // 0xDEADBEAF (RIFF AM)
+ && fileHeader.deadbeaf != J2BFileHeader::magicDEADBABE) // 0xDEADBABE (RIFF AMFF)
+ )
+ {
+ return false;
+ }
+ if(fileHeader.packedLength == 0)
+ {
+ return false;
+ }
+ if(fileHeader.fileLength != fileHeader.packedLength + sizeof(J2BFileHeader))
+ {
+ return false;
+ }
+ return true;
+}
+
+
+static bool ValidateHeaderFileSize(const J2BFileHeader &fileHeader, uint64 filesize)
+//----------------------------------------------------------------------------------
+{
+ if(filesize != fileHeader.fileLength)
+ {
+ return false;
+ }
+ return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderJ2B(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ J2BFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ if(pfilesize)
+ {
+ if(!ValidateHeaderFileSize(fileHeader, *pfilesize))
+ {
+ return ProbeFailure;
+ }
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
bool CSoundFile::ReadJ2B(FileReader &file, ModLoadingFlags loadFlags)
//-------------------------------------------------------------------
{
@@ -891,17 +1017,21 @@
file.Rewind();
J2BFileHeader fileHeader;
- if(!file.ReadStruct(fileHeader)
- || memcmp(fileHeader.signature, "MUSE", 4)
- || (fileHeader.deadbeaf != J2BFileHeader::magicDEADBEAF // 0xDEADBEAF (RIFF AM)
- && fileHeader.deadbeaf != J2BFileHeader::magicDEADBABE) // 0xDEADBABE (RIFF AMFF)
- || fileHeader.fileLength != file.GetLength()
+ if(!file.ReadStruct(fileHeader))
+ {
+ return false;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return false;
+ }
+ if(fileHeader.fileLength != file.GetLength()
|| fileHeader.packedLength != file.BytesLeft()
- || fileHeader.packedLength == 0
)
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ if(loadFlags == onlyVerifyHeader)
{
return true;
}
probe-refactor-v19.patch (110,567 bytes)
Index: libopenmpt/libopenmpt_version.h
===================================================================
--- libopenmpt/libopenmpt_version.h (revision 8932)
+++ libopenmpt/libopenmpt_version.h (working copy)
@@ -21,7 +21,7 @@
/*! \brief libopenmpt patch version number */
#define OPENMPT_API_VERSION_PATCH 0
/*! \brief libopenmpt pre-release tag */
-#define OPENMPT_API_VERSION_PREREL "-pre.7"
+#define OPENMPT_API_VERSION_PREREL "-pre.8"
/*! \brief libopenmpt pre-release flag */
#define OPENMPT_API_VERSION_IS_PREREL 1
Index: libopenmpt/libopenmpt_version.mk
===================================================================
--- libopenmpt/libopenmpt_version.mk (revision 8932)
+++ libopenmpt/libopenmpt_version.mk (working copy)
@@ -1,7 +1,7 @@
LIBOPENMPT_VERSION_MAJOR=0
LIBOPENMPT_VERSION_MINOR=3
LIBOPENMPT_VERSION_PATCH=0
-LIBOPENMPT_VERSION_PREREL=-pre.7
+LIBOPENMPT_VERSION_PREREL=-pre.8
LIBOPENMPT_LTVER_CURRENT=1
LIBOPENMPT_LTVER_REVISION=0
Index: soundlib/ContainerMMCMP.cpp
===================================================================
--- soundlib/ContainerMMCMP.cpp (revision 8932)
+++ soundlib/ContainerMMCMP.cpp (working copy)
@@ -13,6 +13,7 @@
#include "../common/FileReader.h"
#include "Container.h"
+#include "Sndfile.h"
#include <stdexcept>
@@ -144,6 +145,66 @@
}
+static bool ValidateHeader(const MMCMPFILEHEADER &mfh)
+//----------------------------------------------------
+{
+ if(std::memcmp(mfh.id, "ziRCONia", 8) != 0)
+ {
+ return false;
+ }
+ if(mfh.hdrsize != sizeof(MMCMPHEADER))
+ {
+ return false;
+ }
+ return true;
+}
+
+
+static bool ValidateHeader(const MMCMPHEADER &mmh)
+//------------------------------------------------
+{
+ if(mmh.nblocks == 0)
+ {
+ return false;
+ }
+ if(mmh.filesize == 0)
+ {
+ return false;
+ }
+ if(mmh.filesize > 0x80000000)
+ {
+ return false;
+ }
+ return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderMMCMP(MemoryFileReader file, const uint64 *pfilesize)
+//------------------------------------------------------------------------------------------------------
+{
+ MMCMPFILEHEADER mfh;
+ if(!file.ReadStruct(mfh))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(mfh))
+ {
+ return ProbeFailure;
+ }
+ MMCMPHEADER mmh;
+ if(!file.ReadStruct(mmh))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(mmh))
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
bool UnpackMMCMP(std::vector<ContainerItem> &containerItems, FileReader &file, ContainerLoadingFlags loadFlags)
//-------------------------------------------------------------------------------------------------------------
{
@@ -151,14 +212,23 @@
containerItems.clear();
MMCMPFILEHEADER mfh;
- if(!file.ReadStruct(mfh)) return false;
- if(std::memcmp(mfh.id, "ziRCONia", 8) != 0) return false;
- if(mfh.hdrsize != sizeof(MMCMPHEADER)) return false;
+ if(!file.ReadStruct(mfh))
+ {
+ return false;
+ }
+ if(!ValidateHeader(mfh))
+ {
+ return false;
+ }
MMCMPHEADER mmh;
- if(!file.ReadStruct(mmh)) return false;
- if(mmh.nblocks == 0) return false;
- if(mmh.filesize == 0) return false;
- if(mmh.filesize > 0x80000000) return false;
+ if(!file.ReadStruct(mmh))
+ {
+ return false;
+ }
+ if(!ValidateHeader(mmh))
+ {
+ return false;
+ }
if(loadFlags == ContainerOnlyVerifyHeader)
{
return true;
Index: soundlib/ContainerPP20.cpp
===================================================================
--- soundlib/ContainerPP20.cpp (revision 8932)
+++ soundlib/ContainerPP20.cpp (working copy)
@@ -13,6 +13,7 @@
#include "../common/FileReader.h"
#include "Container.h"
+#include "Sndfile.h"
#include <stdexcept>
@@ -115,6 +116,50 @@
}
+struct PP20header
+{
+ char magic[4]; // "PP20"
+ uint8be efficiency[4];
+};
+
+MPT_BINARY_STRUCT(PP20header, 8)
+
+
+static bool ValidateHeader(const PP20header &hdr)
+//-----------------------------------------------
+{
+ if(std::memcmp(hdr.magic, "PP20", 4) != 0)
+ {
+ return false;
+ }
+ if(hdr.efficiency[0] < 9 || hdr.efficiency[0] > 15
+ || hdr.efficiency[1] < 9 || hdr.efficiency[1] > 15
+ || hdr.efficiency[2] < 9 || hdr.efficiency[2] > 15
+ || hdr.efficiency[3] < 9 || hdr.efficiency[3] > 15)
+ {
+ return false;
+ }
+ return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderPP20(MemoryFileReader file, const uint64 *pfilesize)
+//-----------------------------------------------------------------------------------------------------
+{
+ PP20header hdr;
+ if(!file.ReadStruct(hdr))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(hdr))
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
bool UnpackPP20(std::vector<ContainerItem> &containerItems, FileReader &file, ContainerLoadingFlags loadFlags)
//------------------------------------------------------------------------------------------------------------
{
@@ -121,20 +166,25 @@
file.Rewind();
containerItems.clear();
- if(!file.ReadMagic("PP20")) return false;
- if(!file.CanRead(8)) return false;
- uint8 efficiency[4];
- file.ReadArray(efficiency);
- if(efficiency[0] < 9 || efficiency[0] > 15
- || efficiency[1] < 9 || efficiency[1] > 15
- || efficiency[2] < 9 || efficiency[2] > 15
- || efficiency[3] < 9 || efficiency[3] > 15)
+ PP20header hdr;
+ if(!file.ReadStruct(hdr))
+ {
return false;
+ }
+ if(!ValidateHeader(hdr))
+ {
+ return false;
+ }
if(loadFlags == ContainerOnlyVerifyHeader)
{
return true;
}
+ if(!file.CanRead(4))
+ {
+ return false;
+ }
+
containerItems.emplace_back();
containerItems.back().data_cache = mpt::make_unique<std::vector<char> >();
std::vector<char> & unpackedData = *(containerItems.back().data_cache);
Index: soundlib/ContainerUMX.cpp
===================================================================
--- soundlib/ContainerUMX.cpp (revision 8932)
+++ soundlib/ContainerUMX.cpp (working copy)
@@ -12,11 +12,48 @@
#include "Loaders.h"
#include "UMXTools.h"
#include "Container.h"
+#include "Sndfile.h"
OPENMPT_NAMESPACE_BEGIN
+static bool ValidateHeader(const UMXFileHeader &fileHeader)
+//---------------------------------------------------------
+{
+ if(std::memcmp(fileHeader.magic, "\xC1\x83\x2A\x9E", 4)
+ || fileHeader.nameCount == 0
+ || fileHeader.exportCount == 0
+ || fileHeader.importCount == 0
+ )
+ {
+ return false;
+ }
+ return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderUMX(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ UMXFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ if(!FindUMXNameTableEntryMemory(file, fileHeader, "music"))
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
bool UnpackUMX(std::vector<ContainerItem> &containerItems, FileReader &file, ContainerLoadingFlags loadFlags)
//-----------------------------------------------------------------------------------------------------------
{
@@ -24,15 +61,14 @@
containerItems.clear();
UMXFileHeader fileHeader;
- if(!file.ReadStruct(fileHeader)
- || memcmp(fileHeader.magic, "\xC1\x83\x2A\x9E", 4)
- || fileHeader.nameCount == 0
- || fileHeader.exportCount == 0
- || fileHeader.importCount == 0
- )
+ if(!file.ReadStruct(fileHeader))
{
return false;
}
+ if(!ValidateHeader(fileHeader))
+ {
+ return false;
+ }
// Note that this can be a false positive, e.g. Unreal maps will have music and sound
// in their name table because they usually import such files. However, it spares us
Index: soundlib/ContainerXPK.cpp
===================================================================
--- soundlib/ContainerXPK.cpp (revision 8932)
+++ soundlib/ContainerXPK.cpp (working copy)
@@ -13,6 +13,7 @@
#include "../common/FileReader.h"
#include "Container.h"
+#include "Sndfile.h"
#include <stdexcept>
@@ -329,6 +330,68 @@
}
+static bool ValidateHeader(const XPKFILEHEADER &header)
+//-----------------------------------------------------
+{
+ if(std::memcmp(header.XPKF, "XPKF", 4) != 0)
+ {
+ return false;
+ }
+ if(std::memcmp(header.SQSH, "SQSH", 4) != 0)
+ {
+ return false;
+ }
+ if(header.SrcLen == 0)
+ {
+ return false;
+ }
+ if(header.DstLen == 0)
+ {
+ return false;
+ }
+ MPT_STATIC_ASSERT(sizeof(XPKFILEHEADER) >= 8);
+ if(header.SrcLen < (sizeof(XPKFILEHEADER) - 8))
+ {
+ return false;
+ }
+ return true;
+}
+
+
+static bool ValidateHeaderFileSize(const XPKFILEHEADER &header, uint64 filesize)
+//------------------------------------------------------------------------------
+{
+ if(filesize < header.SrcLen - 8)
+ {
+ return false;
+ }
+ return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderXPK(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ XPKFILEHEADER header;
+ if(!file.ReadStruct(header))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(header))
+ {
+ return ProbeFailure;
+ }
+ if(pfilesize)
+ {
+ if(!ValidateHeaderFileSize(header, *pfilesize))
+ {
+ return ProbeFailure;
+ }
+ }
+ return ProbeSuccess;
+}
+
+
bool UnpackXPK(std::vector<ContainerItem> &containerItems, FileReader &file, ContainerLoadingFlags loadFlags)
//-----------------------------------------------------------------------------------------------------------
{
@@ -336,19 +399,24 @@
containerItems.clear();
XPKFILEHEADER header;
- if(!file.ReadStruct(header)) return false;
- if(std::memcmp(header.XPKF, "XPKF", 4) != 0) return false;
- if(std::memcmp(header.SQSH, "SQSH", 4) != 0) return false;
- if(header.SrcLen == 0) return false;
- if(header.DstLen == 0) return false;
- STATIC_ASSERT(sizeof(XPKFILEHEADER) >= 8);
- if(header.SrcLen < (sizeof(XPKFILEHEADER) - 8)) return false;
+ if(!file.ReadStruct(header))
+ {
+ return false;
+ }
+ if(!ValidateHeader(header))
+ {
+ return false;
+ }
if(loadFlags == ContainerOnlyVerifyHeader)
{
return true;
}
- if(!file.CanRead(header.SrcLen - (sizeof(XPKFILEHEADER) - 8))) return false;
+ if(!file.CanRead(header.SrcLen - (sizeof(XPKFILEHEADER) - 8)))
+ {
+ return false;
+ }
+
containerItems.emplace_back();
containerItems.back().data_cache = mpt::make_unique<std::vector<char> >();
std::vector<char> & unpackedData = *(containerItems.back().data_cache);
Index: soundlib/Load_669.cpp
===================================================================
--- soundlib/Load_669.cpp (revision 8932)
+++ soundlib/Load_669.cpp (working copy)
@@ -62,14 +62,9 @@
MPT_BINARY_STRUCT(_669Sample, 25)
-bool CSoundFile::Read669(FileReader &file, ModLoadingFlags loadFlags)
-//-------------------------------------------------------------------
+static bool ValidateHeader(const _669FileHeader &fileHeader)
{
- _669FileHeader fileHeader;
-
- file.Rewind();
- if(!file.ReadStruct(fileHeader)
- || (memcmp(fileHeader.magic, "if", 2) && memcmp(fileHeader.magic, "JN", 2))
+ if((std::memcmp(fileHeader.magic, "if", 2) && std::memcmp(fileHeader.magic, "JN", 2))
|| fileHeader.samples > 64
|| fileHeader.restartPos >= 128
|| fileHeader.patterns > 128)
@@ -76,21 +71,68 @@
{
return false;
}
-
- for(size_t i = 0; i < CountOf(fileHeader.breaks); i++)
+ for(std::size_t i = 0; i < CountOf(fileHeader.breaks); i++)
{
if(fileHeader.orders[i] >= 128 && fileHeader.orders[i] < 0xFE)
+ {
return false;
+ }
if(fileHeader.orders[i] < 128 && fileHeader.tempoList[i] == 0)
+ {
return false;
+ }
if(fileHeader.breaks[i] >= 64)
+ {
return false;
+ }
}
+ return true;
+}
+
+static uint64 GetHeaderMinimumAdditionalSize(const _669FileHeader &fileHeader)
+//----------------------------------------------------------------------------
+{
+ return fileHeader.samples * sizeof(_669Sample) + fileHeader.patterns * 1536u;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeader669(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ _669FileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader));
+}
+
+
+bool CSoundFile::Read669(FileReader &file, ModLoadingFlags loadFlags)
+//-------------------------------------------------------------------
+{
+ _669FileHeader fileHeader;
+
+ file.Rewind();
+ if(!file.ReadStruct(fileHeader))
+ {
+ return false;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return false;
+ }
if(loadFlags == onlyVerifyHeader)
{
return true;
- } else if(!file.CanRead(fileHeader.samples * sizeof(_669Sample) + fileHeader.patterns * 1536u))
+ }
+
+ if(!file.CanRead(GetHeaderMinimumAdditionalSize(fileHeader)))
{
return false;
}
Index: soundlib/Load_amf.cpp
===================================================================
--- soundlib/Load_amf.cpp (revision 8932)
+++ soundlib/Load_amf.cpp (working copy)
@@ -80,6 +80,42 @@
MPT_BINARY_STRUCT(AMFFileHeader, 41)
+static bool ValidateHeader(const AsylumFileHeader &fileHeader)
+//------------------------------------------------------------
+{
+ if(std::memcmp(fileHeader.signature, "ASYLUM Music Format V1.0\0", 25)
+ || fileHeader.numSamples > 64
+ )
+ {
+ return false;
+ }
+ return true;
+}
+
+
+static uint64 GetHeaderMinimumAdditionalSize(const AsylumFileHeader &fileHeader)
+//------------------------------------------------------------------------------
+{
+ return 256 + 64 * sizeof(AsylumSampleHeader) + 64 * 4 * 8 * fileHeader.numPatterns;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderAMF_Asylum(MemoryFileReader file, const uint64 *pfilesize)
+//-----------------------------------------------------------------------------------------------------------
+{
+ AsylumFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader));
+}
+
+
bool CSoundFile::ReadAMF_Asylum(FileReader &file, ModLoadingFlags loadFlags)
//--------------------------------------------------------------------------
{
@@ -86,14 +122,20 @@
file.Rewind();
AsylumFileHeader fileHeader;
- if(!file.ReadStruct(fileHeader)
- || memcmp(fileHeader.signature, "ASYLUM Music Format V1.0\0", 25)
- || fileHeader.numSamples > 64
- || !file.CanRead(256 + 64 * sizeof(AsylumSampleHeader) + 64 * 4 * 8 * fileHeader.numPatterns))
+ if(!file.ReadStruct(fileHeader))
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ if(!ValidateHeader(fileHeader))
{
+ return false;
+ }
+ if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(fileHeader))))
+ {
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
@@ -341,6 +383,37 @@
}
+static bool ValidateHeader(const AMFFileHeader &fileHeader)
+//---------------------------------------------------------
+{
+ if(std::memcmp(fileHeader.amf, "AMF", 3)
+ || fileHeader.version < 8 || fileHeader.version > 14
+ || ((fileHeader.numChannels < 1 || fileHeader.numChannels > 32) && fileHeader.version >= 10)
+ )
+ {
+ return false;
+ }
+ return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderAMF_DSMI(MemoryFileReader file, const uint64 *pfilesize)
+//---------------------------------------------------------------------------------------------------------
+{
+ AMFFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
bool CSoundFile::ReadAMF_DSMI(FileReader &file, ModLoadingFlags loadFlags)
//------------------------------------------------------------------------
{
@@ -347,14 +420,16 @@
file.Rewind();
AMFFileHeader fileHeader;
- if(!file.ReadStruct(fileHeader)
- || memcmp(fileHeader.amf, "AMF", 3)
- || fileHeader.version < 8 || fileHeader.version > 14
- || ((fileHeader.numChannels < 1 || fileHeader.numChannels > 32) && fileHeader.version >= 10))
+ if(!file.ReadStruct(fileHeader))
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ if(!ValidateHeader(fileHeader))
{
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
Index: soundlib/Load_ams.cpp
===================================================================
--- soundlib/Load_ams.cpp (revision 8932)
+++ soundlib/Load_ams.cpp (working copy)
@@ -332,21 +332,76 @@
MPT_BINARY_STRUCT(AMSSampleHeader, 17)
+static bool ValidateHeader(const AMSFileHeader &fileHeader)
+//---------------------------------------------------------
+{
+ if(fileHeader.versionHigh != 0x01)
+ {
+ return false;
+ }
+ return true;
+}
+
+
+static uint64 GetHeaderMinimumAdditionalSize(const AMSFileHeader &fileHeader)
+//---------------------------------------------------------------------------
+{
+ return fileHeader.extraSize + 3u + fileHeader.numSamps * (1u + sizeof(AMSSampleHeader)) + fileHeader.numOrds * 2u + fileHeader.numPats * 4u;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderAMS(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ if(!file.CanRead(7))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!file.ReadMagic("Extreme"))
+ {
+ return ProbeFailure;
+ }
+ AMSFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader));
+}
+
+
bool CSoundFile::ReadAMS(FileReader &file, ModLoadingFlags loadFlags)
//-------------------------------------------------------------------
{
file.Rewind();
+ if(!file.ReadMagic("Extreme"))
+ {
+ return false;
+ }
AMSFileHeader fileHeader;
- if(!file.ReadMagic("Extreme")
- || !file.ReadStruct(fileHeader)
- || !file.Skip(fileHeader.extraSize)
- || !file.CanRead(3u + fileHeader.numSamps * (1u + sizeof(AMSSampleHeader)) + fileHeader.numOrds * 2u + fileHeader.numPats * 4u)
- || fileHeader.versionHigh != 0x01)
+ if(!file.ReadStruct(fileHeader))
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ if(!ValidateHeader(fileHeader))
{
+ return false;
+ }
+ if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(fileHeader))))
+ {
+ return false;
+ }
+ if(!file.Skip(fileHeader.extraSize))
+ {
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
@@ -641,30 +696,93 @@
MPT_BINARY_STRUCT(AMS2Description, 11)
+static bool ValidateHeader(const AMS2FileHeader &fileHeader)
+//----------------------------------------------------------
+{
+ if(fileHeader.versionHigh != 2 || fileHeader.versionLow > 2)
+ {
+ return false;
+ }
+ return true;
+}
+
+
+static uint64 GetHeaderMinimumAdditionalSize(const AMS2FileHeader &fileHeader)
+//----------------------------------------------------------------------------
+{
+ return 36u + sizeof(AMS2Description) + fileHeader.numIns * 2u + fileHeader.numOrds * 2u + fileHeader.numPats * 4u;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderAMS2(MemoryFileReader file, const uint64 *pfilesize)
+//-----------------------------------------------------------------------------------------------------
+{
+ if(!file.CanRead(7))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!file.ReadMagic("AMShdr\x1A"))
+ {
+ return ProbeFailure;
+ }
+ if(!file.CanRead(1))
+ {
+ return ProbeWantMoreData;
+ }
+ const uint8 songNameLength = file.ReadUint8();
+ if(!file.Skip(songNameLength))
+ {
+ return ProbeWantMoreData;
+ }
+ AMS2FileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader));
+}
+
+
bool CSoundFile::ReadAMS2(FileReader &file, ModLoadingFlags loadFlags)
//--------------------------------------------------------------------
{
file.Rewind();
- AMS2FileHeader fileHeader;
if(!file.ReadMagic("AMShdr\x1A"))
{
return false;
}
-
- InitializeGlobals(MOD_TYPE_AMS2);
-
- if(!file.ReadSizedString<uint8le, mpt::String::spacePadded>(m_songName)
- || !file.ReadStruct(fileHeader)
- || fileHeader.versionHigh != 2 || fileHeader.versionLow > 2
- || !file.CanRead(36u + sizeof(AMS2Description) + fileHeader.numIns * 2u + fileHeader.numOrds * 2u + fileHeader.numPats * 4u))
+ std::string songName;
+ if(!file.ReadSizedString<uint8le, mpt::String::spacePadded>(songName))
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ AMS2FileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
{
+ return false;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return false;
+ }
+ if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(fileHeader))))
+ {
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
+ InitializeGlobals(MOD_TYPE_AMS2);
+
+ m_songName = songName;
+
m_nInstruments = fileHeader.numIns;
m_nChannels = 32;
SetupMODPanning(true);
Index: soundlib/Load_dbm.cpp
===================================================================
--- soundlib/Load_dbm.cpp (revision 8932)
+++ soundlib/Load_dbm.cpp (working copy)
@@ -293,19 +293,51 @@
}
+static bool ValidateHeader(const DBMFileHeader &fileHeader)
+//---------------------------------------------------------
+{
+ if(std::memcmp(fileHeader.dbm0, "DBM0", 4)
+ || fileHeader.trkVerHi > 3)
+ {
+ return false;
+ }
+ return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderDBM(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ DBMFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
bool CSoundFile::ReadDBM(FileReader &file, ModLoadingFlags loadFlags)
//-------------------------------------------------------------------
{
- DBMFileHeader fileHeader;
file.Rewind();
- if(!file.ReadStruct(fileHeader)
- || memcmp(fileHeader.dbm0, "DBM0", 4)
- || fileHeader.trkVerHi > 3)
+ DBMFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ if(!ValidateHeader(fileHeader))
{
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
Index: soundlib/Load_digi.cpp
===================================================================
--- soundlib/Load_digi.cpp (revision 8932)
+++ soundlib/Load_digi.cpp (working copy)
@@ -73,6 +73,36 @@
}
+static bool ValidateHeader(const DIGIFileHeader &fileHeader)
+{
+ if(std::memcmp(fileHeader.signature, "DIGI Booster module\0", 20)
+ || !fileHeader.numChannels
+ || fileHeader.numChannels > 8
+ || fileHeader.lastOrdIndex > 127)
+ {
+ return false;
+ }
+ return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderDIGI(MemoryFileReader file, const uint64 *pfilesize)
+//-----------------------------------------------------------------------------------------------------
+{
+ DIGIFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
bool CSoundFile::ReadDIGI(FileReader &file, ModLoadingFlags loadFlags)
//--------------------------------------------------------------------
{
@@ -79,15 +109,16 @@
file.Rewind();
DIGIFileHeader fileHeader;
- if(!file.ReadStruct(fileHeader)
- || memcmp(fileHeader.signature, "DIGI Booster module\0", 20)
- || !fileHeader.numChannels
- || fileHeader.numChannels > 8
- || fileHeader.lastOrdIndex > 127)
+ if(!file.ReadStruct(fileHeader))
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ if(!ValidateHeader(fileHeader))
{
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
Index: soundlib/Load_dmf.cpp
===================================================================
--- soundlib/Load_dmf.cpp (revision 8932)
+++ soundlib/Load_dmf.cpp (working copy)
@@ -887,18 +887,51 @@
}
+static bool ValidateHeader(const DMFFileHeader &fileHeader)
+//---------------------------------------------------------
+{
+ if(std::memcmp(fileHeader.signature, "DDMF", 4)
+ || !fileHeader.version || fileHeader.version > 10)
+ {
+ return false;
+ }
+ return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderDMF(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ DMFFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
bool CSoundFile::ReadDMF(FileReader &file, ModLoadingFlags loadFlags)
//-------------------------------------------------------------------
{
+ file.Rewind();
+
DMFFileHeader fileHeader;
- file.Rewind();
- if(!file.ReadStruct(fileHeader)
- || memcmp(fileHeader.signature, "DDMF", 4)
- || !fileHeader.version || fileHeader.version > 10)
+ if(!file.ReadStruct(fileHeader))
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ if(!ValidateHeader(fileHeader))
{
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
Index: soundlib/Load_dsm.cpp
===================================================================
--- soundlib/Load_dsm.cpp (revision 8932)
+++ soundlib/Load_dsm.cpp (working copy)
@@ -100,40 +100,100 @@
MPT_BINARY_STRUCT(DSMSampleHeader, 64)
-bool CSoundFile::ReadDSM(FileReader &file, ModLoadingFlags loadFlags)
-//-------------------------------------------------------------------
+struct DSMHeader
{
- file.Rewind();
+ char fileMagic0[4];
+ char fileMagic1[4];
+ char fileMagic2[4];
+};
- char fileMagic0[4], fileMagic1[4], fileMagic2[4];
- if(!file.ReadArray(fileMagic0)) return false;
- if(!file.ReadArray(fileMagic1)) return false;
- if(!file.ReadArray(fileMagic2)) return false;
+MPT_BINARY_STRUCT(DSMHeader, 12)
- if(!memcmp(fileMagic0, "RIFF", 4)
- && !memcmp(fileMagic2, "DSMF", 4))
+
+static bool ValidateHeader(const DSMHeader &fileHeader)
+//-----------------------------------------------------
+{
+ if(!std::memcmp(fileHeader.fileMagic0, "RIFF", 4)
+ && !std::memcmp(fileHeader.fileMagic2, "DSMF", 4))
{
// "Normal" DSM files with RIFF header
// <RIFF> <file size> <DSMF>
- } else if(!memcmp(fileMagic0, "DSMF", 4))
+ return true;
+ } else if(!std::memcmp(fileHeader.fileMagic0, "DSMF", 4))
{
// DSM files with alternative header
// <DSMF> <4 bytes, usually 4x NUL or RIFF> <file size> <4 bytes, usually DSMF but not always>
- file.Skip(4);
+ return true;
} else
{
return false;
}
+}
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderDSM(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ DSMHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ if(std::memcmp(fileHeader.fileMagic0, "DSMF", 4) == 0)
+ {
+ if(!file.Skip(4))
+ {
+ return ProbeWantMoreData;
+ }
+ }
DSMChunk chunkHeader;
+ if(!file.ReadStruct(chunkHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(std::memcmp(chunkHeader.magic, "SONG", 4))
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
- file.ReadStruct(chunkHeader);
+
+bool CSoundFile::ReadDSM(FileReader &file, ModLoadingFlags loadFlags)
+//-------------------------------------------------------------------
+{
+ file.Rewind();
+
+ DSMHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return false;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return false;
+ }
+ if(std::memcmp(fileHeader.fileMagic0, "DSMF", 4) == 0)
+ {
+ file.Skip(4);
+ }
+ DSMChunk chunkHeader;
+ if(!file.ReadStruct(chunkHeader))
+ {
+ return false;
+ }
// Technically, the song chunk could be anywhere in the file, but we're going to simplify
// things by not using a chunk header here and just expect it to be right at the beginning.
- if(memcmp(chunkHeader.magic, "SONG", 4))
+ if(std::memcmp(chunkHeader.magic, "SONG", 4))
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ if(loadFlags == onlyVerifyHeader)
{
return true;
}
Index: soundlib/Load_dtm.cpp
===================================================================
--- soundlib/Load_dtm.cpp (revision 8932)
+++ soundlib/Load_dtm.cpp (working copy)
@@ -181,6 +181,37 @@
MPT_BINARY_STRUCT(DTMText, 12)
+static bool ValidateHeader(const DTMFileHeader &fileHeader)
+//---------------------------------------------------------
+{
+ if(std::memcmp(fileHeader.magic, "D.T.", 4)
+ || fileHeader.headerSize < sizeof(fileHeader) - 8u
+ || fileHeader.headerSize > 256 // Excessively long song title?
+ || fileHeader.type != 0)
+ {
+ return false;
+ }
+ return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderDTM(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ DTMFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
bool CSoundFile::ReadDTM(FileReader &file, ModLoadingFlags loadFlags)
//-------------------------------------------------------------------
{
@@ -187,15 +218,16 @@
file.Rewind();
DTMFileHeader fileHeader;
- if(!file.ReadStruct(fileHeader)
- || memcmp(fileHeader.magic, "D.T.", 4)
- || fileHeader.headerSize < sizeof(fileHeader) - 8u
- || fileHeader.headerSize > 256 // Excessively long song title?
- || fileHeader.type != 0)
+ if(!file.ReadStruct(fileHeader))
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ if(!ValidateHeader(fileHeader))
{
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
Index: soundlib/Load_far.cpp
===================================================================
--- soundlib/Load_far.cpp (revision 8932)
+++ soundlib/Load_far.cpp (working copy)
@@ -102,6 +102,46 @@
MPT_BINARY_STRUCT(FARSampleHeader, 48)
+static bool ValidateHeader(const FARFileHeader &fileHeader)
+//---------------------------------------------------------
+{
+ if(std::memcmp(fileHeader.magic, "FAR\xFE", 4) != 0
+ || std::memcmp(fileHeader.eof, "\x0D\x0A\x1A", 3)
+ )
+ {
+ return false;
+ }
+ if(fileHeader.headerLength < sizeof(FARFileHeader))
+ {
+ return false;
+ }
+ return true;
+}
+
+
+static uint64 GetHeaderMinimumAdditionalSize(const FARFileHeader &fileHeader)
+//---------------------------------------------------------------------------
+{
+ return fileHeader.headerLength - sizeof(FARFileHeader);
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderFAR(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ FARFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader));
+}
+
+
bool CSoundFile::ReadFAR(FileReader &file, ModLoadingFlags loadFlags)
//-------------------------------------------------------------------
{
@@ -108,14 +148,20 @@
file.Rewind();
FARFileHeader fileHeader;
- if(!file.ReadStruct(fileHeader)
- || memcmp(fileHeader.magic, "FAR\xFE", 4) != 0
- || memcmp(fileHeader.eof, "\x0D\x0A\x1A", 3)
- || !file.LengthIsAtLeast(fileHeader.headerLength))
+ if(!file.ReadStruct(fileHeader))
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ if(!ValidateHeader(fileHeader))
{
+ return false;
+ }
+ if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(fileHeader))))
+ {
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
Index: soundlib/Load_gdm.cpp
===================================================================
--- soundlib/Load_gdm.cpp (revision 8932)
+++ soundlib/Load_gdm.cpp (working copy)
@@ -90,28 +90,61 @@
MPT_BINARY_STRUCT(GDMSampleHeader, 62)
-bool CSoundFile::ReadGDM(FileReader &file, ModLoadingFlags loadFlags)
-//-------------------------------------------------------------------
+static const MODTYPE gdmFormatOrigin[] =
{
- file.Rewind();
+ MOD_TYPE_NONE, MOD_TYPE_MOD, MOD_TYPE_MTM, MOD_TYPE_S3M, MOD_TYPE_669, MOD_TYPE_FAR, MOD_TYPE_ULT, MOD_TYPE_STM, MOD_TYPE_MED, MOD_TYPE_PSM
+};
- const MODTYPE gdmFormatOrigin[] =
- {
- MOD_TYPE_NONE, MOD_TYPE_MOD, MOD_TYPE_MTM, MOD_TYPE_S3M, MOD_TYPE_669, MOD_TYPE_FAR, MOD_TYPE_ULT, MOD_TYPE_STM, MOD_TYPE_MED, MOD_TYPE_PSM
- };
- GDMFileHeader fileHeader;
- if(!file.ReadStruct(fileHeader)
- || memcmp(fileHeader.magic, "GDM\xFE", 4)
+static bool ValidateHeader(const GDMFileHeader &fileHeader)
+//---------------------------------------------------------
+{
+ if(std::memcmp(fileHeader.magic, "GDM\xFE", 4)
|| fileHeader.dosEOF[0] != 13 || fileHeader.dosEOF[1] != 10 || fileHeader.dosEOF[2] != 26
- || memcmp(fileHeader.magic2, "GMFS", 4)
+ || std::memcmp(fileHeader.magic2, "GMFS", 4)
|| fileHeader.formatMajorVer != 1 || fileHeader.formatMinorVer != 0
- || fileHeader.originalFormat >= CountOf(gdmFormatOrigin)
+ || fileHeader.originalFormat >= mpt::size(gdmFormatOrigin)
|| fileHeader.originalFormat == 0)
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderGDM(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ GDMFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
{
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
+bool CSoundFile::ReadGDM(FileReader &file, ModLoadingFlags loadFlags)
+//-------------------------------------------------------------------
+{
+ file.Rewind();
+
+ GDMFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return false;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
Index: soundlib/Load_imf.cpp
===================================================================
--- soundlib/Load_imf.cpp (revision 8932)
+++ soundlib/Load_imf.cpp (working copy)
@@ -351,19 +351,84 @@
}
}
+
+static bool ValidateHeader(const IMFFileHeader &fileHeader)
+//---------------------------------------------------------
+{
+ if(std::memcmp(fileHeader.im10, "IM10", 4)
+ || fileHeader.ordNum > 256
+ || fileHeader.insNum >= MAX_INSTRUMENTS
+ )
+ {
+ return false;
+ }
+ bool channelFound = false;
+ for(uint8 chn = 0; chn < 32; chn++)
+ {
+ switch(fileHeader.channels[chn].status)
+ {
+ case 0: // enabled; don't worry about it
+ channelFound = true;
+ break;
+ case 1: // mute
+ channelFound = true;
+ break;
+ case 2: // disabled
+ // nothing
+ break;
+ default: // uhhhh.... freak out
+ return false;
+ }
+ }
+ if(!channelFound)
+ {
+ return false;
+ }
+ return true;
+}
+
+
+static uint64 GetHeaderMinimumAdditionalSize(const IMFFileHeader &fileHeader)
+//---------------------------------------------------------------------------
+{
+ MPT_UNREFERENCED_PARAMETER(fileHeader);
+ return 256;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderIMF(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ IMFFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader));
+}
+
+
bool CSoundFile::ReadIMF(FileReader &file, ModLoadingFlags loadFlags)
//-------------------------------------------------------------------
{
IMFFileHeader fileHeader;
file.Rewind();
- if(!file.ReadStruct(fileHeader)
- || memcmp(fileHeader.im10, "IM10", 4)
- || fileHeader.ordNum > 256
- || fileHeader.insNum >= MAX_INSTRUMENTS
- || !file.CanRead(256))
+ if(!file.ReadStruct(fileHeader))
{
return false;
}
+ if(!ValidateHeader(fileHeader))
+ {
+ return false;
+ }
+ if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(fileHeader))))
+ {
+ return false;
+ }
// Read channel configuration
std::bitset<32> ignoreChannels; // bit set for each channel that's completely disabled
@@ -397,7 +462,9 @@
if(!detectedChannels)
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+
+ if(loadFlags == onlyVerifyHeader)
{
return true;
}
Index: soundlib/Load_it.cpp
===================================================================
--- soundlib/Load_it.cpp (revision 8932)
+++ soundlib/Load_it.cpp (working copy)
@@ -402,6 +402,43 @@
}
+static bool ValidateHeader(const ITFileHeader &fileHeader)
+//--------------------------------------------------------
+{
+ if((std::memcmp(fileHeader.id, "IMPM", 4) && std::memcmp(fileHeader.id, "tpm.", 4))
+ || fileHeader.insnum > 0xFF
+ || fileHeader.smpnum >= MAX_SAMPLES
+ )
+ {
+ return false;
+ }
+ return true;
+}
+
+
+static uint64 GetHeaderMinimumAdditionalSize(const ITFileHeader &fileHeader)
+//--------------------------------------------------------------------------
+{
+ return fileHeader.ordnum + (fileHeader.insnum + fileHeader.smpnum + fileHeader.patnum) * 4;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderIT(MemoryFileReader file, const uint64 *pfilesize)
+//---------------------------------------------------------------------------------------------------
+{
+ ITFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader));
+}
+
+
bool CSoundFile::ReadIT(FileReader &file, ModLoadingFlags loadFlags)
//------------------------------------------------------------------
{
@@ -408,15 +445,20 @@
file.Rewind();
ITFileHeader fileHeader;
- if(!file.ReadStruct(fileHeader)
- || (memcmp(fileHeader.id, "IMPM", 4) && memcmp(fileHeader.id, "tpm.", 4))
- || fileHeader.insnum > 0xFF
- || fileHeader.smpnum >= MAX_SAMPLES
- || !file.CanRead(fileHeader.ordnum + (fileHeader.insnum + fileHeader.smpnum + fileHeader.patnum) * 4))
+ if(!file.ReadStruct(fileHeader))
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ if(!ValidateHeader(fileHeader))
{
+ return false;
+ }
+ if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(fileHeader))))
+ {
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
Index: soundlib/Load_itp.cpp
===================================================================
--- soundlib/Load_itp.cpp (revision 8932)
+++ soundlib/Load_itp.cpp (working copy)
@@ -60,6 +60,54 @@
MPT_BINARY_STRUCT(ITPModCommand, 6)
+struct ITPHeader
+{
+ uint32le magic;
+ uint32le version;
+};
+
+MPT_BINARY_STRUCT(ITPHeader, 8)
+
+
+static bool ValidateHeader(const ITPHeader &hdr)
+//----------------------------------------------
+{
+ if(hdr.magic != MAGIC4BE('.','i','t','p'))
+ {
+ return false;
+ }
+ if(hdr.version > 0x00000103 || hdr.version < 0x00000100)
+ {
+ return false;
+ }
+ return true;
+}
+
+
+static uint64 GetHeaderMinimumAdditionalSize(const ITPHeader &hdr)
+//----------------------------------------------------------------
+{
+ MPT_UNREFERENCED_PARAMETER(hdr);
+ return 12 + 4 + 24 + 4 - sizeof(ITPHeader);
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderITP(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ ITPHeader hdr;
+ if(!file.ReadStruct(hdr))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(hdr))
+ {
+ return ProbeFailure;
+ }
+ return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(hdr));
+}
+
+
bool CSoundFile::ReadITProject(FileReader &file, ModLoadingFlags loadFlags)
//-------------------------------------------------------------------------
{
@@ -81,22 +129,29 @@
ITP_ITPEMBEDIH = 0x40000, // Embed instrument headers in project file
};
- uint32 version, size;
-
file.Rewind();
- // Check file ID
- if(!file.CanRead(12 + 4 + 24 + 4)
- || file.ReadUint32LE() != MAGIC4BE('.','i','t','p') // Magic bytes
- || (version = file.ReadUint32LE()) > 0x00000103 // Format version
- || version < 0x00000100)
+ ITPHeader hdr;
+ if(!file.ReadStruct(hdr))
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ if(!ValidateHeader(hdr))
{
+ return false;
+ }
+ if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(hdr))))
+ {
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
+ uint32 version, size;
+ version = hdr.version;
+
InitializeGlobals(MOD_TYPE_IT);
m_playBehaviour.reset();
file.ReadSizedString<uint32le, mpt::String::maybeNullTerminated>(m_songName);
Index: soundlib/Load_mdl.cpp
===================================================================
--- soundlib/Load_mdl.cpp (revision 8932)
+++ soundlib/Load_mdl.cpp (working copy)
@@ -422,18 +422,50 @@
}
+static bool ValidateHeader(const MDLFileHeader &fileHeader)
+//---------------------------------------------------------
+{
+ if(std::memcmp(fileHeader.id, "DMDL", 4)
+ || fileHeader.version >= 0x20)
+ {
+ return false;
+ }
+ return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderMDL(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ MDLFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
bool CSoundFile::ReadMDL(FileReader &file, ModLoadingFlags loadFlags)
//-------------------------------------------------------------------
{
file.Rewind();
MDLFileHeader fileHeader;
- if(!file.ReadStruct(fileHeader)
- || memcmp(fileHeader.id, "DMDL", 4)
- || fileHeader.version >= 0x20)
+ if(!file.ReadStruct(fileHeader))
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ if(!ValidateHeader(fileHeader))
{
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
Index: soundlib/Load_med.cpp
===================================================================
--- soundlib/Load_med.cpp (revision 8932)
+++ soundlib/Load_med.cpp (working copy)
@@ -493,22 +493,68 @@
}
+static bool ValidateHeader(const MEDMODULEHEADER &pmmh)
+//-----------------------------------------------------
+{
+ if(std::memcmp(pmmh.id, "MMD", 3)
+ || pmmh.id[3] < '0' || pmmh.id[3] > '3'
+ || pmmh.song == 0
+ )
+ {
+ return false;
+ }
+ return true;
+}
+
+
+static uint64 GetHeaderMinimumAdditionalSize(const MEDMODULEHEADER &pmmh)
+//-----------------------------------------------------------------------
+{
+ MPT_UNREFERENCED_PARAMETER(pmmh);
+ return sizeof(MMD0SONGHEADER);
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderMED(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ MEDMODULEHEADER pmmh;
+ if(!file.ReadStruct(pmmh))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(pmmh))
+ {
+ return ProbeFailure;
+ }
+ return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(pmmh));
+}
+
+
bool CSoundFile::ReadMed(FileReader &file, ModLoadingFlags loadFlags)
//------------------------------------------------------------------
{
file.Rewind();
MEDMODULEHEADER pmmh;
- uint32 dwSong;
- if(!file.CanRead(512)
- || !file.ReadStruct(pmmh)
- || memcmp(pmmh.id, "MMD", 3)
- || pmmh.id[3] < '0' || pmmh.id[3] > '3'
- || (dwSong = pmmh.song) == 0
- || !file.LengthIsAtLeast(dwSong + sizeof(MMD0SONGHEADER)))
+ if(!file.ReadStruct(pmmh))
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ if(!ValidateHeader(pmmh))
{
+ return false;
+ }
+ if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(pmmh))))
+ {
+ return false;
+ }
+ const uint32 dwSong = pmmh.song;
+ if(!file.LengthIsAtLeast(dwSong + sizeof(MMD0SONGHEADER)))
+ {
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
Index: soundlib/Load_mo3.cpp
===================================================================
--- soundlib/Load_mo3.cpp (revision 8932)
+++ soundlib/Load_mo3.cpp (working copy)
@@ -691,26 +691,74 @@
#endif // MPT_WITH_VORBIS && MPT_WITH_VORBISFILE
+struct MO3ContainerHeader
+{
+ char magic[3]; // MO3
+ uint8le version;
+ uint32le musicSize;
+};
+MPT_BINARY_STRUCT(MO3ContainerHeader, 8)
+
+
+static bool ValidateHeader(const MO3ContainerHeader &containerHeader)
+//-------------------------------------------------------------------
+{
+ if(std::memcmp(containerHeader.magic, "MO3", 3))
+ {
+ return false;
+ }
+ if(containerHeader.musicSize <= sizeof(MO3FileHeader))
+ {
+ return false;
+ }
+ if(containerHeader.version > 5)
+ {
+ return false;
+ }
+ return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderMO3(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ MO3ContainerHeader containerHeader;
+ if(!file.ReadStruct(containerHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(containerHeader))
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
bool CSoundFile::ReadMO3(FileReader &file, ModLoadingFlags loadFlags)
//-------------------------------------------------------------------
{
file.Rewind();
- if(!file.CanRead(12) || !file.ReadMagic("MO3"))
+ MO3ContainerHeader containerHeader;
+ if(!file.ReadStruct(containerHeader))
{
return false;
}
- const uint8 version = file.ReadUint8();
- const uint32 musicSize = file.ReadUint32LE();
- if(musicSize <= sizeof(MO3FileHeader) || version > 5)
+ if(!ValidateHeader(containerHeader))
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ if(loadFlags == onlyVerifyHeader)
{
return true;
}
+ const uint8 version = containerHeader.version;
+ const uint32 musicSize = containerHeader.musicSize;
+
uint32 compressedSize = uint32_max;
if(version >= 5)
{
Index: soundlib/Load_mod.cpp
===================================================================
--- soundlib/Load_mod.cpp (revision 8932)
+++ soundlib/Load_mod.cpp (working copy)
@@ -654,20 +654,20 @@
}
-bool CSoundFile::ReadMod(FileReader &file, ModLoadingFlags loadFlags)
-//-------------------------------------------------------------------
+struct MODMagicResult
{
- char magic[4];
- if(!file.Seek(1080) || !file.ReadArray(magic))
- {
- return false;
- }
+ CHANNELINDEX m_nChannels = 4;
+ mpt::ustring m_madeWithTracker = mpt::ustring();
+ bool isNoiseTracker = false;
+ bool isStartrekker = false;
+ bool isGenericMultiChannel = false;
+ bool setMODVBlankTiming = false;
+};
- InitializeGlobals(MOD_TYPE_MOD);
- m_nChannels = 4;
- bool isNoiseTracker = false, isStartrekker = false, isGenericMultiChannel = false;
- // Check MOD Magic
+static bool CheckMODMagic(const char magic[4], MODMagicResult *result)
+{
+ MODMagicResult *r = result;
if(IsMagic(magic, "M.K.") // ProTracker and compatible
|| IsMagic(magic, "M!K!") // ProTracker (>64 patterns)
|| IsMagic(magic, "PATT") // ProTracker 3.6
@@ -674,66 +674,143 @@
|| IsMagic(magic, "NSMS") // kingdomofpleasure.mod by bee hunter
|| IsMagic(magic, "LARD")) // judgement_day_gvine.mod by 4-mat
{
- m_nChannels = 4;
- m_madeWithTracker = MPT_USTRING("Generic ProTracker or compatible");
+ if(r)
+ {
+ r->m_nChannels = 4;
+ r->m_madeWithTracker = MPT_USTRING("Generic ProTracker or compatible");
+ }
} else if(IsMagic(magic, "M&K!") // "His Master's Noise" musicdisk
|| IsMagic(magic, "FEST") // "His Master's Noise" musicdisk
|| IsMagic(magic, "N.T."))
{
- m_nChannels = 4;
- m_madeWithTracker = MPT_USTRING("NoiseTracker");
- isNoiseTracker = true;
+ if(r)
+ {
+ r->m_nChannels = 4;
+ r->m_madeWithTracker = MPT_USTRING("NoiseTracker");
+ r->isNoiseTracker = true;
+ }
} else if(IsMagic(magic, "OKTA")
|| IsMagic(magic, "OCTA"))
{
// Oktalyzer
- m_nChannels = 8;
- m_madeWithTracker = MPT_USTRING("Oktalyzer");
+ if(r)
+ {
+ r->m_nChannels = 8;
+ r->m_madeWithTracker = MPT_USTRING("Oktalyzer");
+ }
} else if(IsMagic(magic, "CD81")
|| IsMagic(magic, "CD61"))
{
// Octalyser on Atari STe/Falcon
- m_nChannels = magic[2] - '0';
- m_madeWithTracker = MPT_USTRING("Octalyser (Atari)");
+ if(r)
+ {
+ r->m_nChannels = magic[2] - '0';
+ r->m_madeWithTracker = MPT_USTRING("Octalyser (Atari)");
+ }
} else if(!memcmp(magic, "FA0", 3) && magic[3] >= '4' && magic[3] <= '8')
{
// Digital Tracker on Atari Falcon
- m_nChannels = magic[3] - '0';
- m_madeWithTracker = MPT_USTRING("Digital Tracker");
+ if(r)
+ {
+ r->m_nChannels = magic[3] - '0';
+ r->m_madeWithTracker = MPT_USTRING("Digital Tracker");
+ }
} else if((!memcmp(magic, "FLT", 3) || !memcmp(magic, "EXO", 3)) && magic[3] >= '4' && magic[3] <= '9')
{
// FLTx / EXOx - Startrekker by Exolon / Fairlight
- m_nChannels = magic[3] - '0';
- m_madeWithTracker = MPT_USTRING("Startrekker");
- isStartrekker = true;
- m_playBehaviour.set(kMODVBlankTiming);
+ if(r)
+ {
+ r->m_nChannels = magic[3] - '0';
+ r->m_madeWithTracker = MPT_USTRING("Startrekker");
+ r->isStartrekker = true;
+ r->setMODVBlankTiming = true;
+ }
} else if(magic[0] >= '1' && magic[0] <= '9' && !memcmp(magic + 1, "CHN", 3))
{
// xCHN - Many trackers
- m_nChannels = magic[0] - '0';
- m_madeWithTracker = MPT_USTRING("Generic MOD-compatible Tracker");
- isGenericMultiChannel = true;
+ if(r)
+ {
+ r->m_nChannels = magic[0] - '0';
+ r->m_madeWithTracker = MPT_USTRING("Generic MOD-compatible Tracker");
+ r->isGenericMultiChannel = true;
+ }
} else if(magic[0] >= '1' && magic[0] <= '9' && magic[1]>='0' && magic[1] <= '9'
&& (!memcmp(magic + 2, "CH", 2) || !memcmp(magic + 2, "CN", 2)))
{
// xxCN / xxCH - Many trackers
- m_nChannels = (magic[0] - '0') * 10 + magic[1] - '0';
- m_madeWithTracker = MPT_USTRING("Generic MOD-compatible Tracker");
- isGenericMultiChannel = true;
+ if(r)
+ {
+ r->m_nChannels = (magic[0] - '0') * 10 + magic[1] - '0';
+ r->m_madeWithTracker = MPT_USTRING("Generic MOD-compatible Tracker");
+ r->isGenericMultiChannel = true;
+ }
} else if(!memcmp(magic, "TDZ", 3) && magic[3] >= '4' && magic[3] <= '9')
{
// TDZx - TakeTracker
- m_nChannels = magic[3] - '0';
- m_madeWithTracker = MPT_USTRING("TakeTracker");
+ if(r)
+ {
+ r->m_nChannels = magic[3] - '0';
+ r->m_madeWithTracker = MPT_USTRING("TakeTracker");
+ }
} else
{
return false;
}
+ return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderMOD(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ if(!file.CanRead(1080 + 4))
+ {
+ return ProbeWantMoreData;
+ }
+ file.Seek(1080);
+ char magic[4];
+ file.ReadArray(magic);
+ if(!CheckMODMagic(magic, nullptr))
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
+bool CSoundFile::ReadMod(FileReader &file, ModLoadingFlags loadFlags)
+//-------------------------------------------------------------------
+{
+ char magic[4];
+ if(!file.Seek(1080) || !file.ReadArray(magic))
+ {
+ return false;
+ }
+
+ InitializeGlobals(MOD_TYPE_MOD);
+
+ MODMagicResult modMagicResult;
+ if(!CheckMODMagic(magic, &modMagicResult))
+ {
+ return false;
+ }
+
if(loadFlags == onlyVerifyHeader)
{
return true;
}
+ m_nChannels = modMagicResult.m_nChannels;
+ m_madeWithTracker = modMagicResult.m_madeWithTracker;
+ bool isNoiseTracker = modMagicResult.isNoiseTracker;
+ bool isStartrekker = modMagicResult.isStartrekker;
+ bool isGenericMultiChannel = modMagicResult.isGenericMultiChannel;
+ if(modMagicResult.setMODVBlankTiming)
+ {
+ m_playBehaviour.set(kMODVBlankTiming);
+ }
+
LimitMax(m_nChannels, MAX_BASECHANNELS);
// Startrekker 8 channel mod (needs special treatment, see below)
@@ -1166,8 +1243,8 @@
// Check if a name string is valid (i.e. doesn't contain binary garbage data)
template<size_t N>
-static uint32 CountInvalidChars(char (&name)[N])
-//----------------------------------------------
+static uint32 CountInvalidChars(const char (&name)[N])
+//----------------------------------------------------
{
uint32 invalidChars = 0;
for(auto c : name)
@@ -1195,25 +1272,127 @@
};
-bool CSoundFile::ReadM15(FileReader &file, ModLoadingFlags loadFlags)
-//-------------------------------------------------------------------
+
+struct M15FileHeaders
{
- file.Rewind();
+ char songname[20];
+ MODSampleHeader sampleHeaders[15];
+ MODFileHeader fileHeader;
+};
- char songname[20];
- file.ReadArray(songname);
+MPT_BINARY_STRUCT(M15FileHeaders, 20 + 15 * 30 + 130)
+
+static bool ValidateHeader(const M15FileHeaders &fileHeaders)
+{
// In theory, sample and song names should only ever contain printable ASCII chars and null.
// 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: 20 bogus characters in total
// or more than 5 invalid characters just in the title alone.
- uint32 invalidChars = CountInvalidChars(songname);
- if(invalidChars > 5 || !file.CanRead(sizeof(MODSampleHeader) * 15 + sizeof(MODFileHeader)))
+ uint32 invalidChars = CountInvalidChars(fileHeaders.songname);
+ if(invalidChars > 5)
{
return false;
}
+ SmpLength totalSampleLen = 0;
+ uint8 allVolumes = 0;
+
+ for(SAMPLEINDEX smp = 0; smp < 15; smp++)
+ {
+ const MODSampleHeader &sampleHeader = fileHeaders.sampleHeaders[smp];
+
+ invalidChars += CountInvalidChars(sampleHeader.name);
+
+ // Sanity checks - invalid character count adjusted for ata.mod (MD5 937b79b54026fa73a1a4d3597c26eace, SHA1 3322ca62258adb9e0ae8e9afe6e0c29d39add874)
+ if(invalidChars > 48
+ || sampleHeader.volume > 64
+ || sampleHeader.finetune != 0
+ || sampleHeader.length > 32768)
+ {
+ return false;
+ }
+
+ totalSampleLen += sampleHeader.length;
+ allVolumes |= sampleHeader.volume;
+
+ }
+
+ // 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)
+ {
+ return false;
+ }
+
+ // Sanity check: No more than 128 positions. ST's GUI limits tempo to [1, 220].
+ // There are some mods with a tempo of 0 (explora3-death.mod) though, so ignore the lower limit.
+ if(fileHeaders.fileHeader.numOrders > 128 || fileHeaders.fileHeader.restartPos > 220)
+ {
+ return false;
+ }
+
+ for(uint8 ord : fileHeaders.fileHeader.orderList)
+ {
+ // Sanity check: 64 patterns max.
+ if(ord > 63)
+ {
+ return false;
+ }
+ }
+
+ bool allPatternsNull = true;
+ for(uint8 pat : fileHeaders.fileHeader.orderList)
+ {
+ if(pat != 0 && pat < 128)
+ {
+ allPatternsNull = false;
+ }
+ }
+ if(fileHeaders.fileHeader.restartPos == 0 && fileHeaders.fileHeader.numOrders == 0 && allPatternsNull)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderM15(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ M15FileHeaders fileHeaders;
+ if(!file.ReadStruct(fileHeaders))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeaders))
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
+bool CSoundFile::ReadM15(FileReader &file, ModLoadingFlags loadFlags)
+//-------------------------------------------------------------------
+{
+ file.Rewind();
+
+ M15FileHeaders fileHeaders;
+ if(!file.ReadStruct(fileHeaders))
+ {
+ return false;
+ }
+ if(!ValidateHeader(fileHeaders))
+ {
+ return false;
+ }
+
+ char songname[20];
+ std::memcpy(songname, fileHeaders.songname, 20);
+
InitializeGlobals(MOD_TYPE_MOD);
m_playBehaviour.reset(kMODOneShotLoops);
m_playBehaviour.set(kMODIgnorePanning);
@@ -1224,26 +1403,15 @@
bool hasDiskNames = true;
SmpLength totalSampleLen = 0;
- uint8 allVolumes = 0;
m_nSamples = 15;
+ file.Seek(20);
for(SAMPLEINDEX smp = 1; smp <= 15; smp++)
{
MODSampleHeader sampleHeader;
ReadSample(file, sampleHeader, Samples[smp], m_szNames[smp], true);
- invalidChars += CountInvalidChars(sampleHeader.name);
- // Sanity checks - invalid character count adjusted for ata.mod (MD5 937b79b54026fa73a1a4d3597c26eace, SHA1 3322ca62258adb9e0ae8e9afe6e0c29d39add874)
- if(invalidChars > 48
- || sampleHeader.volume > 64
- || sampleHeader.finetune != 0
- || sampleHeader.length > 32768)
- {
- return false;
- }
-
totalSampleLen += Samples[smp].nLength;
- allVolumes |= sampleHeader.volume;
if(m_szNames[smp][0] && ((memcmp(m_szNames[smp], "st-", 3) && memcmp(m_szNames[smp], "ST-", 3)) || m_szNames[smp][5] != ':'))
{
@@ -1264,36 +1432,22 @@
minVersion = std::max(minVersion, MST1_00);
}
- // 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)
- return false;
-
MODFileHeader fileHeader;
file.ReadStruct(fileHeader);
- // Sanity check: No more than 128 positions. ST's GUI limits tempo to [1, 220].
- // There are some mods with a tempo of 0 (explora3-death.mod) though, so ignore the lower limit.
- if(fileHeader.numOrders > 128 || fileHeader.restartPos > 220)
- return false;
+ ReadOrderFromArray(Order(), fileHeader.orderList);
+ PATTERNINDEX numPatterns = GetNumPatterns(file, Order(), fileHeader.numOrders, totalSampleLen, m_nChannels, false);
- for(uint8 ord : fileHeader.orderList)
+ // Most likely just a file with lots of NULs at the start
+ if(fileHeader.restartPos == 0 && fileHeader.numOrders == 0 && numPatterns <= 1)
{
- // Sanity check: 64 patterns max.
- if(ord > 63)
- return false;
+ return false;
}
- ReadOrderFromArray(Order(), fileHeader.orderList);
- PATTERNINDEX numPatterns = GetNumPatterns(file, Order(), fileHeader.numOrders, totalSampleLen, m_nChannels, false);
-
// Let's see if the file is too small (including some overhead for broken files like sll7.mod or ghostbus.mod)
if(file.BytesLeft() + 65536 < numPatterns * 64u * 4u + totalSampleLen)
return false;
- // Most likely just a file with lots of NULs at the start
- if(fileHeader.restartPos == 0 && fileHeader.numOrders == 0 && numPatterns <= 1)
- return false;
-
if(loadFlags == onlyVerifyHeader)
return true;
@@ -1579,6 +1733,55 @@
}
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderICE(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ if(!file.CanRead(1464 + 4))
+ {
+ return ProbeWantMoreData;
+ }
+ file.Seek(1464);
+ char magic[4];
+ file.ReadArray(magic);
+ if(!IsMagic(magic, "MTN\0") && !IsMagic(magic, "IT10"))
+ {
+ return ProbeFailure;
+ }
+ file.Seek(20);
+ uint32 invalidChars = 0;
+ for(SAMPLEINDEX smp = 1; smp <= 31; smp++)
+ {
+ MODSampleHeader sampleHeader;
+ if(!file.ReadStruct(sampleHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ invalidChars += CountInvalidChars(sampleHeader.name);
+ }
+ if(invalidChars > 256)
+ {
+ return ProbeFailure;
+ }
+ const uint8 numOrders = file.ReadUint8();
+ const uint8 numTracks = file.ReadUint8();
+ if(numOrders > 128)
+ {
+ return ProbeFailure;
+ }
+ uint8 tracks[128 * 4];
+ file.ReadArray(tracks);
+ for(auto track : tracks)
+ {
+ if(track > numTracks)
+ {
+ return ProbeFailure;
+ }
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
// SoundTracker 2.6 / Ice Tracker variation of the MOD format
// The only real difference to other SoundTracker formats is the way patterns are stored:
// Every pattern consists of four independent, re-usable tracks.
@@ -1597,11 +1800,15 @@
m_playBehaviour.set(kMODSampleSwap); // untested
if(IsMagic(magic, "MTN\0"))
+ {
m_madeWithTracker = MPT_USTRING("SoundTracker 2.6");
- else if(IsMagic(magic, "IT10"))
+ } else if(IsMagic(magic, "IT10"))
+ {
m_madeWithTracker = MPT_USTRING("Ice Tracker 1.0 / 1.1");
- else
+ } else
+ {
return false;
+ }
// Reading song title
file.Seek(0);
@@ -1623,7 +1830,9 @@
const uint8 numOrders = file.ReadUint8();
const uint8 numTracks = file.ReadUint8();
if(numOrders > 128)
+ {
return false;
+ }
uint8 tracks[128 * 4];
file.ReadArray(tracks);
@@ -1630,11 +1839,15 @@
for(auto track : tracks)
{
if(track > numTracks)
+ {
return false;
+ }
}
if(loadFlags == onlyVerifyHeader)
+ {
return true;
+ }
// Now we can be pretty sure that this is a valid MOD file. Set up default song settings.
m_nChannels = 4;
@@ -1732,6 +1945,48 @@
+struct PT36Header
+{
+ char magicFORM[4]; // "FORM"
+ uint8be dummy1[4];
+ char magicMODL[4]; // "MODL"
+};
+
+MPT_BINARY_STRUCT(PT36Header, 12);
+
+
+static bool ValidateHeader(const PT36Header &fileHeader)
+//------------------------------------------------------
+{
+ if(std::memcmp(fileHeader.magicFORM, "FORM", 4))
+ {
+ return false;
+ }
+ if(std::memcmp(fileHeader.magicMODL, "MODL", 4))
+ {
+ return false;
+ }
+ return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderPT36(MemoryFileReader file, const uint64 *pfilesize)
+//-----------------------------------------------------------------------------------------------------
+{
+ PT36Header fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
// ProTracker 3.6 version of the MOD format
// Basically just a normal ProTracker mod with different magic, wrapped in an IFF file.
// The "PTDT" chunk is passed to the normal MOD loader.
@@ -1739,16 +1994,20 @@
//--------------------------------------------------------------------
{
file.Rewind();
- if(!file.ReadMagic("FORM")
- || !file.Skip(4)
- || !file.ReadMagic("MODL"))
+
+ PT36Header fileHeader;
+ if(!file.ReadStruct(fileHeader))
{
return false;
}
-
+ if(!ValidateHeader(fileHeader))
+ {
+ return false;
+ }
+
bool ok = false, infoOk = false;
FileReader commentChunk;
- mpt::ustring version = MPT_USTRING("3.6");
+ mpt::ustring version;
PT36InfoChunk info;
MemsetZero(info);
@@ -1799,6 +2058,11 @@
break;
}
} while(file.ReadStruct(iffHead));
+
+ if(version.empty())
+ {
+ version = MPT_USTRING("3.6");
+ }
// both an info chunk and a module are required
if(ok && infoOk)
Index: soundlib/Load_mt2.cpp
===================================================================
--- soundlib/Load_mt2.cpp (revision 8932)
+++ soundlib/Load_mt2.cpp (working copy)
@@ -395,23 +395,66 @@
}
-bool CSoundFile::ReadMT2(FileReader &file, ModLoadingFlags loadFlags)
-//-------------------------------------------------------------------
+static bool ValidateHeader(const MT2FileHeader &fileHeader)
+//---------------------------------------------------------
{
- file.Rewind();
- MT2FileHeader fileHeader;
- if(!file.ReadStruct(fileHeader)
- || memcmp(fileHeader.signature, "MT20", 4)
+ if(std::memcmp(fileHeader.signature, "MT20", 4)
|| fileHeader.version < 0x200 || fileHeader.version >= 0x300
|| fileHeader.numChannels < 1 || fileHeader.numChannels > 64
|| fileHeader.numOrders > 256
|| fileHeader.numInstruments >= MAX_INSTRUMENTS
|| fileHeader.numSamples >= MAX_SAMPLES
- || !file.CanRead(256))
+ )
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ return true;
+}
+
+
+static uint64 GetHeaderMinimumAdditionalSize(const MT2FileHeader &fileHeader)
+//---------------------------------------------------------------------------
+{
+ MPT_UNREFERENCED_PARAMETER(fileHeader);
+ return 256;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderMT2(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ MT2FileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
{
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader));
+}
+
+
+bool CSoundFile::ReadMT2(FileReader &file, ModLoadingFlags loadFlags)
+//-------------------------------------------------------------------
+{
+ file.Rewind();
+ MT2FileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return false;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return false;
+ }
+ if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(fileHeader))))
+ {
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
Index: soundlib/Load_mtm.cpp
===================================================================
--- soundlib/Load_mtm.cpp (revision 8932)
+++ soundlib/Load_mtm.cpp (working copy)
@@ -75,23 +75,65 @@
MPT_BINARY_STRUCT(MTMSampleHeader, 37)
-bool CSoundFile::ReadMTM(FileReader &file, ModLoadingFlags loadFlags)
-//-------------------------------------------------------------------
+static bool ValidateHeader(const MTMFileHeader &fileHeader)
+//---------------------------------------------------------
{
- file.Rewind();
- MTMFileHeader fileHeader;
- if(!file.ReadStruct(fileHeader)
- || memcmp(fileHeader.id, "MTM", 3)
+ if(std::memcmp(fileHeader.id, "MTM", 3)
|| fileHeader.version >= 0x20
|| fileHeader.lastOrder > 127
|| fileHeader.beatsPerTrack > 64
|| fileHeader.numChannels > 32
|| fileHeader.numChannels == 0
- || !file.CanRead(sizeof(MTMSampleHeader) * fileHeader.numSamples + 128 + 192 * fileHeader.numTracks + 64 * (fileHeader.lastPattern + 1) + fileHeader.commentSize))
+ )
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ return true;
+}
+
+
+static uint64 GetHeaderMinimumAdditionalSize(const MTMFileHeader &fileHeader)
+//---------------------------------------------------------------------------
+{
+ return sizeof(MTMSampleHeader) * fileHeader.numSamples + 128 + 192 * fileHeader.numTracks + 64 * (fileHeader.lastPattern + 1) + fileHeader.commentSize;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderMTM(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ MTMFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
{
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader));
+}
+
+
+bool CSoundFile::ReadMTM(FileReader &file, ModLoadingFlags loadFlags)
+//-------------------------------------------------------------------
+{
+ file.Rewind();
+ MTMFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return false;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return false;
+ }
+ if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(fileHeader))))
+ {
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
Index: soundlib/Load_okt.cpp
===================================================================
--- soundlib/Load_okt.cpp (revision 8932)
+++ soundlib/Load_okt.cpp (working copy)
@@ -258,6 +258,35 @@
}
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderOKT(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ if(!file.CanRead(8))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!file.ReadMagic("OKTASONG"))
+ {
+ return ProbeFailure;
+ }
+ OktIffChunk iffHead;
+ if(!file.ReadStruct(iffHead))
+ {
+ return ProbeWantMoreData;
+ }
+ if(iffHead.chunksize == 0)
+ {
+ return ProbeFailure;
+ }
+ if((iffHead.signature & 0x7f7f7f7fu) != iffHead.signature) // ASCII?
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
bool CSoundFile::ReadOKT(FileReader &file, ModLoadingFlags loadFlags)
//-------------------------------------------------------------------
{
Index: soundlib/Load_plm.cpp
===================================================================
--- soundlib/Load_plm.cpp (revision 8932)
+++ soundlib/Load_plm.cpp (working copy)
@@ -83,6 +83,44 @@
MPT_BINARY_STRUCT(PLMOrderItem, 4)
+static bool ValidateHeader(const PLMFileHeader &fileHeader)
+//---------------------------------------------------------
+{
+ if(std::memcmp(fileHeader.magic, "PLM\x1A", 4)
+ || fileHeader.version != 0x10
+ || fileHeader.numChannels == 0 || fileHeader.numChannels > 32
+ || fileHeader.headerSize < sizeof(PLMFileHeader)
+ )
+ {
+ return false;
+ }
+ return true;
+}
+
+
+static uint64 GetHeaderMinimumAdditionalSize(const PLMFileHeader &fileHeader)
+//---------------------------------------------------------------------------
+{
+ return fileHeader.headerSize - sizeof(PLMFileHeader) + 4 * (fileHeader.numOrders + fileHeader.numPatterns + fileHeader.numSamples);
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderPLM(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ PLMFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader));
+}
+
+
bool CSoundFile::ReadPLM(FileReader &file, ModLoadingFlags loadFlags)
//-------------------------------------------------------------------
{
@@ -89,19 +127,28 @@
file.Rewind();
PLMFileHeader fileHeader;
- if(!file.ReadStruct(fileHeader)
- || memcmp(fileHeader.magic, "PLM\x1A", 4)
- || fileHeader.version != 0x10
- || fileHeader.numChannels == 0 || fileHeader.numChannels > 32
- || !file.Seek(fileHeader.headerSize)
- || !file.CanRead(4 * (fileHeader.numOrders + fileHeader.numPatterns + fileHeader.numSamples)))
+ if(!file.ReadStruct(fileHeader))
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ if(!ValidateHeader(fileHeader))
{
+ return false;
+ }
+ if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(fileHeader))))
+ {
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
+ if(!file.Seek(fileHeader.headerSize))
+ {
+ return false;
+ }
+
InitializeGlobals(MOD_TYPE_PLM);
InitializeChannels();
m_SongFlags = SONG_ITOLDEFFECTS;
Index: soundlib/Load_psm.cpp
===================================================================
--- soundlib/Load_psm.cpp (revision 8932)
+++ soundlib/Load_psm.cpp (working copy)
@@ -208,10 +208,51 @@
offset = 0;
}
return ConvertStrTo<uint16>(&patternID[offset]);
+}
+
+static bool ValidateHeader(const PSMFileHeader &fileHeader)
+//---------------------------------------------------------
+{
+ if(std::memcmp(fileHeader.formatID, "PSM ", 4)
+ || std::memcmp(fileHeader.fileInfoID, "FILE", 4))
+ {
+ return false;
+ }
+ return true;
}
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderPSM(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ PSMFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ PSMChunk chunkHeader;
+ if(!file.ReadStruct(chunkHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(chunkHeader.length == 0)
+ {
+ return ProbeFailure;
+ }
+ if((chunkHeader.id & 0x7f7f7f7fu) != chunkHeader.id) // ASCII?
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
bool CSoundFile::ReadPSM(FileReader &file, ModLoadingFlags loadFlags)
//-------------------------------------------------------------------
{
@@ -244,8 +285,7 @@
#endif // MPT_PSM_DECRYPT
// Check header
- if(memcmp(fileHeader.formatID, "PSM ", 4)
- || memcmp(fileHeader.fileInfoID, "FILE", 4))
+ if(!ValidateHeader(fileHeader))
{
return false;
}
@@ -1029,15 +1069,10 @@
MPT_BINARY_STRUCT(PSM16PatternHeader, 4)
-bool CSoundFile::ReadPSM16(FileReader &file, ModLoadingFlags loadFlags)
-//---------------------------------------------------------------------
+static bool ValidateHeader(const PSM16FileHeader &fileHeader)
+//-----------------------------------------------------------
{
- file.Rewind();
-
- // Is it a valid PSM16 file?
- PSM16FileHeader fileHeader;
- if(!file.ReadStruct(fileHeader)
- || memcmp(fileHeader.formatID, "PSM\xFE", 4)
+ if(std::memcmp(fileHeader.formatID, "PSM\xFE", 4)
|| fileHeader.lineEnd != 0x1A
|| (fileHeader.formatVersion != 0x10 && fileHeader.formatVersion != 0x01) // why is this sometimes 0x01?
|| fileHeader.patternVersion != 0 // 255ch pattern version not supported (did anyone use this?)
@@ -1047,8 +1082,45 @@
|| std::max(fileHeader.numChannelsPlay, fileHeader.numChannelsReal) == 0)
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderPSM16(MemoryFileReader file, const uint64 *pfilesize)
+//------------------------------------------------------------------------------------------------------
+{
+ PSM16FileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
{
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
+bool CSoundFile::ReadPSM16(FileReader &file, ModLoadingFlags loadFlags)
+//---------------------------------------------------------------------
+{
+ file.Rewind();
+
+ // Is it a valid PSM16 file?
+ PSM16FileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return false;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
Index: soundlib/Load_ptm.cpp
===================================================================
--- soundlib/Load_ptm.cpp (revision 8932)
+++ soundlib/Load_ptm.cpp (working copy)
@@ -104,14 +104,10 @@
MPT_BINARY_STRUCT(PTMSampleHeader, 80)
-bool CSoundFile::ReadPTM(FileReader &file, ModLoadingFlags loadFlags)
-//-------------------------------------------------------------------
+static bool ValidateHeader(const PTMFileHeader &fileHeader)
+//---------------------------------------------------------
{
- file.Rewind();
-
- PTMFileHeader fileHeader;
- if(!file.ReadStruct(fileHeader)
- || memcmp(fileHeader.magic, "PTMF", 4)
+ if(std::memcmp(fileHeader.magic, "PTMF", 4)
|| fileHeader.dosEOF != 26
|| fileHeader.versionHi > 2
|| fileHeader.flags != 0
@@ -120,11 +116,57 @@
|| !fileHeader.numOrders || fileHeader.numOrders > 256
|| !fileHeader.numSamples || fileHeader.numSamples > 255
|| !fileHeader.numPatterns || fileHeader.numPatterns > 128
- || !file.CanRead(fileHeader.numSamples * sizeof(PTMSampleHeader)))
+ )
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ return true;
+}
+
+
+static uint64 GetHeaderMinimumAdditionalSize(const PTMFileHeader &fileHeader)
+//---------------------------------------------------------------------------
+{
+ return fileHeader.numSamples * sizeof(PTMSampleHeader);
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderPTM(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ PTMFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
{
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader));
+}
+
+
+bool CSoundFile::ReadPTM(FileReader &file, ModLoadingFlags loadFlags)
+//-------------------------------------------------------------------
+{
+ file.Rewind();
+
+ PTMFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return false;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return false;
+ }
+ if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(fileHeader))))
+ {
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
Index: soundlib/Load_s3m.cpp
===================================================================
--- soundlib/Load_s3m.cpp (revision 8932)
+++ soundlib/Load_s3m.cpp (working copy)
@@ -172,6 +172,43 @@
};
+static bool ValidateHeader(const S3MFileHeader &fileHeader)
+//---------------------------------------------------------
+{
+ if(std::memcmp(fileHeader.magic, "SCRM", 4)
+ || fileHeader.fileType != S3MFileHeader::idS3MType
+ || (fileHeader.formatVersion != S3MFileHeader::oldVersion && fileHeader.formatVersion != S3MFileHeader::newVersion)
+ )
+ {
+ return false;
+ }
+ return true;
+}
+
+
+static uint64 GetHeaderMinimumAdditionalSize(const S3MFileHeader &fileHeader)
+//---------------------------------------------------------------------------
+{
+ return fileHeader.ordNum + (fileHeader.smpNum + fileHeader.patNum) * 2;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderS3M(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ S3MFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader));
+}
+
+
bool CSoundFile::ReadS3M(FileReader &file, ModLoadingFlags loadFlags)
//-------------------------------------------------------------------
{
@@ -179,15 +216,20 @@
// Is it a valid S3M file?
S3MFileHeader fileHeader;
- if(!file.ReadStruct(fileHeader)
- || !file.CanRead(fileHeader.ordNum + (fileHeader.smpNum + fileHeader.patNum) * 2)
- || memcmp(fileHeader.magic, "SCRM", 4)
- || fileHeader.fileType != S3MFileHeader::idS3MType
- || (fileHeader.formatVersion != S3MFileHeader::oldVersion && fileHeader.formatVersion != S3MFileHeader::newVersion))
+ if(!file.ReadStruct(fileHeader))
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ if(!ValidateHeader(fileHeader))
{
+ return false;
+ }
+ if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(fileHeader))))
+ {
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
Index: soundlib/Load_sfx.cpp
===================================================================
--- soundlib/Load_sfx.cpp (revision 8932)
+++ soundlib/Load_sfx.cpp (working copy)
@@ -96,6 +96,87 @@
return 0;
}
+
+static bool ValidateHeader(const SFXFileHeader &fileHeader)
+//---------------------------------------------------------
+{
+ if(fileHeader.numOrders > 128)
+ {
+ return false;
+ }
+ return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderSFX(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ SAMPLEINDEX numSamples = 0;
+ if(numSamples == 0)
+ {
+ file.Rewind();
+ if(!file.CanRead(0x40))
+ {
+ return ProbeWantMoreData;
+ }
+ if(file.Seek(0x3c) && file.ReadMagic("SONG"))
+ {
+ numSamples = 15;
+ }
+ }
+ if(numSamples == 0)
+ {
+ file.Rewind();
+ if(!file.CanRead(0x80))
+ {
+ return ProbeWantMoreData;
+ }
+ if(file.Seek(0x7c) && file.ReadMagic("SO31"))
+ {
+ numSamples = 31;
+ }
+ }
+ if(numSamples == 0)
+ {
+ return ProbeFailure;
+ }
+ file.Rewind();
+ for(SAMPLEINDEX smp = 0; smp < numSamples; smp++)
+ {
+ if(file.ReadUint32BE() > 131072)
+ {
+ return ProbeFailure;
+ }
+ }
+ file.Skip(4);
+ if(!file.CanRead(2))
+ {
+ return ProbeWantMoreData;
+ }
+ uint16 speed = file.ReadUint16BE();
+ if(speed < 178)
+ {
+ return ProbeFailure;
+ }
+ if(!file.CanRead(sizeof(SFXSampleHeader) * numSamples))
+ {
+ return ProbeWantMoreData;
+ }
+ file.Skip(sizeof(SFXSampleHeader) * numSamples);
+ SFXFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
bool CSoundFile::ReadSFX(FileReader &file, ModLoadingFlags loadFlags)
//-------------------------------------------------------------------
{
@@ -164,12 +245,18 @@
}
SFXFileHeader fileHeader;
- file.ReadStruct(fileHeader);
-
- if(fileHeader.numOrders > 128)
+ if(!file.ReadStruct(fileHeader))
+ {
return false;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return false;
+ }
if(loadFlags == onlyVerifyHeader)
+ {
return true;
+ }
PATTERNINDEX numPatterns = 0;
for(ORDERINDEX ord = 0; ord < fileHeader.numOrders; ord++)
Index: soundlib/Load_stm.cpp
===================================================================
--- soundlib/Load_stm.cpp (revision 8932)
+++ soundlib/Load_stm.cpp (working copy)
@@ -94,6 +94,49 @@
MPT_BINARY_STRUCT(STMPatternData, 4*64*4)
+static bool ValidateHeader(const STMFileHeader &fileHeader)
+//---------------------------------------------------------
+{
+ if(fileHeader.filetype != 2
+ || (fileHeader.dosEof != 0x1A && fileHeader.dosEof != 2) // ST2 ignores this, ST3 doesn't. putup10.stm / putup11.stm have dosEof = 2.
+ || fileHeader.verMajor != 2
+ || fileHeader.verMinor > 21 // ST3 only accepts 0, 10, 20 and 21
+ || fileHeader.globalVolume > 64
+ || (std::memcmp(fileHeader.trackername, "!Scream!", 8)
+ && std::memcmp(fileHeader.trackername, "BMOD2STM", 8)
+ && std::memcmp(fileHeader.trackername, "WUZAMOD!", 8))
+ )
+ {
+ return false;
+ }
+ return true;
+}
+
+
+static uint64 GetHeaderMinimumAdditionalSize(const STMFileHeader &fileHeader)
+//---------------------------------------------------------------------------
+{
+ MPT_UNREFERENCED_PARAMETER(fileHeader);
+ return 31 * sizeof(STMSampleHeader) + 128;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderSTM(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ STMFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader));
+}
+
+
bool CSoundFile::ReadSTM(FileReader &file, ModLoadingFlags loadFlags)
//-------------------------------------------------------------------
{
@@ -105,20 +148,20 @@
// After reviewing all STM files on ModLand and ModArchive, it was found that the
// case-insensitive comparison is most likely not necessary for any files in the wild.
STMFileHeader fileHeader;
- if(!file.ReadStruct(fileHeader)
- || fileHeader.filetype != 2
- || (fileHeader.dosEof != 0x1A && fileHeader.dosEof != 2) // ST2 ignores this, ST3 doesn't. putup10.stm / putup11.stm have dosEof = 2.
- || fileHeader.verMajor != 2
- || fileHeader.verMinor > 21 // ST3 only accepts 0, 10, 20 and 21
- || fileHeader.globalVolume > 64
- || (memcmp(fileHeader.trackername, "!Scream!", 8)
- && memcmp(fileHeader.trackername, "BMOD2STM", 8)
- && memcmp(fileHeader.trackername, "WUZAMOD!", 8))
- || !file.CanRead(31 * sizeof(STMSampleHeader) + 128))
+ if(!file.ReadStruct(fileHeader))
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ if(!ValidateHeader(fileHeader))
{
+ return false;
+ }
+ if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(fileHeader))))
+ {
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
Index: soundlib/Load_stp.cpp
===================================================================
--- soundlib/Load_stp.cpp (revision 8932)
+++ soundlib/Load_stp.cpp (working copy)
@@ -23,6 +23,7 @@
// File header (except for "STP3" magic)
struct STPFileHeader
{
+ char magic[4];
uint16be version;
uint8be numOrders;
uint8be patternLength;
@@ -38,7 +39,7 @@
uint16be sampleStructSize;
};
-MPT_BINARY_STRUCT(STPFileHeader, 200);
+MPT_BINARY_STRUCT(STPFileHeader, 204);
// Sample header (common part between all versions)
@@ -203,24 +204,57 @@
}
-bool CSoundFile::ReadSTP(FileReader &file, ModLoadingFlags loadFlags)
-//-------------------------------------------------------------------
+static bool ValidateHeader(const STPFileHeader &fileHeader)
+//---------------------------------------------------------
{
- file.Rewind();
- if(!file.ReadMagic("STP3"))
- return false;
-
- STPFileHeader fileHeader;
- if(!file.ReadStruct(fileHeader)
+ if(std::memcmp(fileHeader.magic, "STP3", 4)
|| fileHeader.version > 2
|| fileHeader.numOrders > 128
|| fileHeader.numSamples >= MAX_SAMPLES
|| fileHeader.timerCount == 0
|| fileHeader.midiCount != 50)
+ {
return false;
+ }
+ return true;
+}
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderSTP(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ STPFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
+bool CSoundFile::ReadSTP(FileReader &file, ModLoadingFlags loadFlags)
+//-------------------------------------------------------------------
+{
+ file.Rewind();
+
+ STPFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return false;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return false;
+ }
if(loadFlags == onlyVerifyHeader)
+ {
return true;
+ }
InitializeGlobals(MOD_TYPE_STP);
Index: soundlib/Load_ult.cpp
===================================================================
--- soundlib/Load_ult.cpp (revision 8932)
+++ soundlib/Load_ult.cpp (working copy)
@@ -336,21 +336,53 @@
};
+static bool ValidateHeader(const UltFileHeader &fileHeader)
+//---------------------------------------------------------
+{
+ if(fileHeader.version < '1'
+ || fileHeader.version > '4'
+ || std::memcmp(fileHeader.signature, "MAS_UTrack_V00", sizeof(fileHeader.signature))
+ )
+ {
+ return false;
+ }
+ return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderULT(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ UltFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
bool CSoundFile::ReadUlt(FileReader &file, ModLoadingFlags loadFlags)
//-------------------------------------------------------------------
{
file.Rewind();
+
UltFileHeader fileHeader;
-
- // Tracker ID
- if(!file.ReadStruct(fileHeader)
- || fileHeader.version < '1'
- || fileHeader.version > '4'
- || memcmp(fileHeader.signature, "MAS_UTrack_V00", sizeof(fileHeader.signature)) != 0)
+ if(!file.ReadStruct(fileHeader))
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ if(!ValidateHeader(fileHeader))
{
+ return false;
+ }
+ if(loadFlags == onlyVerifyHeader)
+ {
return true;
}
Index: soundlib/Load_xm.cpp
===================================================================
--- soundlib/Load_xm.cpp (revision 8932)
+++ soundlib/Load_xm.cpp (working copy)
@@ -262,6 +262,43 @@
DECLARE_FLAGSET(TrackerVersions)
+static bool ValidateHeader(const XMFileHeader &fileHeader)
+//--------------------------------------------------------
+{
+ if(fileHeader.channels == 0
+ || fileHeader.channels > MAX_BASECHANNELS
+ || std::memcmp(fileHeader.signature, "Extended Module: ", 17)
+ )
+ {
+ return false;
+ }
+ return true;
+}
+
+
+static uint64 GetHeaderMinimumAdditionalSize(const XMFileHeader &fileHeader)
+//--------------------------------------------------------------------------
+{
+ return fileHeader.orders + 4 * (fileHeader.patterns + fileHeader.instruments);
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderXM(MemoryFileReader file, const uint64 *pfilesize)
+//---------------------------------------------------------------------------------------------------
+{
+ XMFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader));
+}
+
+
bool CSoundFile::ReadXM(FileReader &file, ModLoadingFlags loadFlags)
//------------------------------------------------------------------
{
@@ -268,13 +305,17 @@
file.Rewind();
XMFileHeader fileHeader;
- if(!file.ReadStruct(fileHeader)
- || fileHeader.channels == 0
- || fileHeader.channels > MAX_BASECHANNELS
- || memcmp(fileHeader.signature, "Extended Module: ", 17)
- || !file.CanRead(fileHeader.orders + 4 * (fileHeader.patterns + fileHeader.instruments)))
+ if(!file.ReadStruct(fileHeader))
{
return false;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return false;
+ }
+ if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(fileHeader))))
+ {
+ return false;
} else if(loadFlags == onlyVerifyHeader)
{
return true;
Index: soundlib/Sndfile.cpp
===================================================================
--- soundlib/Sndfile.cpp (revision 8932)
+++ soundlib/Sndfile.cpp (working copy)
@@ -211,12 +211,141 @@
}
+CSoundFile::ProbeResult CSoundFile::ProbeAdditionalSize(MemoryFileReader &file, const uint64 *pfilesize, uint64 minimumAdditionalSize)
+//------------------------------------------------------------------------------------------------------------------------------------
+{
+ const uint64 availableFileSize = file.GetLength();
+ const uint64 fileSize = (pfilesize ? *pfilesize : file.GetLength());
+ //const uint64 validFileSize = std::min<uint64>(fileSize, ProbeRecommendedSize);
+ const uint64 goalSize = file.GetPosition() + minimumAdditionalSize;
+ //const uint64 goalMinimumSize = std::min<uint64>(goalSize, ProbeRecommendedSize);
+ if(pfilesize)
+ {
+ if(availableFileSize < std::min<uint64>(fileSize, ProbeRecommendedSize))
+ {
+ if(availableFileSize < goalSize)
+ {
+ return ProbeWantMoreData;
+ }
+ } else
+ {
+ if(fileSize < goalSize)
+ {
+ return ProbeFailure;
+ }
+ }
+ return ProbeSuccess;
+ }
+#if 0
+ if(!pfilesize)
+ {
+ if(fileSize < goalSize && fileSize < ProbeRecommendedSize)
+ {
+ return ProbeWantMoreData;
+ }
+ return ProbeSuccess;
+ }
+#else
+ return ProbeSuccess;
+#endif
+}
+
+
const std::size_t CSoundFile::ProbeRecommendedSize = PROBE_RECOMMENDED_SIZE;
+#define MPT_DO_PROBE( storedResult , call ) \
+ MPT_DO { \
+ ProbeResult lastResult = call ; \
+ if(lastResult == ProbeSuccess) { \
+ return ProbeSuccess; \
+ } else if(lastResult == ProbeWantMoreData) { \
+ storedResult = ProbeWantMoreData; \
+ } \
+ } MPT_WHILE_0 \
+/**/
+
+
CSoundFile::ProbeResult CSoundFile::Probe(ProbeFlags flags, mpt::span<const mpt::byte> data, const uint64 *pfilesize)
//-------------------------------------------------------------------------------------------------------------------
{
+#if 1
+ ProbeResult result = ProbeFailure;
+ if(pfilesize && (*pfilesize < data.size()))
+ {
+ throw std::out_of_range("");
+ }
+ if(!data.data())
+ {
+ throw std::invalid_argument("");
+ }
+ MemoryFileReader file(data);
+ if(flags & ProbeContainers)
+ {
+ MPT_DO_PROBE(result, ProbeFileHeaderMMCMP(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderPP20(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderUMX(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderXPK(file, pfilesize));
+ }
+ if(flags & ProbeModules)
+ {
+ MPT_DO_PROBE(result, ProbeFileHeader669(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderAM(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderAMF_Asylum(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderAMF_DSMI(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderAMS(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderAMS2(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderDBM(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderDTM(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderDIGI(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderDMF(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderDSM(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderFAR(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderGDM(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderICE(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderIMF(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderIT(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderITP(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderJ2B(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderM15(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderMDL(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderMED(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderMO3(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderMOD(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderMT2(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderMTM(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderOKT(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderPLM(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderPSM(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderPSM16(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderPT36(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderPTM(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderS3M(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderSFX(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderSTM(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderSTP(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderULT(file, pfilesize));
+ MPT_DO_PROBE(result, ProbeFileHeaderXM(file, pfilesize));
+ }
+ if(pfilesize)
+ {
+ if((result == ProbeWantMoreData) && (mpt::saturate_cast<std::size_t>(*pfilesize) <= data.size()))
+ {
+ // If the prober wants more data but we already reached EOF,
+ // probing must fail.
+ result = ProbeFailure;
+ }
+ } else
+ {
+ if((result == ProbeWantMoreData) && (data.size() >= ProbeRecommendedSize))
+ {
+ // If the prober wants more daat but we already provided the recommended required maximum,
+ // just return success as this is th ebest we can do for the suggestesd probing size.
+ result = ProbeSuccess;
+ }
+ }
+ return result;
+#else
uint64 filesize = 0;
if(pfilesize)
{
@@ -257,6 +386,7 @@
}
sndFile->Destroy();
return ProbeSuccess;
+#endif
}
Index: soundlib/Sndfile.h
===================================================================
--- soundlib/Sndfile.h (revision 8932)
+++ soundlib/Sndfile.h (working copy)
@@ -581,6 +581,8 @@
ProbeWantMoreData = -1
};
+ static ProbeResult ProbeAdditionalSize(MemoryFileReader &file, const uint64 *pfilesize, uint64 minimumAdditionalSize);
+
static ProbeResult Probe(ProbeFlags flags, mpt::span<const mpt::byte> data, const uint64 *pfilesize);
public:
@@ -672,6 +674,49 @@
bool InitChannel(CHANNELINDEX nChn);
void InitAmigaResampler();
+ static ProbeResult ProbeFileHeaderMMCMP(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderPP20(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderUMX(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderXPK(MemoryFileReader file, const uint64 *pfilesize);
+
+ static ProbeResult ProbeFileHeader669(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderAM(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderAMF_Asylum(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderAMF_DSMI(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderAMS(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderAMS2(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderDBM(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderDTM(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderDIGI(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderDMF(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderDSM(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderFAR(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderGDM(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderICE(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderIMF(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderIT(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderITP(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderJ2B(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderM15(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderMDL(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderMED(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderMO3(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderMOD(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderMT2(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderMTM(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderOKT(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderPLM(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderPSM(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderPSM16(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderPT36(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderPTM(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderS3M(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderSFX(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderSTM(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderSTP(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderULT(MemoryFileReader file, const uint64 *pfilesize);
+ static ProbeResult ProbeFileHeaderXM(MemoryFileReader file, const uint64 *pfilesize);
+
// Module Loaders
bool Read669(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadAM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
@@ -694,7 +739,6 @@
bool ReadM15(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadMDL(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadMed(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
- bool ReadMID(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadMO3(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadMod(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadMT2(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
@@ -710,9 +754,11 @@
bool ReadSTM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadSTP(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadUlt(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
+ bool ReadXM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
+
+ bool ReadMID(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadUAX(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadWav(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
- bool ReadXM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
static std::vector<const char *> GetSupportedExtensions(bool otherFormats);
static bool IsExtensionSupported(const char *ext); // UTF8, casing of ext is ignored
Index: soundlib/UMXTools.cpp
===================================================================
--- soundlib/UMXTools.cpp (revision 8932)
+++ soundlib/UMXTools.cpp (working copy)
@@ -17,8 +17,9 @@
// Read compressed unreal integers - similar to MIDI integers, but signed values are possible.
-int32 ReadUMXIndex(FileReader &chunk)
-//-----------------------------------
+template <typename Tfile>
+static int32 ReadUMXIndexImpl(Tfile &chunk)
+//-----------------------------------------
{
enum
{
@@ -55,10 +56,17 @@
return result;
}
+int32 ReadUMXIndex(FileReader &chunk)
+//-----------------------------------
+{
+ return ReadUMXIndexImpl(chunk);
+}
+
// Returns true if the given nme exists in the name table.
-bool FindUMXNameTableEntry(FileReader &file, const UMXFileHeader &fileHeader, const char *name)
-//---------------------------------------------------------------------------------------------
+template <typename TFile>
+static bool FindUMXNameTableEntryImpl(TFile &file, const UMXFileHeader &fileHeader, const char *name)
+//---------------------------------------------------------------------------------------------------
{
if(!name)
{
@@ -77,7 +85,7 @@
{
if(fileHeader.packageVersion >= 64)
{
- int32 length = ReadUMXIndex(file);
+ int32 length = ReadUMXIndexImpl(file);
if(length <= 0)
{
continue;
@@ -110,7 +118,19 @@
return result;
}
+bool FindUMXNameTableEntry(FileReader &file, const UMXFileHeader &fileHeader, const char *name)
+//---------------------------------------------------------------------------------------------
+{
+ return FindUMXNameTableEntryImpl(file, fileHeader, name);
+}
+bool FindUMXNameTableEntryMemory(MemoryFileReader &file, const UMXFileHeader &fileHeader, const char *name)
+//---------------------------------------------------------------------------------------------------------
+{
+ return FindUMXNameTableEntryImpl(file, fileHeader, name);
+}
+
+
// Read an entry from the name table.
std::string ReadUMXNameTableEntry(FileReader &chunk, uint16 packageVersion)
//-------------------------------------------------------------------------
Index: soundlib/UMXTools.h
===================================================================
--- soundlib/UMXTools.h (revision 8932)
+++ soundlib/UMXTools.h (working copy)
@@ -38,6 +38,9 @@
// Returns true if the given nme exists in the name table.
bool FindUMXNameTableEntry(FileReader &file, const UMXFileHeader &fileHeader, const char *name);
+// Returns true if the given nme exists in the name table.
+bool FindUMXNameTableEntryMemory(MemoryFileReader &file, const UMXFileHeader &fileHeader, const char *name);
+
// Read an entry from the name table.
std::string ReadUMXNameTableEntry(FileReader &chunk, uint16 packageVersion);
Index: soundlib/load_j2b.cpp
===================================================================
--- soundlib/load_j2b.cpp (revision 8932)
+++ soundlib/load_j2b.cpp (working copy)
@@ -615,6 +615,66 @@
}
+struct AMFFRiffChunkFormat
+{
+ uint32le format;
+};
+
+MPT_BINARY_STRUCT(AMFFRiffChunkFormat, 4)
+
+
+static bool ValidateHeader(const AMFFRiffChunk &fileHeader)
+//---------------------------------------------------------
+{
+ if(fileHeader.id != AMFFRiffChunk::idRIFF)
+ {
+ return false;
+ }
+ if(fileHeader.GetLength() < 8 + sizeof(AMFFMainChunk))
+ {
+ return false;
+ }
+ return true;
+}
+
+
+static bool ValidateHeader(const AMFFRiffChunkFormat &formatHeader)
+//-----------------------------------------------------------------
+{
+ if(formatHeader.format != AMFFRiffChunk::idAMFF || formatHeader.format != AMFFRiffChunk::idAM__)
+ {
+ return false;
+ }
+ return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderAM(MemoryFileReader file, const uint64 *pfilesize)
+//---------------------------------------------------------------------------------------------------
+{
+ AMFFRiffChunk fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ AMFFRiffChunkFormat formatHeader;
+ if(!file.ReadStruct(formatHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(formatHeader))
+ {
+ return ProbeFailure;
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
bool CSoundFile::ReadAM(FileReader &file, ModLoadingFlags loadFlags)
//------------------------------------------------------------------
{
@@ -624,15 +684,23 @@
{
return false;
}
-
- if(fileHeader.id != AMFFRiffChunk::idRIFF)
+ if(!ValidateHeader(fileHeader))
{
return false;
}
+ AMFFRiffChunkFormat formatHeader;
+ if(!file.ReadStruct(formatHeader))
+ {
+ return false;
+ }
+ if(!ValidateHeader(formatHeader))
+ {
+ return false;
+ }
bool isAM; // false: AMFF, true: AM
- uint32 format = file.ReadUint32LE();
+ uint32 format = formatHeader.format;
if(format == AMFFRiffChunk::idAMFF)
isAM = false; // "AMFF"
else if(format == AMFFRiffChunk::idAM__)
@@ -877,6 +945,64 @@
return true;
}
+
+static bool ValidateHeader(const J2BFileHeader &fileHeader)
+//---------------------------------------------------------
+{
+ if(std::memcmp(fileHeader.signature, "MUSE", 4)
+ || (fileHeader.deadbeaf != J2BFileHeader::magicDEADBEAF // 0xDEADBEAF (RIFF AM)
+ && fileHeader.deadbeaf != J2BFileHeader::magicDEADBABE) // 0xDEADBABE (RIFF AMFF)
+ )
+ {
+ return false;
+ }
+ if(fileHeader.packedLength == 0)
+ {
+ return false;
+ }
+ if(fileHeader.fileLength != fileHeader.packedLength + sizeof(J2BFileHeader))
+ {
+ return false;
+ }
+ return true;
+}
+
+
+static bool ValidateHeaderFileSize(const J2BFileHeader &fileHeader, uint64 filesize)
+//----------------------------------------------------------------------------------
+{
+ if(filesize != fileHeader.fileLength)
+ {
+ return false;
+ }
+ return true;
+}
+
+
+CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderJ2B(MemoryFileReader file, const uint64 *pfilesize)
+//----------------------------------------------------------------------------------------------------
+{
+ J2BFileHeader fileHeader;
+ if(!file.ReadStruct(fileHeader))
+ {
+ return ProbeWantMoreData;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return ProbeFailure;
+ }
+ if(pfilesize)
+ {
+ if(!ValidateHeaderFileSize(fileHeader, *pfilesize))
+ {
+ return ProbeFailure;
+ }
+ }
+ MPT_UNREFERENCED_PARAMETER(pfilesize);
+ return ProbeSuccess;
+}
+
+
bool CSoundFile::ReadJ2B(FileReader &file, ModLoadingFlags loadFlags)
//-------------------------------------------------------------------
{
@@ -891,17 +1017,21 @@
file.Rewind();
J2BFileHeader fileHeader;
- if(!file.ReadStruct(fileHeader)
- || memcmp(fileHeader.signature, "MUSE", 4)
- || (fileHeader.deadbeaf != J2BFileHeader::magicDEADBEAF // 0xDEADBEAF (RIFF AM)
- && fileHeader.deadbeaf != J2BFileHeader::magicDEADBABE) // 0xDEADBABE (RIFF AMFF)
- || fileHeader.fileLength != file.GetLength()
+ if(!file.ReadStruct(fileHeader))
+ {
+ return false;
+ }
+ if(!ValidateHeader(fileHeader))
+ {
+ return false;
+ }
+ if(fileHeader.fileLength != file.GetLength()
|| fileHeader.packedLength != file.BytesLeft()
- || fileHeader.packedLength == 0
)
{
return false;
- } else if(loadFlags == onlyVerifyHeader)
+ }
+ if(loadFlags == onlyVerifyHeader)
{
return true;
}
| ||||
| Has the bug occurred in previous versions? | |||||
| Tested code revision (in case you know it) | |||||
| Date Modified | Username | Field | Change |
|---|---|---|---|
| 2017-01-24 10:39 | manx | New Issue | |
| 2017-01-24 10:39 | manx | Status | new => assigned |
| 2017-01-24 10:39 | manx | Assigned To | => manx |
| 2017-05-24 10:21 | manx | Target Version | OpenMPT 1.?? (libopenmpt 1.0) (goals) => OpenMPT 1.27.01.00 / libopenmpt 0.3.1 (upgrade first) |
| 2017-09-17 09:28 | manx | File Added: probe-refactor-v11.patch | |
| 2017-09-17 09:34 | manx | Relationship added | related to 0000575 |
| 2017-09-20 08:43 | manx | File Added: probe-refactor-v18.patch | |
| 2017-09-21 06:38 | manx | File Added: probe-refactor-v19.patch | |
| 2017-09-21 06:44 | manx | Status | assigned => resolved |
| 2017-09-21 06:44 | manx | Resolution | open => fixed |
| 2017-09-21 06:44 | manx | Fixed in Version | => OpenMPT 1.27.01.00 / libopenmpt 0.3.1 (upgrade first) |
| 2017-09-21 06:44 | manx | Note Added: 0003224 |