From: <sag...@us...> - 2012-11-05 23:24:53
|
Revision: 1419 http://modplug.svn.sourceforge.net/modplug/?rev=1419&view=rev Author: saga-games Date: 2012-11-05 23:24:41 +0000 (Mon, 05 Nov 2012) Log Message: ----------- [Ref] Rewrote IT/ITS/ITI loaders to use FileReader classes. Rewrite a lot of related stuff as well, so many things might be broken now (despite of unit tests)! Modified Paths: -------------- trunk/OpenMPT/mptrack/MIDIMapping.cpp trunk/OpenMPT/mptrack/MIDIMapping.h trunk/OpenMPT/mptrack/View_gen.cpp trunk/OpenMPT/mptrack/test/test.cpp trunk/OpenMPT/mptrack/test/test.mptm trunk/OpenMPT/soundlib/FileReader.h trunk/OpenMPT/soundlib/ITTools.cpp trunk/OpenMPT/soundlib/ITTools.h trunk/OpenMPT/soundlib/LOAD_AMF.CPP trunk/OpenMPT/soundlib/Load_it.cpp trunk/OpenMPT/soundlib/Load_itp.cpp trunk/OpenMPT/soundlib/Load_mo3.cpp trunk/OpenMPT/soundlib/Load_umx.cpp trunk/OpenMPT/soundlib/Load_xm.cpp trunk/OpenMPT/soundlib/ModInstrument.cpp trunk/OpenMPT/soundlib/ModSample.cpp trunk/OpenMPT/soundlib/ModSequence.cpp trunk/OpenMPT/soundlib/ModSequence.h trunk/OpenMPT/soundlib/SampleFormats.cpp trunk/OpenMPT/soundlib/SampleIO.cpp trunk/OpenMPT/soundlib/SampleIO.h trunk/OpenMPT/soundlib/Sndfile.cpp trunk/OpenMPT/soundlib/Sndfile.h Modified: trunk/OpenMPT/mptrack/MIDIMapping.cpp =================================================================== --- trunk/OpenMPT/mptrack/MIDIMapping.cpp 2012-11-05 15:09:20 UTC (rev 1418) +++ trunk/OpenMPT/mptrack/MIDIMapping.cpp 2012-11-05 23:24:41 UTC (rev 1419) @@ -76,11 +76,11 @@ } -bool CMIDIMapper::Deserialize(const BYTE* ptr, const size_t size) +bool CMIDIMapper::Deserialize(const char *ptr, const size_t size) //--------------------------------------------------------------- { m_Directives.clear(); - const BYTE* endptr = ptr + size; + const char* endptr = ptr + size; while(ptr + 5 <= endptr) { uint8 i8 = 0; Modified: trunk/OpenMPT/mptrack/MIDIMapping.h =================================================================== --- trunk/OpenMPT/mptrack/MIDIMapping.h 2012-11-05 15:09:20 UTC (rev 1418) +++ trunk/OpenMPT/mptrack/MIDIMapping.h 2012-11-05 23:24:41 UTC (rev 1419) @@ -112,7 +112,7 @@ size_t GetSerializationSize() const; void Serialize(FILE* f) const; - bool Deserialize(const BYTE* ptr, const size_t size); //Return false if succesful, true otherwise. + bool Deserialize(const char *ptr, const size_t size); //Return false if succesful, true otherwise. bool AreOrderEqual(const size_t a, const size_t b) {return !(m_Directives[a] < m_Directives[b] || m_Directives[b] < m_Directives[a]);} Modified: trunk/OpenMPT/mptrack/View_gen.cpp =================================================================== --- trunk/OpenMPT/mptrack/View_gen.cpp 2012-11-05 15:09:20 UTC (rev 1418) +++ trunk/OpenMPT/mptrack/View_gen.cpp 2012-11-05 23:24:41 UTC (rev 1419) @@ -1416,31 +1416,48 @@ CModDoc *pModDoc = GetDocument(); CSoundFile* pSndFile = pModDoc->GetSoundFile(); prompt.Format("Insert empty slot before slot FX%d?", m_nCurrentPlugin + 1); - if (pSndFile->m_MixPlugins[MAX_MIXPLUGINS-1].pMixPlugin) + + // If last plugin slot is occupied, move it so that the plugin is not lost. + // This could certainly be improved... + bool moveLastPlug = false; + + if(pSndFile->m_MixPlugins[MAX_MIXPLUGINS - 1].pMixPlugin) { - prompt.Append("\nWarning: plugin data in last slot will be lost."); + if(pSndFile->m_MixPlugins[MAX_MIXPLUGINS - 2].pMixPlugin == nullptr) + { + moveLastPlug = true; + } else + { + prompt.Append("\nWarning: plugin data in last slot will be lost."); + } } - if (Reporting::Confirm(prompt) == cnfYes) + if(Reporting::Confirm(prompt) == cnfYes) { - //Delete last plug... - if (pSndFile->m_MixPlugins[MAX_MIXPLUGINS-1].pMixPlugin) + // Delete last plug... + if(pSndFile->m_MixPlugins[MAX_MIXPLUGINS - 1].pMixPlugin) { - pSndFile->m_MixPlugins[MAX_MIXPLUGINS-1].pMixPlugin->Release(); - memset(&(pSndFile->m_MixPlugins[MAX_MIXPLUGINS-1]), 0, sizeof(SNDMIXPLUGIN)); - //possible mem leak here... + if(moveLastPlug) + { + MovePlug(MAX_MIXPLUGINS - 1, MAX_MIXPLUGINS - 2, true); + } else + { + pSndFile->m_MixPlugins[MAX_MIXPLUGINS - 1].pMixPlugin->Release(); + memset(&(pSndFile->m_MixPlugins[MAX_MIXPLUGINS - 1]), 0, sizeof(SNDMIXPLUGIN)); + //possible mem leak here... + } } // Update MODCOMMANDs so that they won't be referring to old indexes (e.g. with NOTE_PC). - if (pSndFile->GetType() == MOD_TYPE_MPT) + if(pSndFile->GetType() == MOD_TYPE_MPT) pSndFile->Patterns.ForEachModCommand(PlugIndexModifier(m_nCurrentPlugin + 1, MAX_MIXPLUGINS - 1, 1)); - for (PLUGINDEX nSlot = MAX_MIXPLUGINS-1; nSlot > m_nCurrentPlugin; nSlot--) + for(PLUGINDEX nSlot = MAX_MIXPLUGINS - 1; nSlot > m_nCurrentPlugin; nSlot--) { - if (pSndFile->m_MixPlugins[nSlot-1].pMixPlugin) + if(pSndFile->m_MixPlugins[nSlot-1].pMixPlugin) { - MovePlug(nSlot-1, nSlot, NoPatternAdjust); + MovePlug(nSlot - 1, nSlot, NoPatternAdjust); } } Modified: trunk/OpenMPT/mptrack/test/test.cpp =================================================================== --- trunk/OpenMPT/mptrack/test/test.cpp 2012-11-05 15:09:20 UTC (rev 1418) +++ trunk/OpenMPT/mptrack/test/test.cpp 2012-11-05 23:24:41 UTC (rev 1419) @@ -519,7 +519,7 @@ const CSoundFile *pSndFile = pModDoc->GetSoundFile(); // Global Variables - VERIFY_EQUAL_NONCONT(strcmp(pSndFile->m_szNames[0], "Test Module"), 0); + VERIFY_EQUAL_NONCONT(strcmp(pSndFile->m_szNames[0], "Test Module_____________X"), 0); VERIFY_EQUAL_NONCONT(pSndFile->m_lpszSongComments[0], 'O'); VERIFY_EQUAL_NONCONT(pSndFile->m_nDefaultTempo, 139); VERIFY_EQUAL_NONCONT(pSndFile->m_nDefaultSpeed, 5); @@ -555,7 +555,7 @@ VERIFY_EQUAL_NONCONT(pSndFile->m_MidiCfg.GetFixedMacroType(), zxx_resomode); // Channels - VERIFY_EQUAL_NONCONT(pSndFile->GetNumChannels(), 2); + VERIFY_EQUAL_NONCONT(pSndFile->GetNumChannels(), 70); VERIFY_EQUAL_NONCONT(strcmp(pSndFile->ChnSettings[0].szName, "First Channel"), 0); VERIFY_EQUAL_NONCONT(pSndFile->ChnSettings[0].nPan, 32); VERIFY_EQUAL_NONCONT(pSndFile->ChnSettings[0].nVolume, 32); @@ -568,6 +568,11 @@ VERIFY_EQUAL_NONCONT(pSndFile->ChnSettings[1].dwFlags, CHN_SURROUND); VERIFY_EQUAL_NONCONT(pSndFile->ChnSettings[1].nMixPlugin, 1); + VERIFY_EQUAL_NONCONT(strcmp(pSndFile->ChnSettings[69].szName, "Last Channel______X"), 0); + VERIFY_EQUAL_NONCONT(pSndFile->ChnSettings[69].nPan, 256); + VERIFY_EQUAL_NONCONT(pSndFile->ChnSettings[69].nVolume, 7); + VERIFY_EQUAL_NONCONT(pSndFile->ChnSettings[69].dwFlags, 0); + VERIFY_EQUAL_NONCONT(pSndFile->ChnSettings[69].nMixPlugin, 1); // Samples VERIFY_EQUAL_NONCONT(pSndFile->GetNumSamples(), 3); { @@ -621,73 +626,75 @@ } // Instruments - VERIFY_EQUAL_NONCONT(pSndFile->GetNumInstruments(), 1); - const ModInstrument *pIns = pSndFile->Instruments[1]; - VERIFY_EQUAL_NONCONT(pIns->nGlobalVol, 32); - VERIFY_EQUAL_NONCONT(pIns->nFadeOut, 1024); - VERIFY_EQUAL_NONCONT(pIns->nPan, 64); - VERIFY_EQUAL_NONCONT(pIns->dwFlags, INS_SETPANNING); + VERIFY_EQUAL_NONCONT(pSndFile->GetNumInstruments(), 2); + for(INSTRUMENTINDEX ins = 1; ins <= 2; ins++) + { + const ModInstrument *pIns = pSndFile->Instruments[ins]; + VERIFY_EQUAL_NONCONT(pIns->nGlobalVol, 32); + VERIFY_EQUAL_NONCONT(pIns->nFadeOut, 1024); + VERIFY_EQUAL_NONCONT(pIns->nPan, 64); + VERIFY_EQUAL_NONCONT(pIns->dwFlags, INS_SETPANNING); - VERIFY_EQUAL_NONCONT(pIns->nPPS, 16); - VERIFY_EQUAL_NONCONT(pIns->nPPC, (NOTE_MIDDLEC - NOTE_MIN) + 6); // F#5 + VERIFY_EQUAL_NONCONT(pIns->nPPS, 16); + VERIFY_EQUAL_NONCONT(pIns->nPPC, (NOTE_MIDDLEC - NOTE_MIN) + 6); // F#5 - VERIFY_EQUAL_NONCONT(pIns->nVolRampUp, 1200); - VERIFY_EQUAL_NONCONT(pIns->nResampling, SRCMODE_POLYPHASE); + VERIFY_EQUAL_NONCONT(pIns->nVolRampUp, 1200); + VERIFY_EQUAL_NONCONT(pIns->nResampling, SRCMODE_POLYPHASE); - VERIFY_EQUAL_NONCONT(pIns->IsCutoffEnabled(), true); - VERIFY_EQUAL_NONCONT(pIns->GetCutoff(), 0x32); - VERIFY_EQUAL_NONCONT(pIns->IsResonanceEnabled(), true); - VERIFY_EQUAL_NONCONT(pIns->GetResonance(), 0x64); - VERIFY_EQUAL_NONCONT(pIns->nFilterMode, FLTMODE_HIGHPASS); + VERIFY_EQUAL_NONCONT(pIns->IsCutoffEnabled(), true); + VERIFY_EQUAL_NONCONT(pIns->GetCutoff(), 0x32); + VERIFY_EQUAL_NONCONT(pIns->IsResonanceEnabled(), true); + VERIFY_EQUAL_NONCONT(pIns->GetResonance(), 0x64); + VERIFY_EQUAL_NONCONT(pIns->nFilterMode, FLTMODE_HIGHPASS); - VERIFY_EQUAL_NONCONT(pIns->nVolSwing, 0x30); - VERIFY_EQUAL_NONCONT(pIns->nPanSwing, 0x18); - VERIFY_EQUAL_NONCONT(pIns->nCutSwing, 0x0C); - VERIFY_EQUAL_NONCONT(pIns->nResSwing, 0x3C); + VERIFY_EQUAL_NONCONT(pIns->nVolSwing, 0x30); + VERIFY_EQUAL_NONCONT(pIns->nPanSwing, 0x18); + VERIFY_EQUAL_NONCONT(pIns->nCutSwing, 0x0C); + VERIFY_EQUAL_NONCONT(pIns->nResSwing, 0x3C); - VERIFY_EQUAL_NONCONT(pIns->nNNA, NNA_CONTINUE); - VERIFY_EQUAL_NONCONT(pIns->nDCT, DCT_NOTE); - VERIFY_EQUAL_NONCONT(pIns->nDNA, DNA_NOTEFADE); + VERIFY_EQUAL_NONCONT(pIns->nNNA, NNA_CONTINUE); + VERIFY_EQUAL_NONCONT(pIns->nDCT, DCT_NOTE); + VERIFY_EQUAL_NONCONT(pIns->nDNA, DNA_NOTEFADE); - VERIFY_EQUAL_NONCONT(pIns->nMixPlug, 1); - VERIFY_EQUAL_NONCONT(pIns->nMidiChannel, 16); - VERIFY_EQUAL_NONCONT(pIns->nMidiProgram, 64); - VERIFY_EQUAL_NONCONT(pIns->wMidiBank, 2); + VERIFY_EQUAL_NONCONT(pIns->nMixPlug, 1); + VERIFY_EQUAL_NONCONT(pIns->nMidiChannel, 16); + VERIFY_EQUAL_NONCONT(pIns->nMidiProgram, 64); + VERIFY_EQUAL_NONCONT(pIns->wMidiBank, 2); - VERIFY_EQUAL_NONCONT(pIns->pTuning, pIns->s_DefaultTuning); + VERIFY_EQUAL_NONCONT(pIns->pTuning, pIns->s_DefaultTuning); - VERIFY_EQUAL_NONCONT(pIns->wPitchToTempoLock, 130); + VERIFY_EQUAL_NONCONT(pIns->wPitchToTempoLock, 130); - VERIFY_EQUAL_NONCONT(pIns->nPluginVelocityHandling, PLUGIN_VELOCITYHANDLING_VOLUME); - VERIFY_EQUAL_NONCONT(pIns->nPluginVolumeHandling, PLUGIN_VOLUMEHANDLING_MIDI); + VERIFY_EQUAL_NONCONT(pIns->nPluginVelocityHandling, PLUGIN_VELOCITYHANDLING_VOLUME); + VERIFY_EQUAL_NONCONT(pIns->nPluginVolumeHandling, PLUGIN_VOLUMEHANDLING_MIDI); - for(size_t i = 0; i < NOTE_MAX; i++) - { - VERIFY_EQUAL_NONCONT(pIns->Keyboard[i], (i == NOTE_MIDDLEC - 1) ? 99 : 1); - VERIFY_EQUAL_NONCONT(pIns->NoteMap[i], (i == NOTE_MIDDLEC - 1) ? (i + 13) : (i + 1)); - } + for(size_t i = 0; i < NOTE_MAX; i++) + { + VERIFY_EQUAL_NONCONT(pIns->Keyboard[i], (i == NOTE_MIDDLEC - 1) ? 99 : 1); + VERIFY_EQUAL_NONCONT(pIns->NoteMap[i], (i == NOTE_MIDDLEC - 1) ? (i + 13) : (i + 1)); + } - VERIFY_EQUAL_NONCONT(pIns->VolEnv.dwFlags, ENV_ENABLED | ENV_CARRY); - VERIFY_EQUAL_NONCONT(pIns->VolEnv.nNodes, 3); - VERIFY_EQUAL_NONCONT(pIns->VolEnv.nReleaseNode, 1); - VERIFY_EQUAL_NONCONT(pIns->VolEnv.Ticks[2], 96); - VERIFY_EQUAL_NONCONT(pIns->VolEnv.Values[2], 0); + VERIFY_EQUAL_NONCONT(pIns->VolEnv.dwFlags, ENV_ENABLED | ENV_CARRY); + VERIFY_EQUAL_NONCONT(pIns->VolEnv.nNodes, 3); + VERIFY_EQUAL_NONCONT(pIns->VolEnv.nReleaseNode, 1); + VERIFY_EQUAL_NONCONT(pIns->VolEnv.Ticks[2], 96); + VERIFY_EQUAL_NONCONT(pIns->VolEnv.Values[2], 0); - VERIFY_EQUAL_NONCONT(pIns->PanEnv.dwFlags, ENV_LOOP); - VERIFY_EQUAL_NONCONT(pIns->PanEnv.nNodes, 76); - VERIFY_EQUAL_NONCONT(pIns->PanEnv.nLoopStart, 22); - VERIFY_EQUAL_NONCONT(pIns->PanEnv.nLoopEnd, 29); - VERIFY_EQUAL_NONCONT(pIns->PanEnv.nReleaseNode, ENV_RELEASE_NODE_UNSET); - VERIFY_EQUAL_NONCONT(pIns->PanEnv.Ticks[75], 427); - VERIFY_EQUAL_NONCONT(pIns->PanEnv.Values[75], 27); + VERIFY_EQUAL_NONCONT(pIns->PanEnv.dwFlags, ENV_LOOP); + VERIFY_EQUAL_NONCONT(pIns->PanEnv.nNodes, 76); + VERIFY_EQUAL_NONCONT(pIns->PanEnv.nLoopStart, 22); + VERIFY_EQUAL_NONCONT(pIns->PanEnv.nLoopEnd, 29); + VERIFY_EQUAL_NONCONT(pIns->PanEnv.nReleaseNode, ENV_RELEASE_NODE_UNSET); + VERIFY_EQUAL_NONCONT(pIns->PanEnv.Ticks[75], 427); + VERIFY_EQUAL_NONCONT(pIns->PanEnv.Values[75], 27); - VERIFY_EQUAL_NONCONT(pIns->PitchEnv.dwFlags, ENV_ENABLED | ENV_CARRY | ENV_SUSTAIN | ENV_FILTER); - VERIFY_EQUAL_NONCONT(pIns->PitchEnv.nNodes, 3); - VERIFY_EQUAL_NONCONT(pIns->PitchEnv.nSustainStart, 1); - VERIFY_EQUAL_NONCONT(pIns->PitchEnv.nSustainEnd, 2); - VERIFY_EQUAL_NONCONT(pIns->PitchEnv.Ticks[1], 96); - VERIFY_EQUAL_NONCONT(pIns->PitchEnv.Values[1], 64); - + VERIFY_EQUAL_NONCONT(pIns->PitchEnv.dwFlags, ENV_ENABLED | ENV_CARRY | ENV_SUSTAIN | ENV_FILTER); + VERIFY_EQUAL_NONCONT(pIns->PitchEnv.nNodes, 3); + VERIFY_EQUAL_NONCONT(pIns->PitchEnv.nSustainStart, 1); + VERIFY_EQUAL_NONCONT(pIns->PitchEnv.nSustainEnd, 2); + VERIFY_EQUAL_NONCONT(pIns->PitchEnv.Ticks[1], 96); + VERIFY_EQUAL_NONCONT(pIns->PitchEnv.Values[1], 64); + } // Sequences VERIFY_EQUAL_NONCONT(pSndFile->Order.GetNumSequences(), 2); @@ -707,7 +714,7 @@ VERIFY_EQUAL_NONCONT(pSndFile->Patterns[0].GetName(), "First Pattern"); VERIFY_EQUAL_NONCONT(pSndFile->Patterns[0].GetNumRows(), 70); - VERIFY_EQUAL_NONCONT(pSndFile->Patterns[0].GetNumChannels(), 2); + VERIFY_EQUAL_NONCONT(pSndFile->Patterns[0].GetNumChannels(), 70); VERIFY_EQUAL_NONCONT(pSndFile->Patterns[0].GetOverrideSignature(), true); VERIFY_EQUAL_NONCONT(pSndFile->Patterns[0].GetRowsPerBeat(), 5); VERIFY_EQUAL_NONCONT(pSndFile->Patterns[0].GetRowsPerMeasure(), 10); @@ -715,7 +722,7 @@ VERIFY_EQUAL_NONCONT(pSndFile->Patterns[1].GetName(), "Second Pattern"); VERIFY_EQUAL_NONCONT(pSndFile->Patterns[1].GetNumRows(), 32); - VERIFY_EQUAL_NONCONT(pSndFile->Patterns[1].GetNumChannels(), 2); + VERIFY_EQUAL_NONCONT(pSndFile->Patterns[1].GetNumChannels(), 70); VERIFY_EQUAL_NONCONT(pSndFile->Patterns[1].GetOverrideSignature(), false); VERIFY_EQUAL_NONCONT(pSndFile->Patterns[1].GetRowsPerBeat(), 0); VERIFY_EQUAL_NONCONT(pSndFile->Patterns[1].GetRowsPerMeasure(), 0); Modified: trunk/OpenMPT/mptrack/test/test.mptm =================================================================== (Binary files differ) Modified: trunk/OpenMPT/soundlib/FileReader.h =================================================================== --- trunk/OpenMPT/soundlib/FileReader.h 2012-11-05 15:09:20 UTC (rev 1418) +++ trunk/OpenMPT/soundlib/FileReader.h 2012-11-05 23:24:41 UTC (rev 1419) @@ -21,16 +21,19 @@ class FileReader //============== { +public: + typedef size_t off_t; // Type for file offsets and sizes + private: - const char *streamData; // Pointer to memory-mapped file - size_t streamLength; // Size of memory-mapped file in bytes - size_t streamPos; // Cursor location in the file + const char *streamData; // Pointer to memory-mapped file + off_t streamLength; // Size of memory-mapped file in bytes + off_t streamPos; // Cursor location in the file public: // Initialize invalid file reader object. FileReader() : streamData(nullptr), streamLength(0), streamPos(0) { } // Initialize file reader object with pointer to data and data length. - FileReader(const char *data, size_t length) : streamData(data), streamLength(length), streamPos(0) { } + FileReader(const char *data, off_t length) : streamData(data), streamLength(length), streamPos(0) { } // Initialize file reader object based on an existing file reader object. The other object's stream position is copied. FileReader(const FileReader &other) : streamData(other.streamData), streamLength(other.streamLength), streamPos(other.streamPos) { } @@ -48,7 +51,7 @@ // Seek to a position in the mapped file. // Returns false if position is invalid. - bool Seek(size_t position) + bool Seek(off_t position) { if(position <= streamLength) { @@ -62,7 +65,7 @@ // Increases position by skipBytes. // Returns true if skipBytes could be skipped or false if the file end was reached earlier. - bool Skip(size_t skipBytes) + bool Skip(off_t skipBytes) { if(BytesLeft() >= skipBytes) { @@ -77,7 +80,7 @@ // Decreases position by skipBytes. // Returns true if skipBytes could be skipped or false if the file start was reached earlier. - bool SkipBack(size_t skipBytes) + bool SkipBack(off_t skipBytes) { if(streamPos >= skipBytes) { @@ -91,33 +94,33 @@ } // Returns cursor position in the mapped file. - size_t GetPosition() const + off_t GetPosition() const { return streamPos; } // Returns size of the mapped file in bytes. - size_t GetLength() const + off_t GetLength() const { return streamLength; } // Return byte count between cursor position and end of file, i.e. how many bytes can still be read. - size_t BytesLeft() const + off_t BytesLeft() const { ASSERT(streamPos <= streamLength); return streamLength - streamPos; } // Check if "amount" bytes can be read from the current position in the stream. - bool CanRead(size_t amount) const + bool CanRead(off_t amount) const { return (amount <= BytesLeft()); } // Create a new FileReader object for parsing a sub chunk at a given position with a given length. // The file cursor is not modified. - FileReader GetChunk(size_t position, size_t length) const + FileReader GetChunk(off_t position, off_t length) const { if(position < streamLength) { @@ -130,9 +133,9 @@ // Create a new FileReader object for parsing a sub chunk at the current position with a given length. // The file cursor is advanced by "length" bytes. - FileReader GetChunk(size_t length) + FileReader GetChunk(off_t length) { - size_t position = streamPos; + off_t position = streamPos; Skip(length); return GetChunk(position, length); } @@ -328,9 +331,9 @@ // Allow to read a struct partially (if there's less memory available than the struct's size, fill it up with zeros). // The file cursor is advanced by "partialSize" bytes. template <typename T> - bool ReadStructPartial(T &target, size_t partialSize = sizeof(T)) + bool ReadStructPartial(T &target, off_t partialSize = sizeof(T)) { - const size_t copyBytes = Util::Min(partialSize, sizeof(target), BytesLeft()); + const off_t copyBytes = Util::Min(partialSize, sizeof(target), BytesLeft()); memcpy(&target, streamData + streamPos, copyBytes); memset(reinterpret_cast<char *>(&target) + copyBytes, 0, sizeof(target) - copyBytes); @@ -357,8 +360,8 @@ // Read a string of length srcSize into fixed-length char array destBuffer using a given read mode. // The file cursor is advanced by "srcSize" bytes. - template<StringFixer::ReadWriteMode mode, size_t destSize> - bool ReadString(char (&destBuffer)[destSize], const size_t srcSize) + template<StringFixer::ReadWriteMode mode, off_t destSize> + bool ReadString(char (&destBuffer)[destSize], const off_t srcSize) { if(CanRead(srcSize)) { @@ -374,7 +377,7 @@ // Read an array. // If successful, the file cursor is advanced by the size of the array. // Otherwise, the target is zeroed. - template<typename T, size_t destSize> + template<typename T, off_t destSize> bool ReadArray(T (&destArray)[destSize]) { if(CanRead(sizeof(destArray))) @@ -395,12 +398,15 @@ template<typename T> bool ReadVector(std::vector<T> &destVector, size_t destSize) { - const size_t readSize = sizeof(T) * destSize; + const off_t readSize = sizeof(T) * destSize; if(CanRead(readSize)) { destVector.resize(destSize); - memcpy(&destVector[0], streamData + streamPos, readSize); - streamPos += readSize; + if(readSize) + { + memcpy(&destVector[0], streamData + streamPos, readSize); + streamPos += readSize; + } return true; } else { @@ -414,7 +420,7 @@ // Returns false if the string could not be found. The file cursor is not advanced in this case. bool ReadMagic(const char *const magic) { - const size_t magicLength = strlen(magic); + const off_t magicLength = strlen(magic); if(CanRead(magicLength) && !memcmp(streamData + streamPos, magic, magicLength)) { streamPos += magicLength; @@ -442,12 +448,12 @@ return false; } - size_t writtenBits = 0; + off_t writtenBits = 0; uint8 b = ReadUint8(); target = (b & 0x7F); // Count actual bits used in most significant byte (i.e. this one) - for(size_t bit = 0; bit < 7; bit++) + for(off_t bit = 0; bit < 7; bit++) { if((b & (1 << bit)) != 0) { Modified: trunk/OpenMPT/soundlib/ITTools.cpp =================================================================== --- trunk/OpenMPT/soundlib/ITTools.cpp 2012-11-05 15:09:20 UTC (rev 1418) +++ trunk/OpenMPT/soundlib/ITTools.cpp 2012-11-05 23:24:41 UTC (rev 1419) @@ -114,12 +114,22 @@ } +// Convert all multi-byte numeric values to current platform's endianness or vice versa. +void ITOldInstrument::ConvertEndianness() +//--------------------------------------- +{ + SwapBytesLE(id); + SwapBytesLE(fadeout); + SwapBytesLE(trkvers); +} + + // Convert an ITOldInstrument to OpenMPT's internal instrument representation. void ITOldInstrument::ConvertToMPT(ModInstrument &mptIns) const //------------------------------------------------------------- { // Header - if(id != LittleEndian(ITOldInstrument::magic)) + if(id != ITOldInstrument::magic) { return; } @@ -128,7 +138,7 @@ StringFixer::ReadString<StringFixer::nullTerminated>(mptIns.filename, filename); // Volume / Panning - mptIns.nFadeOut = LittleEndianW(fadeout) << 6; + mptIns.nFadeOut = fadeout << 6; mptIns.nGlobalVol = 64; mptIns.nPan = 128; @@ -182,6 +192,18 @@ } +// Convert all multi-byte numeric values to current platform's endianness or vice versa. +void ITInstrument::ConvertEndianness() +//------------------------------------ +{ + SwapBytesLE(id); + SwapBytesLE(fadeout); + SwapBytesLE(trkvers); + SwapBytesLE(mbank); + SwapBytesLE(dummy); +} + + // Convert OpenMPT's internal instrument representation to an ITInstrument. size_t ITInstrument::ConvertToIT(const ModInstrument &mptIns, bool compatExport, const CSoundFile &sndFile) //--------------------------------------------------------------------------------------------------------- @@ -189,14 +211,14 @@ MemsetZero(*this); // Header - id = LittleEndian(ITInstrument::magic); - trkvers = LittleEndianW(0x0214); + id = ITInstrument::magic; + trkvers = 0x0214; StringFixer::WriteString<StringFixer::nullTerminated>(filename, mptIns.filename); StringFixer::WriteString<StringFixer::nullTerminated>(name, mptIns.name); // Volume / Panning - fadeout = LittleEndianW(static_cast<uint16>(min(mptIns.nFadeOut >> 5, 256))); + fadeout = static_cast<uint16>(min(mptIns.nFadeOut >> 5, 256)); gbv = static_cast<uint8>(min(mptIns.nGlobalVol * 2, 128)); dfp = static_cast<uint8>(min(mptIns.nPan / 4, 64)); if(!mptIns.dwFlags[INS_SETPANNING]) dfp |= ITInstrument::ignorePanning; @@ -268,7 +290,7 @@ size_t ITInstrument::ConvertToMPT(ModInstrument &mptIns, MODTYPE modFormat) const //------------------------------------------------------------------------------- { - if(id != LittleEndian(ITInstrument::magic)) + if(id != ITInstrument::magic) { return 0; } @@ -277,7 +299,7 @@ StringFixer::ReadString<StringFixer::nullTerminated>(mptIns.filename, filename); // Volume / Panning - mptIns.nFadeOut = LittleEndianW(fadeout) << 5; + mptIns.nFadeOut = fadeout << 5; mptIns.nGlobalVol = gbv / 2; LimitMax(mptIns.nGlobalVol, 64u); mptIns.nPan = (dfp & 0x7F) * 4; @@ -315,7 +337,7 @@ } if(mbank <= 128) { - mptIns.wMidiBank = LittleEndianW(mbank); + mptIns.wMidiBank = mbank; } // Envelope point count. Limited to 25 in IT format. @@ -351,6 +373,14 @@ } +// Convert all multi-byte numeric values to current platform's endianness or vice versa. +void ITInstrumentEx::ConvertEndianness() +//-------------------------------------- +{ + iti.ConvertEndianness(); +} + + // Convert OpenMPT's internal instrument representation to an ITInstrumentEx. Returns amount of bytes that need to be written to file. size_t ITInstrumentEx::ConvertToIT(const ModInstrument &mptIns, bool compatExport, const CSoundFile &sndFile) //----------------------------------------------------------------------------------------------------------- @@ -391,7 +421,7 @@ if(usedExtension) { // If we actually had to extend the sample map, update the magic bytes and instrument size. - iti.dummy = LittleEndian(ITInstrumentEx::mptx); + iti.dummy = ITInstrumentEx::mptx; instSize = sizeof(ITInstrumentEx); } @@ -406,7 +436,7 @@ size_t insSize = iti.ConvertToMPT(mptIns, fromType); // Is this actually an extended instrument? - if(insSize == 0 || iti.dummy != LittleEndian(ITInstrumentEx::mptx)) + if(insSize == 0 || iti.dummy != ITInstrumentEx::mptx) { return insSize; } @@ -421,6 +451,21 @@ } +// Convert all multi-byte numeric values to current platform's endianness or vice versa. +void ITSample::ConvertEndianness() +//-------------------------------- +{ + SwapBytesLE(id); + SwapBytesLE(length); + SwapBytesLE(loopbegin); + SwapBytesLE(loopend); + SwapBytesLE(C5Speed); + SwapBytesLE(susloopbegin); + SwapBytesLE(susloopend); + SwapBytesLE(samplepointer); +} + + // Convert OpenMPT's internal sample representation to an ITSample. void ITSample::ConvertToIT(const ModSample &mptSmp, MODTYPE fromType) //------------------------------------------------------------------- @@ -428,7 +473,7 @@ MemsetZero(*this); // Header - id = LittleEndian(ITSample::magic); + id = ITSample::magic; StringFixer::WriteString<StringFixer::nullTerminated>(filename, mptSmp.filename); //StringFixer::WriteString<StringFixer::nullTerminated>(name, m_szNames[nsmp]); @@ -463,14 +508,14 @@ } // Frequency - C5Speed = LittleEndian(mptSmp.nC5Speed ? mptSmp.nC5Speed : 8363); + C5Speed = mptSmp.nC5Speed ? mptSmp.nC5Speed : 8363; // Size and loops - length = LittleEndian(mptSmp.nLength); - loopbegin = LittleEndian(mptSmp.nLoopStart); - loopend = LittleEndian(mptSmp.nLoopEnd); - susloopbegin = LittleEndian(mptSmp.nSustainStart); - susloopend = LittleEndian(mptSmp.nSustainEnd); + length = mptSmp.nLength; + loopbegin = mptSmp.nLoopStart; + loopend = mptSmp.nLoopEnd; + susloopbegin = mptSmp.nSustainStart; + susloopend = mptSmp.nSustainEnd; // Auto Vibrato settings static const uint8 autovibxm2it[8] = { 0, 2, 4, 1, 3, 0, 0, 0 }; // OpenMPT VibratoType -> IT Vibrato @@ -491,7 +536,7 @@ size_t ITSample::ConvertToMPT(ModSample &mptSmp) const //---------------------------------------------------- { - if(id != LittleEndian(ITSample::magic)) + if(id != ITSample::magic) { return 0; } @@ -515,16 +560,16 @@ if(flags & ITSample::sampleBidiSustain) mptSmp.uFlags |= CHN_PINGPONGSUSTAIN; // Frequency - mptSmp.nC5Speed = LittleEndian(C5Speed); + mptSmp.nC5Speed = C5Speed; if(!mptSmp.nC5Speed) mptSmp.nC5Speed = 8363; if(mptSmp.nC5Speed < 256) mptSmp.nC5Speed = 256; // Size and loops - mptSmp.nLength = LittleEndian(length); - mptSmp.nLoopStart = LittleEndian(loopbegin); - mptSmp.nLoopEnd = LittleEndian(loopend); - mptSmp.nSustainStart = LittleEndian(susloopbegin); - mptSmp.nSustainEnd = LittleEndian(susloopend); + mptSmp.nLength = length; + mptSmp.nLoopStart = loopbegin; + mptSmp.nLoopEnd = loopend; + mptSmp.nSustainStart = susloopbegin; + mptSmp.nSustainEnd = susloopend; // Auto Vibrato settings static const uint8 autovibit2xm[8] = { VIB_SINE, VIB_RAMP_DOWN, VIB_SQUARE, VIB_RANDOM, VIB_RAMP_UP, 0, 0, 0 }; // IT Vibrato -> OpenMPT VibratoType @@ -533,7 +578,7 @@ mptSmp.nVibDepth = vid & 0x7F; mptSmp.nVibSweep = vir; - return LittleEndian(samplepointer); + return samplepointer; } @@ -587,23 +632,29 @@ #ifdef MODPLUG_TRACKER +// Convert all multi-byte numeric values to current platform's endianness or vice versa. +void ITHistoryStruct::ConvertEndianness() +//--------------------------------------- +{ + SwapBytesLE(fatdate); + SwapBytesLE(fattime); + SwapBytesLE(runtime); +} + + // Convert an ITHistoryStruct to OpenMPT's internal edit history representation void ITHistoryStruct::ConvertToMPT(FileHistory &mptHistory) const //--------------------------------------------------------------- { - uint16 date = LittleEndianW(fatdate); - uint16 time = LittleEndianW(fattime); - uint32 run = LittleEndian(runtime); - // Decode FAT date and time MemsetZero(mptHistory.loadDate); - mptHistory.loadDate.tm_year = ((date >> 9) & 0x7F) + 80; - mptHistory.loadDate.tm_mon = Clamp((date >> 5) & 0x0F, 1, 12) - 1; - mptHistory.loadDate.tm_mday = Clamp(date & 0x1F, 1, 31); - mptHistory.loadDate.tm_hour = Clamp((time >> 11) & 0x1F, 0, 23); - mptHistory.loadDate.tm_min = Clamp((time >> 5) & 0x3F, 0, 59); - mptHistory.loadDate.tm_sec = Clamp((time & 0x1F) * 2, 0, 59); - mptHistory.openTime = static_cast<uint32>(run * (HISTORY_TIMER_PRECISION / 18.2f)); + mptHistory.loadDate.tm_year = ((fatdate >> 9) & 0x7F) + 80; + mptHistory.loadDate.tm_mon = Clamp((fatdate >> 5) & 0x0F, 1, 12) - 1; + mptHistory.loadDate.tm_mday = Clamp(fatdate & 0x1F, 1, 31); + mptHistory.loadDate.tm_hour = Clamp((fattime >> 11) & 0x1F, 0, 23); + mptHistory.loadDate.tm_min = Clamp((fattime >> 5) & 0x3F, 0, 59); + mptHistory.loadDate.tm_sec = Clamp((fattime & 0x1F) * 2, 0, 59); + mptHistory.openTime = static_cast<uint32>(runtime * (HISTORY_TIMER_PRECISION / 18.2f)); } @@ -615,10 +666,6 @@ fatdate = static_cast<uint16>(mptHistory.loadDate.tm_mday | ((mptHistory.loadDate.tm_mon + 1) << 5) | ((mptHistory.loadDate.tm_year - 80) << 9)); fattime = static_cast<uint16>((mptHistory.loadDate.tm_sec / 2) | (mptHistory.loadDate.tm_min << 5) | (mptHistory.loadDate.tm_hour << 11)); runtime = static_cast<uint32>(mptHistory.openTime * (18.2f / HISTORY_TIMER_PRECISION)); - - SwapBytesLE(fatdate); - SwapBytesLE(fattime); - SwapBytesLE(runtime); } #endif // MODPLUG_TRACKER \ No newline at end of file Modified: trunk/OpenMPT/soundlib/ITTools.h =================================================================== --- trunk/OpenMPT/soundlib/ITTools.h 2012-11-05 15:09:20 UTC (rev 1418) +++ trunk/OpenMPT/soundlib/ITTools.h 2012-11-05 23:24:41 UTC (rev 1419) @@ -143,6 +143,9 @@ uint8 volenv[200]; // This appears to be a pre-computed (interpolated) version of the volume envelope data found below. uint8 nodes[25 * 2]; // Volume Envelope Node Positions / Values + // Convert all multi-byte numeric values to current platform's endianness or vice versa. + void ConvertEndianness(); + // Convert an ITOldInstrument to OpenMPT's internal instrument representation. void ConvertToMPT(ModInstrument &mptIns) const; }; @@ -193,6 +196,9 @@ ITEnvelope pitchenv; // Pitch / Filter Envelope uint32 dummy; // IT saves some additional padding bytes to match the size of the old instrument format for simplified loading. We use them for some hacks. + // Convert all multi-byte numeric values to current platform's endianness or vice versa. + void ConvertEndianness(); + // Convert OpenMPT's internal instrument representation to an ITInstrument. Returns amount of bytes that need to be written. size_t ConvertToIT(const ModInstrument &mptIns, bool compatExport, const CSoundFile &sndFile); // Convert an ITInstrument to OpenMPT's internal instrument representation. Returns size of the instrument data that has been read. @@ -213,6 +219,9 @@ ITInstrument iti; // Normal IT Instrument uint8 keyboardhi[120]; // High Byte of Sample map + // Convert all multi-byte numeric values to current platform's endianness or vice versa. + void ConvertEndianness(); + // Convert OpenMPT's internal instrument representation to an ITInstrumentEx. Returns amount of bytes that need to be written. size_t ConvertToIT(const ModInstrument &mptIns, bool compatExport, const CSoundFile &sndFile); // Convert an ITInstrumentEx to OpenMPT's internal instrument representation. Returns size of the instrument data that has been read. @@ -274,6 +283,9 @@ uint8 vir; // Auto-Vibrato Sweep (called Rate in IT) uint8 vit; // Auto-Vibrato Type + // Convert all multi-byte numeric values to current platform's endianness or vice versa. + void ConvertEndianness(); + // Convert OpenMPT's internal sample representation to an ITSample. void ConvertToIT(const ModSample &mptSmp, MODTYPE fromType); // Convert an ITSample to OpenMPT's internal sample representation. @@ -301,6 +313,9 @@ #ifdef MODPLUG_TRACKER + // Convert all multi-byte numeric values to current platform's endianness or vice versa. + void ConvertEndianness(); + // Convert an ITHistoryStruct to OpenMPT's internal edit history representation void ConvertToMPT(FileHistory &mptHistory) const; // Convert OpenMPT's internal edit history representation to an ITHistoryStruct Modified: trunk/OpenMPT/soundlib/LOAD_AMF.CPP =================================================================== --- trunk/OpenMPT/soundlib/LOAD_AMF.CPP 2012-11-05 15:09:20 UTC (rev 1418) +++ trunk/OpenMPT/soundlib/LOAD_AMF.CPP 2012-11-05 23:24:41 UTC (rev 1419) @@ -430,7 +430,7 @@ // Setup Order List Order.resize(fileHeader.numOrders); vector<ROWINDEX> patternLength(fileHeader.numOrders, 64); - const size_t trackStartPos = file.GetPosition() + (fileHeader.version >= 14 ? 2 : 0); + const FileReader::off_t trackStartPos = file.GetPosition() + (fileHeader.version >= 14 ? 2 : 0); for(ORDERINDEX ord = 0; ord < fileHeader.numOrders; ord++) { Modified: trunk/OpenMPT/soundlib/Load_it.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_it.cpp 2012-11-05 15:09:20 UTC (rev 1418) +++ trunk/OpenMPT/soundlib/Load_it.cpp 2012-11-05 23:24:41 UTC (rev 1419) @@ -234,112 +234,107 @@ } -size_t CSoundFile::ITInstrToMPT(const void *p, ModInstrument *pIns, UINT trkvers, size_t memLength) -//------------------------------------------------------------------------------------------------- +size_t CSoundFile::ITInstrToMPT(FileReader &file, ModInstrument &ins, uint16 trkvers) +//----------------------------------------------------------------------------------- { if(trkvers < 0x0200) { // Load old format (IT 1.xx) instrument - const ITOldInstrument *itIns = reinterpret_cast<const ITOldInstrument *>(p); - itIns->ConvertToMPT(*pIns); - return sizeof(ITOldInstrument); - } else - { - size_t instSize = 0; - if(memLength >= sizeof(ITInstrumentEx)) + ITOldInstrument instrumentHeader; + if(!file.ReadConvertEndianness(instrumentHeader)) { - // Try loading extended instrument - const ITInstrumentEx *itIns = reinterpret_cast<const ITInstrumentEx *>(p); - instSize = itIns->ConvertToMPT(*pIns, GetType()); + return 0; } else { - // Load normal instrument - const ITInstrument *itIns = reinterpret_cast<const ITInstrument *>(p); - instSize = itIns->ConvertToMPT(*pIns, GetType()); + instrumentHeader.ConvertToMPT(ins); + return sizeof(ITOldInstrument); } + } else + { + const FileReader::off_t offset = file.GetPosition(); + // Try loading extended instrument... instSize will differ between normal and extended instruments. + ITInstrumentEx instrumentHeader; + file.ReadStructPartial(instrumentHeader); + instrumentHeader.ConvertEndianness(); + size_t instSize = instrumentHeader.ConvertToMPT(ins, GetType()); + file.Seek(offset + instSize); + // Try reading modular instrument data - instSize += LoadModularInstrumentData(LPCBYTE(p) + instSize, memLength - instSize, pIns); + instSize += LoadModularInstrumentData(file, ins); return instSize; } } -void CopyPatternName(CPattern &pattern, const char **patNames, UINT &patNamesLen) -//------------------------------------------------------------------------------- +void CopyPatternName(CPattern &pattern, FileReader &file) +//------------------------------------------------------- { - if(*patNames != nullptr && patNamesLen > 0) - { - pattern.SetName(*patNames, min(MAX_PATTERNNAME, patNamesLen)); - *patNames += MAX_PATTERNNAME; - patNamesLen -= min(MAX_PATTERNNAME, patNamesLen); - } + char name[MAX_PATTERNNAME] = ""; + file.ReadString<StringFixer::maybeNullTerminated>(name, MAX_PATTERNNAME); + pattern.SetName(name); } -bool CSoundFile::ReadIT(const LPCBYTE lpStream, const DWORD dwMemLength) -//---------------------------------------------------------------------- +bool CSoundFile::ReadIT(FileReader &file) +//--------------------------------------- { - if(!lpStream || dwMemLength < sizeof(ITFileHeader)) return false; + file.Rewind(); - ITFileHeader itHeader = *reinterpret_cast<const ITFileHeader *>(lpStream); - itHeader.ConvertEndianness(); + ITFileHeader fileHeader; + if(!file.ReadConvertEndianness(fileHeader) + || (fileHeader.id != ITFileHeader::itMagic && fileHeader.id != ITFileHeader::mptmMagic) + || fileHeader.insnum > 0xFF + || fileHeader.smpnum >= MAX_SAMPLES + || !file.CanRead(fileHeader.ordnum + (fileHeader.insnum + fileHeader.smpnum + fileHeader.patnum) * 4)) + { + return false; + } - DWORD dwMemPos = sizeof(ITFileHeader); - vector<DWORD> inspos; - vector<DWORD> smppos; - vector<DWORD> patpos; - bool interpretModPlugMade = false; - bool hasModPlugExtensions = false; - if((itHeader.id != ITFileHeader::itMagic && itHeader.id != ITFileHeader::mptmMagic) || itHeader.insnum > 0xFF - || itHeader.smpnum >= MAX_SAMPLES) return false; - // Check if we can actually read all parapointers - if(dwMemPos + itHeader.ordnum + itHeader.insnum * 4 - + itHeader.smpnum * 4 + itHeader.patnum * 4 > dwMemLength) return false; + // OpenMPT crap at the end of file + file.Seek(file.GetLength() - 4); + size_t mptStartPos = file.ReadUint32LE(); + if(mptStartPos >= file.GetLength() || mptStartPos < 0x100) + { + mptStartPos = file.GetLength(); + } - DWORD mptStartPos = dwMemLength; - memcpy(&mptStartPos, lpStream + (dwMemLength - sizeof(DWORD)), sizeof(DWORD)); - if(mptStartPos >= dwMemLength || mptStartPos < 0x100) - mptStartPos = dwMemLength; - - if(itHeader.id == ITFileHeader::mptmMagic) + if(fileHeader.id == ITFileHeader::mptmMagic) { ChangeModTypeTo(MOD_TYPE_MPT); - } - else + } else { - if(mptStartPos <= dwMemLength - 3 && itHeader.cwtv > 0x888) + if(mptStartPos <= file.GetLength() - 3 && fileHeader.cwtv > 0x888) { - char temp[3]; - const char ID[3] = {'2','2','8'}; - memcpy(temp, lpStream + mptStartPos, 3); - if(!memcmp(temp, ID, 3)) ChangeModTypeTo(MOD_TYPE_MPT); - else ChangeModTypeTo(MOD_TYPE_IT); + file.Seek(mptStartPos); + ChangeModTypeTo(file.ReadMagic("228") ? MOD_TYPE_MPT : MOD_TYPE_IT); + } else + { + ChangeModTypeTo(MOD_TYPE_IT); } - else ChangeModTypeTo(MOD_TYPE_IT); if(GetType() == MOD_TYPE_IT) { // Which tracker was used to made this? - if((itHeader.cwtv & 0xF000) == 0x5000) + if((fileHeader.cwtv & 0xF000) == 0x5000) { // OpenMPT Version number (Major.Minor) // This will only be interpreted as "made with ModPlug" (i.e. disable compatible playback etc) if the "reserved" field is set to "OMPT" - else, compatibility was used. - m_dwLastSavedWithVersion = (itHeader.cwtv & 0x0FFF) << 16; - if(itHeader.reserved == ITFileHeader::omptMagic) + m_dwLastSavedWithVersion = (fileHeader.cwtv & 0x0FFF) << 16; + if(fileHeader.reserved == ITFileHeader::omptMagic) interpretModPlugMade = true; - } else if(itHeader.cmwt == 0x888 || itHeader.cwtv == 0x888) + } else if(fileHeader.cmwt == 0x888 || fileHeader.cwtv == 0x888) { // OpenMPT 1.17 and 1.18 (raped IT format) // Exact version number will be determined later. interpretModPlugMade = true; m_dwLastSavedWithVersion = MAKE_VERSION_NUMERIC(1, 17, 00, 00); - } else if(itHeader.cwtv == 0x0217 && itHeader.cmwt == 0x0200 && itHeader.reserved == 0) + } else if(fileHeader.cwtv == 0x0217 && fileHeader.cmwt == 0x0200 && fileHeader.reserved == 0) { - if(memchr(itHeader.chnpan, 0xFF, sizeof(itHeader.chnpan)) != NULL) + if(memchr(fileHeader.chnpan, 0xFF, sizeof(fileHeader.chnpan)) != NULL) { // ModPlug Tracker 1.16 (semi-raped IT format) m_dwLastSavedWithVersion = MAKE_VERSION_NUMERIC(1, 16, 00, 00); @@ -350,206 +345,163 @@ m_dwLastSavedWithVersion = MAKE_VERSION_NUMERIC(1, 17, 00, 00); } interpretModPlugMade = true; - } else if(itHeader.cwtv == 0x0214 && itHeader.cmwt == 0x0202 && itHeader.reserved == 0) + } else if(fileHeader.cwtv == 0x0214 && fileHeader.cmwt == 0x0202 && fileHeader.reserved == 0) { // ModPlug Tracker b3.3 - 1.09, instruments 557 bytes apart m_dwLastSavedWithVersion = MAKE_VERSION_NUMERIC(1, 09, 00, 00); interpretModPlugMade = true; } - else if(itHeader.cwtv == 0x0214 && itHeader.cmwt == 0x0200 && itHeader.reserved == 0) + else if(fileHeader.cwtv == 0x0214 && fileHeader.cmwt == 0x0200 && fileHeader.reserved == 0) { // ModPlug Tracker 1.00a5, instruments 560 bytes apart m_dwLastSavedWithVersion = MAKE_VERSION_NUMERIC(1, 00, 00, A5); interpretModPlugMade = true; } - } - else // case: type == MOD_TYPE_MPT + } else // case: type == MOD_TYPE_MPT { - if (itHeader.cwtv >= verMptFileVerLoadLimit) + if (fileHeader.cwtv >= verMptFileVerLoadLimit) { - if (GetpModDoc()) + if(GetpModDoc()) GetpModDoc()->AddToLog(str_LoadingIncompatibleVersion); return false; } - else if (itHeader.cwtv > verMptFileVer) + else if (fileHeader.cwtv > verMptFileVer) { - if (GetpModDoc()) + if(GetpModDoc()) GetpModDoc()->AddToLog(str_LoadingMoreRecentVersion); } } } - if(GetType() == MOD_TYPE_IT) mptStartPos = dwMemLength; + if(GetType() == MOD_TYPE_IT) mptStartPos = file.GetLength(); // Read row highlights - if((itHeader.special & ITFileHeader::embedPatternHighlights)) + if((fileHeader.special & ITFileHeader::embedPatternHighlights)) { // MPT 1.09, 1.07 and most likely other old MPT versions leave this blank (0/0), but have the "special" flag set. // Newer versions of MPT and OpenMPT 1.17 *always* write 4/16 here. // Thus, we will just ignore those old versions. if(m_dwLastSavedWithVersion == 0 || m_dwLastSavedWithVersion >= MAKE_VERSION_NUMERIC(1, 17, 03, 02)) { - m_nDefaultRowsPerBeat = itHeader.highlight_minor; - m_nDefaultRowsPerMeasure = itHeader.highlight_major; + m_nDefaultRowsPerBeat = fileHeader.highlight_minor; + m_nDefaultRowsPerMeasure = fileHeader.highlight_major; } -#ifdef DEBUG - if((itHeader.highlight_minor | itHeader.highlight_major) == 0) +#ifdef _DEBUG + if((fileHeader.highlight_minor | fileHeader.highlight_major) == 0) { Log("IT Header: Row highlight is 0"); } #endif } - m_SongFlags.set(SONG_LINEARSLIDES, (itHeader.flags & ITFileHeader::linearSlides) != 0); - m_SongFlags.set(SONG_ITOLDEFFECTS, (itHeader.flags & ITFileHeader::itOldEffects) != 0); - m_SongFlags.set(SONG_ITCOMPATGXX, (itHeader.flags & ITFileHeader::itCompatGxx) != 0); - m_SongFlags.set(SONG_EMBEDMIDICFG, (itHeader.flags & ITFileHeader::reqEmbeddedMIDIConfig) || (itHeader.special & ITFileHeader::embedMIDIConfiguration)); - m_SongFlags.set(SONG_EXFILTERRANGE, (itHeader.flags & ITFileHeader::extendedFilterRange) != 0); + m_SongFlags.set(SONG_LINEARSLIDES, (fileHeader.flags & ITFileHeader::linearSlides) != 0); + m_SongFlags.set(SONG_ITOLDEFFECTS, (fileHeader.flags & ITFileHeader::itOldEffects) != 0); + m_SongFlags.set(SONG_ITCOMPATGXX, (fileHeader.flags & ITFileHeader::itCompatGxx) != 0); + m_SongFlags.set(SONG_EMBEDMIDICFG, (fileHeader.flags & ITFileHeader::reqEmbeddedMIDIConfig) || (fileHeader.special & ITFileHeader::embedMIDIConfiguration)); + m_SongFlags.set(SONG_EXFILTERRANGE, (fileHeader.flags & ITFileHeader::extendedFilterRange) != 0); - StringFixer::ReadString<StringFixer::spacePadded>(m_szNames[0], itHeader.songname); + StringFixer::ReadString<StringFixer::spacePadded>(m_szNames[0], fileHeader.songname); // Global Volume - m_nDefaultGlobalVolume = itHeader.globalvol << 1; - if (m_nDefaultGlobalVolume > MAX_GLOBAL_VOLUME) m_nDefaultGlobalVolume = MAX_GLOBAL_VOLUME; - if (itHeader.speed) m_nDefaultSpeed = itHeader.speed; - m_nDefaultTempo = max(32, itHeader.tempo); // tempo 31 is possible. due to conflicts with the rest of the engine, let's just clamp it to 32. - m_nSamplePreAmp = min(itHeader.mv, 128); + m_nDefaultGlobalVolume = fileHeader.globalvol << 1; + if(m_nDefaultGlobalVolume > MAX_GLOBAL_VOLUME) m_nDefaultGlobalVolume = MAX_GLOBAL_VOLUME; + if(fileHeader.speed) m_nDefaultSpeed = fileHeader.speed; + m_nDefaultTempo = Util::Max(uint8(32), fileHeader.tempo); // Tempo 31 is possible. due to conflicts with the rest of the engine, let's just clamp it to 32. + m_nSamplePreAmp = Util::Min(fileHeader.mv, uint8(128)); // Reading Channels Pan Positions - for (int ipan=0; ipan< 64; ipan++) if (itHeader.chnpan[ipan] != 0xFF) + for(CHANNELINDEX i = 0; i < 64; i++) if(fileHeader.chnpan[i] != 0xFF) { - ChnSettings[ipan].nVolume = itHeader.chnvol[ipan]; - ChnSettings[ipan].nPan = 128; - ChnSettings[ipan].dwFlags.reset(); - if(itHeader.chnpan[ipan] & 0x80) ChnSettings[ipan].dwFlags.set(CHN_MUTE); - UINT n = itHeader.chnpan[ipan] & 0x7F; - if (n <= 64) ChnSettings[ipan].nPan = n << 2; - if (n == 100) ChnSettings[ipan].dwFlags.set(CHN_SURROUND); + ChnSettings[i].nVolume = fileHeader.chnvol[i]; + ChnSettings[i].nPan = 128; + ChnSettings[i].dwFlags.reset(); + if(fileHeader.chnpan[i] & 0x80) ChnSettings[i].dwFlags.set(CHN_MUTE); + uint8 n = fileHeader.chnpan[i] & 0x7F; + if(n <= 64) ChnSettings[i].nPan = n * 4; + if(n == 100) ChnSettings[i].dwFlags.set(CHN_SURROUND); } - if (m_nChannels < GetModSpecifications().channelsMin) m_nChannels = GetModSpecifications().channelsMin; // Reading orders - UINT nordsize = itHeader.ordnum; + file.Seek(sizeof(ITFileHeader)); if(GetType() == MOD_TYPE_IT) { - if(nordsize > MAX_ORDERS) nordsize = MAX_ORDERS; - Order.ReadAsByte(lpStream + dwMemPos, nordsize, dwMemLength-dwMemPos); - dwMemPos += itHeader.ordnum; - } - else + Order.ReadAsByte(file, fileHeader.ordnum); + } else { - if(nordsize > GetModSpecifications().ordersMax) + ORDERINDEX ordSize = fileHeader.ordnum; + if(fileHeader.ordnum > GetModSpecifications().ordersMax) { #ifdef MODPLUG_TRACKER CString str; - str.Format(str_SequenceTruncationNote, nordsize, GetModSpecifications().ordersMax); + str.Format(str_SequenceTruncationNote, fileHeader.ordnum, GetModSpecifications().ordersMax); if(GetpModDoc() != nullptr) GetpModDoc()->AddToLog(str); #endif // MODPLUG_TRACKER - nordsize = GetModSpecifications().ordersMax; + ordSize = GetModSpecifications().ordersMax; } - if(itHeader.cwtv > 0x88A && itHeader.cwtv <= 0x88D) - dwMemPos += Order.Deserialize(lpStream+dwMemPos, dwMemLength-dwMemPos); - else + if(fileHeader.cwtv > 0x88A && fileHeader.cwtv <= 0x88D) { - Order.ReadAsByte(lpStream + dwMemPos, nordsize, dwMemLength - dwMemPos); - dwMemPos += itHeader.ordnum; - //Replacing 0xFF and 0xFE with new corresponding indexes + Order.Deserialize(file); + } else + { + Order.ReadAsByte(file, fileHeader.ordnum); + // Replacing 0xFF and 0xFE with new corresponding indexes Order.Replace(0xFE, Order.GetIgnoreIndex()); Order.Replace(0xFF, Order.GetInvalidPatIndex()); } } + // Reading instrument, sample and pattern offsets + vector<uint32> insPos, smpPos, patPos; + file.ReadVector(insPos, fileHeader.insnum); + file.ReadVector(smpPos, fileHeader.smpnum); + file.ReadVector(patPos, fileHeader.patnum); + // Find the first parapointer. // This is used for finding out whether the edit history is actually stored in the file or not, // as some early versions of Schism Tracker set the history flag, but didn't save anything. // We will consider the history invalid if it ends after the first parapointer. - DWORD minptr = dwMemLength; - - // Reading Instrument Offsets - inspos.resize(itHeader.insnum); - for(size_t n = 0; n < itHeader.insnum; n++) + uint32 minPtr = Util::MaxValueOfType(minPtr); + for(uint16 n = 0; n < fileHeader.insnum; n++) { - if(4 > dwMemLength - dwMemPos) - return false; - DWORD insptr = LittleEndian(*(DWORD *)(lpStream + dwMemPos)); - inspos[n] = insptr; - if(insptr > 0) + if(insPos[n] > 0) { - minptr = min(minptr, insptr); + minPtr = Util::Min(minPtr, insPos[n]); } - dwMemPos += 4; } - // Reading Sample Offsets - smppos.resize(itHeader.smpnum); - for(size_t n = 0; n < itHeader.smpnum; n++) + for(uint16 n = 0; n < fileHeader.smpnum; n++) { - if(4 > dwMemLength - dwMemPos) - return false; - DWORD smpptr = LittleEndian(*(DWORD *)(lpStream + dwMemPos)); - smppos[n] = smpptr; - if(smpptr > 0) + if(smpPos[n] > 0) { - minptr = min(minptr, smpptr); + minPtr = Util::Min(minPtr, smpPos[n]); } - dwMemPos += 4; } - // Reading Pattern Offsets - patpos.resize(itHeader.patnum); - for(size_t n = 0; n < itHeader.patnum; n++) + for(uint16 n = 0; n < fileHeader.patnum; n++) { - if(4 > dwMemLength - dwMemPos) - return false; - DWORD patptr = LittleEndian(*(DWORD *)(lpStream + dwMemPos)); - patpos[n] = patptr; - if(patptr > 0) + if(patPos[n] > 0) { - minptr = min(minptr, patptr); + minPtr = Util::Min(minPtr, patPos[n]); } - dwMemPos += 4; } - // Reading Patterns Offsets - if(patpos.size() > GetModSpecifications().patternsMax) + if(fileHeader.special & ITFileHeader::embedSongMessage) { - // Hack: Note user here if file contains more patterns than what can be read. -#ifdef MODPLUG_TRACKER - if(GetpModDoc() != nullptr) - { - CString str; - str.Format(str_PatternSetTruncationNote, patpos.size(), GetModSpecifications().patternsMax); - GetpModDoc()->AddToLog(str); - } -#endif // MODPLUG_TRACKER + minPtr = Util::Min(minPtr, fileHeader.msgoffset); } - // Reading Song Message - if(itHeader.special & ITFileHeader::embedSongMessage) - { - if(itHeader.msglength > 0 && itHeader.msglength <= dwMemLength && itHeader.msgoffset < (dwMemLength - itHeader.msglength)) - { - // Generally, IT files should use CR for line endings. However, ChibiTracker uses LF. One could do... - // if(itHeader.cwtv == 0x0214 && itHeader.cmwt == 0x0214 && itHeader.reserved == ITFileHeader::chibiMagic) --> Chibi detected. - // But we'll just use autodetection here: - ReadMessage(lpStream + itHeader.msgoffset, itHeader.msglength, leAutodetect); - } - minptr = min(minptr, itHeader.msgoffset); - } - // Reading IT Edit History Info // This is only supposed to be present if bit 1 of the special flags is set. // However, old versions of Schism and probably other trackers always set this bit // even if they don't write the edit history count. So we have to filter this out... // This is done by looking at the parapointers. If the history data end after // the first parapointer, we assume that it's actually no history data. - if(dwMemPos + 2 < dwMemLength && (itHeader.special & ITFileHeader::embedEditHistory)) + if(fileHeader.special & ITFileHeader::embedEditHistory) { - const size_t nflt = LittleEndianW(*((uint16*)(lpStream + dwMemPos))); - dwMemPos += 2; + const uint16 nflt = file.ReadUint16LE(); - if(nflt * sizeof(ITHistoryStruct) <= dwMemLength - dwMemPos && dwMemPos + nflt * 8 <= minptr) + if(file.CanRead(nflt * sizeof(ITHistoryStruct)) && file.GetPosition() + nflt * sizeof(ITHistoryStruct) <= minPtr) { #ifdef MODPLUG_TRACKER if(GetpModDoc() != nullptr) @@ -558,46 +510,40 @@ for(size_t n = 0; n < nflt; n++) { FileHistory mptHistory; - const ITHistoryStruct *itHistory = reinterpret_cast<const ITHistoryStruct *>(lpStream + dwMemPos); - itHistory->ConvertToMPT(mptHistory); + ITHistoryStruct itHistory; + file.Read(itHistory); + itHistory.ConvertToMPT(mptHistory); GetpModDoc()->GetFileHistory().push_back(mptHistory); - - dwMemPos += sizeof(ITHistoryStruct); } } else #endif // MODPLUG_TRACKER { - dwMemPos += nflt * sizeof(ITHistoryStruct); + file.Skip(nflt * sizeof(ITHistoryStruct)); } } else { // Oops, we were not supposed to read this. - dwMemPos -= 2; + file.SkipBack(2); } - } - // Another non-conforming application is unmo3 < v2.4.0.1, which doesn't set the special bit - // at all, but still writes the two edit history length bytes (zeroes)... - else if(dwMemPos + 2 < dwMemLength && itHeader.highlight_major == 0 && itHeader.highlight_minor == 0 && itHeader.cmwt == 0x0214 && itHeader.cwtv == 0x0214 && itHeader.reserved == 0 && (itHeader.special & (ITFileHeader::embedEditHistory | ITFileHeader::embedPatternHighlights)) == 0) + } else if(fileHeader.highlight_major == 0 && fileHeader.highlight_minor == 0 && fileHeader.cmwt == 0x0214 && fileHeader.cwtv == 0x0214 && fileHeader.reserved == 0 && (fileHeader.special & (ITFileHeader::embedEditHistory | ITFileHeader::embedPatternHighlights)) == 0) { - const size_t nflt = LittleEndianW(*((uint16*)(lpStream + dwMemPos))); - if(nflt == 0) + // Another non-conforming application is unmo3 < v2.4.0.1, which doesn't set the special bit + // at all, but still writes the two edit history length bytes (zeroes)... + if(file.ReadUint16LE() != 0) { - dwMemPos += 2; + // These were not zero bytes -> We're in the wrong place! + file.SkipBack(2); } } // Reading MIDI Output & Macros - if (m_SongFlags[SONG_EMBEDMIDICFG]) + if(m_SongFlags[SONG_EMBEDMIDICFG] && file.Read(m_MidiCfg)) { - if (dwMemPos + sizeof(MIDIMacroConfig) < dwMemLength) - { - memcpy(&m_MidiCfg, lpStream + dwMemPos, sizeof(MIDIMacroConfig)); m_MidiCfg.Sanitize(); - dwMemPos += sizeof(MIDIMacroConfig); - } } + // Ignore MIDI data. Fixes some files like denonde.it that were made with old versions of Impulse Tracker (which didn't support Zxx filters) and have Zxx effects in the patterns. - if (itHeader.cwtv < 0x0214) + if(fileHeader.cwtv < 0x0214) { MemsetZero(m_MidiCfg.szMidiSFXExt); MemsetZero(m_MidiCfg.szMidiZXXExt); @@ -605,333 +551,331 @@ } // Read pattern names: "PNAM" - const char *patNames = nullptr; - UINT patNamesLen = 0; - if ((dwMemPos + 8 < dwMemLength) && (*((DWORD *)(lpStream+dwMemPos)) == LittleEndian(magicPatternNames))) + FileReader patNames; + if(file.ReadMagic("PNAM")) { - patNamesLen = *((DWORD *)(lpStream + dwMemPos + 4)); - dwMemPos += 8; - if ((dwMemPos + patNamesLen <= dwMemLength) && (patNamesLen > 0)) - { - patNames = (char *)(lpStream + dwMemPos); - dwMemPos += patNamesLen; - } + patNames = file.GetChunk(file.ReadUint32LE()); } m_nChannels = GetModSpecifications().channelsMin; // Read channel names: "CNAM" - if ((dwMemPos + 8 < dwMemLength) && (*((DWORD *)(lpStream+dwMemPos)) == LittleEndian(magicChannelNames))) + if(file.ReadMagic("CNAM")) { - UINT len = *((DWORD *)(lpStream + dwMemPos + 4)); - dwMemPos += 8; - if ((dwMemPos + len <= dwMemLength) && (len <= MAX_BASECHANNELS * MAX_CHANNELNAME)) + FileReader chnNames = file.GetChunk(file.ReadUint32LE()); + const CHANNELINDEX readChns = Util::Min(MAX_BASECHANNELS, static_cast<CHANNELINDEX>(chnNames.GetLength() / MAX_CHANNELNAME)); + m_nChannels = readChns; + + for(CHANNELINDEX i = 0; i < readChns; i++) { - UINT n = len / MAX_CHANNELNAME; - if (n > m_nChannels) m_nChannels = n; - for (UINT i=0; i<n; i++) - { - memcpy(ChnSettings[i].szName, (lpStream + dwMemPos + i * MAX_CHANNELNAME), MAX_CHANNELNAME); - ChnSettings[i].szName[MAX_CHANNELNAME - 1] = 0; - } - dwMemPos += len; + chnNames.ReadString<StringFixer::maybeNullTerminated>(ChnSettings[i].szName, MAX_CHANNELNAME); } } + // Read mix plugins information - if (dwMemPos + 8 < dwMemLength) + if(file.BytesLeft() > 8) { - dwMemPos += LoadMixPlugins(lpStream+dwMemPos, dwMemLength-dwMemPos); + file.Skip(LoadMixPlugins(file.GetRawData(), file.BytesLeft())); } - //UINT npatterns = pifh->patnum; - UINT npatterns = patpos.size(); - - if (npatterns > GetModSpecifications().patternsMax) - npatterns = GetModSpecifications().patternsMax; - - // Checking for unused channels - for (UINT patchk=0; patchk<npatterns; patchk++) + // Read Song Message + if(fileHeader.special & ITFileHeader::embedSongMessage) { - if ((!patpos[patchk]) || ((DWORD)patpos[patchk] >= dwMemLength - 4)) - continue; - - UINT len = *((WORD *)(lpStream+patpos[patchk])); - UINT rows = *((WORD *)(lpStream+patpos[patchk]+2)); - - if(rows <= ModSpecs::itEx.patternRowsMax && rows > ModSpecs::it.patternRowsMax) + if(fileHeader.msglength > 0 && file.Seek(fileHeader.msgoffset)) { - //interpretModPlugMade = true; // Chibi also does this. - hasModPlugExtensions = true; + // Generally, IT files should use CR for line endings. However, ChibiTracker uses LF. One could do... + // if(itHeader.cwtv == 0x0214 && itHeader.cmwt == 0x0214 && itHeader.reserved == ITFileHeader::chibiMagic) --> Chibi detected. + // But we'll just use autodetection here: + ReadMessage(file, fileHeader.msglength, leAutodetect); } - - if ((rows < GetModSpecifications().patternRowsMin) || (rows > GetModSpecifications().patternRowsMax)) - continue; - - if (patpos[patchk]+8+len > dwMemLength) - continue; - - UINT i = 0; - const BYTE *p = lpStream+patpos[patchk]+8; - UINT nrow = 0; - - vector<BYTE> chnmask; - - while (nrow<rows) - { - if (i >= len) break; - BYTE b = p[i++]; // p is the bytestream offset at current pattern_position - if (!b) - { - nrow++; - continue; - } - - UINT ch = b & IT_bitmask_patternChanField_c; // 0x7f We have some data grab a byte keeping only 7 bits - if (ch) - ch = (ch - 1);// & IT_bitmask_patternChanMask_c; // 0x3f mask of the byte again, keeping only 6 bits - - if(ch >= chnmask.size()) - { - chnmask.resize(ch + 1, 0); - } - - if (b & IT_bitmask_patternChanEnabled_c) // 0x80 check if the upper bit is enabled. - { - if (i >= len) - break; - chnmask[ch] = p[i++]; // set the channel mask for this channel. - } - // Channel used - if (chnmask[ch] & 0x0F) // if this channel is used set m_nChannels - { -// -> CODE#0006 -// -> DESC="misc quantity changes" -// if ((ch >= m_nChannels) && (ch < 64)) m_nChannels = ch+1; - if ((ch >= m_nChannels) && (ch < MAX_BASECHANNELS)) m_nChannels = ch+1; -// -! BEHAVIOUR_CHANGE#0006 - } - // Now we actually update the pattern-row entry the note,instrument etc. - // Note - if (chnmask[ch] & 1) i++; - // Instrument - if (chnmask[ch] & 2) i++; - // Volume - if (chnmask[ch] & 4) i++; - // Effect - if (chnmask[ch] & 8) i += 2; - if (i >= len) break; - } } - // Reading Instruments m_nInstruments = 0; - if (itHeader.flags & ITFileHeader::instrumentMode) m_nInstruments = itHeader.insnum; - if (m_nInstruments >= MAX_INSTRUMENTS) m_nInstruments = MAX_INSTRUMENTS-1; - for (UINT nins=0; nins<m_nInstruments; nins++) + if(fileHeader.flags & ITFileHeader::instrumentMode) { - if ((inspos[nins] > 0) && (inspos[nins] <= dwMemLength - (itHeader.cmwt < 0x200 ? sizeof(ITOldInstrument) : sizeof(ITInstrument)))) + m_nInstruments = Util::Min(fileHeader.insnum, INSTRUMENTINDEX(MAX_INSTRUMENTS - 1)); + } + for(INSTRUMENTINDEX i = 0; i < GetNumInstruments(); i++) + { + if(insPos[i] > 0 && file.Seek(insPos[i]) && file.CanRead(fileHeader.cmwt < 0x200 ? sizeof(ITOldInstrument) : sizeof(ITInstrument))) { - ModInstrument *instrument = AllocateInstrument(nins + 1); + ModInstrument *instrument = AllocateInstrument(i + 1); if(instrument != nullptr) { - ITInstrToMPT(lpStream + inspos[nins], instrument, itHeader.cmwt, dwMemLength - inspos[nins]); - instrument->midiPWD = itHeader.pwd; + ITInstrToMPT(file, *instrument, fileHeader.cmwt); + // MIDI Pitch Wheel Depth is a global setting in IT. Apply it to all instruments. + instrument->midiPWD = fileHeader.pwd; } } } -// -> CODE#0027 -// -> DESC="per-instrument volume ramping setup (refered as attack)" // In order to properly compute the position, in file, of eventual extended settings // such as "attack" we need to keep the "real" size of the last sample as those extra // setting will follow this sample in the file - UINT lastSampleOffset = 0; - if(itHeader.smpnum > 0) + FileReader::off_t lastSampleOffset = 0; + if(fileHeader.smpnum > 0) { - lastSampleOffset = smppos[itHeader.smpnum - 1] + sizeof(ITSample); + lastSampleOffset = smpPos[fileHeader.smpnum - 1] + sizeof(ITSample); } -// -! NEW_FEATURE#0027 // Reading Samples - m_nSamples = min(itHeader.smpnum, MAX_SAMPLES - 1); - for (UINT nsmp = 0; nsmp < m_nSamples; nsmp++) if ((smppos[nsmp]) && (smppos[nsmp] <= dwMemLength - sizeof(ITSample))) + m_nSamples = Util::Min(fileHeader.smpnum, SAMPLEINDEX(MAX_SAMPLES - 1)); + for(SAMPLEINDEX i = 0; i < GetNumSamples(); i++) { - ITSample *pis = (ITSample *)(lpStream+smppos[nsmp]); - if(pis->id == LittleEndian(ITSample::magic)) + ITSample sampleHeader; + if(smpPos[i] > 0 && file.Seek(smpPos[i]) && file.ReadConvertEndianness(sampleHeader)) { - size_t sampleOffset = pis->ConvertToMPT(Samples[nsmp + 1]); + if(sample... [truncated message content] |