From: <rel...@us...> - 2009-06-12 17:32:32
|
Revision: 268 http://modplug.svn.sourceforge.net/modplug/?rev=268&view=rev Author: relabsoluness Date: 2009-06-12 17:32:08 +0000 (Fri, 12 Jun 2009) Log Message: ----------- ? Added validations to song/instrument extension reading and refactored related code. (merged from rev. 267) Modified Paths: -------------- trunk/OpenMPT/mptrack/misc_util.h trunk/OpenMPT/soundlib/Load_it.cpp trunk/OpenMPT/soundlib/Load_xm.cpp trunk/OpenMPT/soundlib/Sampleio.cpp trunk/OpenMPT/soundlib/Sndfile.h Modified: trunk/OpenMPT/mptrack/misc_util.h =================================================================== --- trunk/OpenMPT/mptrack/misc_util.h 2009-06-12 16:25:54 UTC (rev 267) +++ trunk/OpenMPT/mptrack/misc_util.h 2009-06-12 17:32:08 UTC (rev 268) @@ -42,10 +42,34 @@ // Size of the array must be known at compile time. template <size_t size> inline void SetNullTerminator(char (&buffer)[size]) +//------------------------------------------------- { STATIC_ASSERT(size > 0); buffer[size-1] = 0; } +// Limits 'val' to given range. If 'val' is less than 'lowerLimit', 'val' is set to value 'lowerLimit'. +// Similarly if 'val' is greater than 'upperLimit', 'val' is set to value 'upperLimit'. +// If 'lowerLimit' > 'upperLimit', 'val' won't be modified. +template<class T, class C> +inline void Limit(T& val, const C lowerLimit, const C upperLimit) +//--------------------------------------------------------------- +{ + if(lowerLimit > upperLimit) return; + if(val < lowerLimit) val = lowerLimit; + else if(val > upperLimit) val = upperLimit; +} + + +// Like Limit, but with upperlimit only. +template<class T, class C> +inline void LimitMax(T& val, const C upperLimit) +//---------------------------------------------- +{ + if(val > upperLimit) + val = upperLimit; +} + + #endif Modified: trunk/OpenMPT/soundlib/Load_it.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_it.cpp 2009-06-12 16:25:54 UTC (rev 267) +++ trunk/OpenMPT/soundlib/Load_it.cpp 2009-06-12 17:32:08 UTC (rev 268) @@ -847,8 +847,7 @@ // Extra info data __int32 fcode = 0; - __int16 fsize = 0; - BYTE * ptr = (BYTE *)(lpStream + streamPos); + LPCBYTE ptr = lpStream + min(streamPos, dwMemLength); if (streamPos <= dwMemLength - 4) { fcode = (*((__int32 *)ptr)); @@ -863,7 +862,7 @@ i = 1; // parse file - while( ptr + 4 <= (BYTE *)(lpStream + dwMemLength) && i <= m_nInstruments ){ + while( uintptr_t(ptr - lpStream) <= dwMemLength - 4 && i <= m_nInstruments ){ fcode = (*((__int32 *)ptr)); // read field code @@ -876,16 +875,7 @@ default: ptr += sizeof(__int32); // jump field code - if(ptr + 2 > (BYTE *)(lpStream + dwMemLength)) return FALSE; - fsize = (*((__int16 *)ptr)); // read field size - ptr += sizeof(__int16); // jump field size - BYTE * fadr = GetInstrumentHeaderFieldPointer(Headers[i], fcode, fsize); - if(fadr && fcode != 'K[..') // copy field data in instrument's header - { - if(ptr + fsize > (BYTE *)(lpStream + dwMemLength)) return FALSE; - memcpy(fadr,ptr,fsize); // (except for keyboard mapping) - } - ptr += fsize; // jump field + ReadExtendedInstrumentProperty(Headers[i], fcode, ptr, lpStream + dwMemLength); break; } } @@ -893,7 +883,7 @@ //HACK: if we fail on i <= m_nInstruments above, arrive here without having set fcode as appropriate, // hence the code duplication. - if (ptr + 4 <= (BYTE *)(lpStream + dwMemLength)) { + if ( (uintptr_t)(ptr - lpStream) <= dwMemLength - 4 ) { fcode = (*((__int32 *)ptr)); } @@ -1320,55 +1310,18 @@ ITSAMPLESTRUCT *pis = (ITSAMPLESTRUCT *)(lpStream+smppos[pifh->smpnum-1]); dwMemPos = pis->samplepointer + lastSampleSize; - // Get file pointer to match the first byte of extra settings informations __int16 size = 0; - __int32 code = 0; - __int16 size = 0; - BYTE * ptr = NULL; - if(dwMemPos < dwMemLength) { - ptr = (BYTE *)(lpStream + dwMemPos); - code = (*((__int32 *)ptr));; + // Load instrument and song extensions. + if(mptStartPos >= dwMemPos) + { + LPCBYTE ptr = LoadExtendedInstrumentProperties(lpStream + dwMemPos, lpStream + mptStartPos, &interpretModplugmade); + LoadExtendedSongProperties(GetType(), ptr, lpStream, mptStartPos, &interpretModplugmade); } - - // Instrument extensions - if( code == 'MPTX' ){ - interpretModplugmade = true; - ptr += sizeof(__int32); // jump extension header code - while( (DWORD)(ptr - lpStream) < mptStartPos ){ //Loop 'till beginning of end of file/mpt specific looking for inst. extensions - code = (*((__int32 *)ptr)); // read field code - if (code == 'MPTS') { //Reached song extensions, break out of this loop - break; - } - - ptr += sizeof(__int32); // jump field code - size = (*((__int16 *)ptr)); // read field size - ptr += sizeof(__int16); // jump field size - - for(UINT nins=1; nins<=m_nInstruments; nins++){ - if(Headers[nins]){ - // get field's adress in instrument's header - BYTE * fadr = GetInstrumentHeaderFieldPointer(Headers[nins], code, size); - // copy field data in instrument's header (except for keyboard mapping) - if(fadr && code != 'K[..') memcpy(fadr,ptr,size); - // jump field - ptr += size; - } - } - //end rewbs.instroVSTi - } - } // -! NEW_FEATURE#0027 - // Song extensions - if( code == 'MPTS' ) - { - interpretModplugmade = true; - LoadExtendedSongProperties(GetType(), ptr, lpStream, mptStartPos); - } + // Reading Patterns Patterns.ResizeArray(max(MAX_PATTERNS, npatterns)); - - // Reading Patterns for (UINT npat=0; npat<npatterns; npat++) { if ((!patpos[npat]) || ((DWORD)patpos[npat] >= dwMemLength - 4)) @@ -3691,47 +3644,124 @@ return; } +LPCBYTE CSoundFile::LoadExtendedInstrumentProperties(const LPCBYTE pStart, + const LPCBYTE pEnd, + bool* pInterpretMptMade) +//--------------------------------------------------------------------------- +{ + if( pStart == NULL || pEnd <= pStart || uintptr_t(pEnd - pStart) < 4) + return NULL; -void CSoundFile::LoadExtendedSongProperties(const MODTYPE modtype, BYTE*& ptr, const LPCBYTE lpStream, const size_t searchlimit) -//-------------------------------------------------- + int32 code = 0; + int16 size = 0; + LPCBYTE ptr = pStart; + + memcpy(&code, ptr, sizeof(code)); + + if(code != 'MPTX') + return NULL; + + // Found MPTX, interpret the file MPT made. + if(pInterpretMptMade != NULL) + *pInterpretMptMade = true; + + ptr += sizeof(int32); // jump extension header code + while( ptr < pEnd && uintptr_t(pEnd-ptr) >= 4) //Loop 'till beginning of end of file/mpt specific looking for inst. extensions + { + memcpy(&code, ptr, sizeof(code)); // read field code + if (code == 'MPTS') //Reached song extensions, break out of this loop + return ptr; + + ptr += sizeof(code); // jump field code + + if((uintptr_t)(pEnd - ptr) < 2) + return NULL; + + memcpy(&size, ptr, sizeof(size)); // read field size + ptr += sizeof(size); // jump field size + + if(IsValidSizeField(ptr, pEnd, size) == false) + return NULL; + + for(UINT nins=1; nins<=m_nInstruments; nins++) + { + if(Headers[nins]) + ReadInstrumentExtensionField(Headers[nins], ptr, code, size); + } + } + + return NULL; +} + + +void CSoundFile::LoadExtendedSongProperties(const MODTYPE modtype, + LPCBYTE ptr, + const LPCBYTE lpStream, + const size_t searchlimit, + bool* pInterpretMptMade) +//------------------------------------------------------------------- { + if(searchlimit < 6 || ptr == NULL || ptr < lpStream || uintptr_t(ptr - lpStream) > searchlimit - 4) + return; + + const LPCBYTE pEnd = lpStream + searchlimit; + int32 code = 0; int16 size = 0; - ptr += sizeof(int32); // jump extension header code - while( (DWORD)((ptr + 6) - lpStream) <= searchlimit ) //Loop until given limit. + + memcpy(&code, ptr, sizeof(code)); + + if(code != 'MPTS') + return; + + // Found MPTS, interpret the file MPT made. + if(pInterpretMptMade != NULL) + *pInterpretMptMade = true; + + + // Case macros. + #define CASE(id, data) \ + case id: fadr = reinterpret_cast<BYTE*>(&data); nMaxReadCount = min(size, sizeof(data)); break; + #define CASE_NOTXM(id, data) \ + case id: if(modtype != MOD_TYPE_XM) {fadr = reinterpret_cast<BYTE*>(&data); nMaxReadCount = min(size, sizeof(data));} break; + + ptr += sizeof(code); // jump extension header code + while( uintptr_t(ptr - lpStream) <= searchlimit-6 ) //Loop until given limit. { - code = (*((__int32 *)ptr)); // read field code - ptr += sizeof(__int32); // jump field code - size = (*((__int16 *)ptr)); // read field size - if(size < 0) break; - ptr += sizeof(__int16); // jump field size + code = (*((int32 *)ptr)); // read field code + ptr += sizeof(int32); // jump field code + size = (*((int16 *)ptr)); // read field size + ptr += sizeof(int16); // jump field size + if(IsValidSizeField(ptr, pEnd, size) == false) + break; + + size_t nMaxReadCount = 0; BYTE * fadr = NULL; - switch (code) { // interpret field code - case 'DT..': fadr = reinterpret_cast<BYTE*>(&m_nDefaultTempo); break; - case 'RPB.': fadr = reinterpret_cast<BYTE*>(&m_nRowsPerBeat); break; - case 'RPM.': fadr = reinterpret_cast<BYTE*>(&m_nRowsPerMeasure); break; - case 'C...': if(modtype != MOD_TYPE_XM) fadr = reinterpret_cast<BYTE*>(&m_nChannels); break; - case 'TM..': fadr = reinterpret_cast<BYTE*>(&m_nTempoMode); break; - case 'PMM.': fadr = reinterpret_cast<BYTE*>(&m_nMixLevels); break; - case 'CWV.': fadr = reinterpret_cast<BYTE*>(&m_dwCreatedWithVersion); break; - case 'LSWV': fadr = reinterpret_cast<BYTE*>(&m_dwLastSavedWithVersion); break; - case 'SPA.': fadr = reinterpret_cast<BYTE*>(&m_nSamplePreAmp); break; - case 'VSTV': fadr = reinterpret_cast<BYTE*>(&m_nVSTiVolume); break; - case 'DGV.': fadr = reinterpret_cast<BYTE*>(&m_nDefaultGlobalVolume); break; - case 'RP..': if(modtype != MOD_TYPE_XM) fadr = reinterpret_cast<BYTE*>(&m_nRestartPos); break; - case 'MSF.': fadr = reinterpret_cast<BYTE*>(&m_ModFlags); break; - case 'MIMA': - if(DWORD(ptr - lpStream + DWORD(size)) > searchlimit) - MessageBox(NULL, "Error: Bad MIMA datasizefield", NULL, MB_ICONERROR); - else - GetMIDIMapper().Unserialize(ptr, size); - break; + + switch (code) // interpret field code + { + CASE('DT..', m_nDefaultTempo); + CASE('RPB.', m_nRowsPerBeat); + CASE('RPM.', m_nRowsPerMeasure); + CASE_NOTXM('C...', m_nChannels); + CASE('TM..', m_nTempoMode); + CASE('PMM.', m_nMixLevels); + CASE('CWV.', m_dwCreatedWithVersion); + CASE('LSWV', m_dwLastSavedWithVersion); + CASE('SPA.', m_nSamplePreAmp); + CASE('VSTV', m_nVSTiVolume); + CASE('DGV.', m_nDefaultGlobalVolume); + CASE_NOTXM('RP..', m_nRestartPos); + CASE('MSF.', m_ModFlags); + case 'MIMA': GetMIDIMapper().Unserialize(ptr, size); break; case 'ChnS': - if( ((ptr - lpStream) + DWORD(size) <= searchlimit) && (size <= 63*2) && (size % 2 == 0) ) + if( (size <= 63*2) && (size % 2 == 0) ) { const BYTE* pData = ptr; - for(__int16 i = 0; i<size/2; i++, pData += 2) if(pData[0] != 0xFF) + STATIC_ASSERT(ARRAYELEMCOUNT(ChnSettings) >= 64); + const __int16 nLoopLimit = min(size/2, ARRAYELEMCOUNT(ChnSettings) - 64); + for(__int16 i = 0; i<nLoopLimit; i++, pData += 2) if(pData[0] != 0xFF) { ChnSettings[i+64].nVolume = pData[1]; ChnSettings[i+64].nPan = 128; @@ -3745,11 +3775,30 @@ break; } - if (fadr != NULL && (ptr - lpStream) + DWORD(size) <= searchlimit) { // if field code recognized - memcpy(fadr,ptr,size); // read field data - } + if (fadr != NULL) // if field code recognized + memcpy(fadr,ptr,nMaxReadCount); // read field data + ptr += size; // jump field data } + + // Validate read values. + Limit(m_nDefaultTempo, GetModSpecifications().tempoMin, GetModSpecifications().tempoMax); + //m_nRowsPerBeat + //m_nRowsPerMeasure + LimitMax(m_nChannels, GetModSpecifications().channelsMax); + //m_nTempoMode + //m_nMixLevels + //m_dwCreatedWithVersion + //m_dwLastSavedWithVersion + //m_nSamplePreAmp + //m_nVSTiVolume + //m_nDefaultGlobalVolume); + //m_nRestartPos + //m_ModFlags + + + #undef CASE + #undef CASE_NOTXM } Modified: trunk/OpenMPT/soundlib/Load_xm.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_xm.cpp 2009-06-12 16:25:54 UTC (rev 267) +++ trunk/OpenMPT/soundlib/Load_xm.cpp 2009-06-12 17:32:08 UTC (rev 268) @@ -611,54 +611,16 @@ // Leave if no extra instrument settings are available (end of file reached) if(dwMemPos >= dwMemLength) return TRUE; - // Get file pointer to match the first byte of extra settings informations - BYTE * ptr = (BYTE *)(lpStream + dwMemPos); + bool bInterpretMptMade = false; + LPCBYTE ptr = lpStream + dwMemPos; + if(m_nInstruments) + ptr = LoadExtendedInstrumentProperties(ptr, lpStream+dwMemLength, &bInterpretMptMade); - // Seek for supported extended settings header - __int16 size = 0; - __int32 code = (*((__int32 *)ptr)); + LoadExtendedSongProperties(GetType(), ptr, lpStream, dwMemLength, &bInterpretMptMade); - // Instrument extensions - if( code == 'MPTX' && m_nInstruments ){ - ptr += sizeof(__int32); // jump extension header code - while( (DWORD)(ptr - lpStream) < dwMemLength ){ //Loop 'till end of file looking for inst. extensions + if(bInterpretMptMade && m_dwLastSavedWithVersion < MAKE_VERSION_NUMERIC(1, 17, 2, 50)) + SetModFlag(MSF_MIDICC_BUGEMULATION, true); - code = (*((__int32 *)ptr)); // read field code - if (code == 'MPTS') { //Reached song extensions, break out of this loop - break; - } - - ptr += sizeof(__int32); // jump field code - size = (*((__int16 *)ptr)); // read field size - ptr += sizeof(__int16); // jump field size - - for(UINT nins=1; nins<=m_nInstruments; nins++){ - if(Headers[nins]){ - // get field's adress in instrument's header - BYTE * fadr = GetInstrumentHeaderFieldPointer(Headers[nins], code, size); - // copy field data in instrument's header (except for keyboard mapping) - if(fadr && code != 'K[..') memcpy(fadr,ptr,size); - // jump field - ptr += size; - } - } - //end rewbs.instroVSTi - } - } -// -! NEW_FEATURE#0027 - - // Song extensions - if( code == 'MPTS' ) - { - LoadExtendedSongProperties(MOD_TYPE_XM, ptr, lpStream, dwMemLength); - if(m_dwLastSavedWithVersion < MAKE_VERSION_NUMERIC(1, 17, 2, 50)) - SetModFlag(MSF_MIDICC_BUGEMULATION, true); - } - - - - - return TRUE; } Modified: trunk/OpenMPT/soundlib/Sampleio.cpp =================================================================== --- trunk/OpenMPT/soundlib/Sampleio.cpp 2009-06-12 16:25:54 UTC (rev 267) +++ trunk/OpenMPT/soundlib/Sampleio.cpp 2009-06-12 17:32:08 UTC (rev 268) @@ -1297,28 +1297,8 @@ // Leave if no extra instrument settings are available (end of file reached) if(dwMemPos >= dwFileLength) return TRUE; - // Compute current file pointer position - BYTE * ptr = (BYTE *)(lpMemFile+dwMemPos); + ReadExtendedInstrumentProperties(penv, lpMemFile + dwMemPos, dwFileLength - dwMemPos); - // Seek for supported extended settings header - if( (*((__int32 *)ptr)) == 'MPTX' && penv ){ - __int16 size; - __int32 code; - ptr += sizeof(__int32); // jump extension header code - - while( (DWORD)(ptr - lpMemFile) < dwFileLength ){ - code = (*((__int32 *)ptr)); // read field code - ptr += sizeof(__int32); // jump field code - size = (*((__int16 *)ptr)); // read field size - ptr += sizeof(__int16); // jump field size - - BYTE * fadr = GetInstrumentHeaderFieldPointer(penv, code, size); - if(fadr && code != 'K[..') // copy field data in instrument's header - memcpy(fadr,ptr,size); // (except for keyboard mapping) - ptr += size; // jump field - } - } - // -! NEW_FEATURE#0027 return TRUE; @@ -1827,28 +1807,8 @@ // Leave if no extra instrument settings are available (end of file reached) if(dwMemPos >= dwFileLength) return TRUE; - // Get file pointer to match the first byte of extra settings informations - ptr = (BYTE *)(lpMemFile+dwMemPos); + ReadExtendedInstrumentProperties(penv, lpMemFile + dwMemPos, dwFileLength - dwMemPos); - // Seek for supported extended settings header - if( (*((__int32 *)ptr)) == 'MPTX' && penv ){ - __int16 size; - __int32 code; - ptr += sizeof(__int32); // jump extension header code - - while( (DWORD)(ptr - lpMemFile) < dwFileLength ){ - code = (*((__int32 *)ptr)); // read field code - ptr += sizeof(__int32); // jump field code - size = (*((__int16 *)ptr)); // read field size - ptr += sizeof(__int16); // jump field size - - BYTE * fadr = GetInstrumentHeaderFieldPointer(penv, code, size); - if(fadr && code != 'K[..') // copy field data in instrument's header - memcpy(fadr,ptr,size); // (except for keyboard mapping) - ptr += size; // jump field - } - } - // -! NEW_FEATURE#0027 return TRUE; @@ -2043,6 +2003,73 @@ } + +bool IsValidSizeField(const LPCBYTE pData, const LPCBYTE pEnd, const int16 size) +//------------------------------------------------------------------------------ +{ + if(size < 0 || (uintptr_t)(pEnd - pData) < (uintptr_t)size) + return false; + else + return true; +} + + +void ReadInstrumentExtensionField(INSTRUMENTHEADER* penv, LPCBYTE& ptr, const int32 code, const int16 size) +//------------------------------------------------------------------------------------------------------------ +{ + // get field's address in instrument's header + BYTE* fadr = GetInstrumentHeaderFieldPointer(penv, code, size); + + if(fadr && code != 'K[..') // copy field data in instrument's header + memcpy(fadr,ptr,size); // (except for keyboard mapping) + ptr += size; // jump field +} + + +void ReadExtendedInstrumentProperty(INSTRUMENTHEADER* penv, const int32 code, LPCBYTE& pData, const LPCBYTE pEnd) +//--------------------------------------------------------------------------------------------------------------- +{ + if(pEnd < pData || uintptr_t(pEnd - pData) < 2) + return; + + int16 size; + memcpy(&size, pData, sizeof(size)); // read field size + pData += sizeof(size); // jump field size + + if(IsValidSizeField(pData, pEnd, size) == false) + return; + + ReadInstrumentExtensionField(penv, pData, code, size); +} + + +void ReadExtendedInstrumentProperties(INSTRUMENTHEADER* penv, const LPCBYTE pDataStart, const size_t nMemLength) +//-------------------------------------------------------------------------------------------------------------- +{ + if(penv == 0 || pDataStart == 0 || nMemLength < 4) + return; + + LPCBYTE pData = pDataStart; + const LPCBYTE pEnd = pDataStart + nMemLength; + + int32 code; + memcpy(&code, pData, sizeof(code)); + + // Seek for supported extended settings header + if( code == 'MPTX' ) + { + pData += sizeof(code); // jump extension header code + + while( (uintptr_t)(pData - pDataStart) <= nMemLength - 4) + { + memcpy(&code, pData, sizeof(code)); // read field code + pData += sizeof(code); // jump field code + ReadExtendedInstrumentProperty(penv, code, pData, pEnd); + } + } +} + + /////////////////////////////////////////////////////////////////////////////////////////////////// // 8SVX Samples Modified: trunk/OpenMPT/soundlib/Sndfile.h =================================================================== --- trunk/OpenMPT/soundlib/Sndfile.h 2009-06-12 16:25:54 UTC (rev 267) +++ trunk/OpenMPT/soundlib/Sndfile.h 2009-06-12 17:32:08 UTC (rev 268) @@ -1086,8 +1086,13 @@ void WriteInstrumentPropertyForAllInstruments(__int32 code, __int16 size, FILE* f, INSTRUMENTHEADER* instruments[], UINT nInstruments); void SaveExtendedInstrumentProperties(INSTRUMENTHEADER *instruments[], UINT nInstruments, FILE* f); void SaveExtendedSongProperties(FILE* f); - void LoadExtendedSongProperties(const MODTYPE modtype, BYTE*& ptr, const BYTE* startpos, const size_t seachlimit); + void LoadExtendedSongProperties(const MODTYPE modtype, LPCBYTE ptr, const LPCBYTE startpos, const size_t seachlimit, bool* pInterpretMptMade = NULL); + // Reads extended instrument properties(XM/IT/MPTM). + // If no errors occur and song extension tag is found, returns pointer to the beginning + // of the tag, else returns NULL. + LPCBYTE LoadExtendedInstrumentProperties(const LPCBYTE pStart, const LPCBYTE pEnd, bool* pInterpretMptMade = NULL); + #endif // MODPLUG_NO_FILESAVE // MOD Convert function UINT GetBestSaveFormat() const; @@ -1515,4 +1520,18 @@ #endif +// Used in instrument/song extension reading to make sure the size field is valid. +bool IsValidSizeField(const LPCBYTE pData, const LPCBYTE pEnd, const int16 size); + +// Read instrument property with 'code' and 'size' from 'ptr' to instrument 'penv'. +// Note: (ptr, size) pair must be valid (e.g. can read 'size' bytes from 'ptr') +void ReadInstrumentExtensionField(INSTRUMENTHEADER* penv, LPCBYTE& ptr, const int32 code, const int16 size); + +// Read instrument property with 'code' from 'pData' to instrument 'penv'. +void ReadExtendedInstrumentProperty(INSTRUMENTHEADER* penv, const int32 code, LPCBYTE& pData, const LPCBYTE pEnd); + +// Read extended instrument properties from 'pDataStart' to instrument 'penv'. +void ReadExtendedInstrumentProperties(INSTRUMENTHEADER* penv, const LPCBYTE pDataStart, const size_t nMemLength); + + #endif This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |