From ac87bfc370ec15c9c81f8738659fb2582b14b792 Mon Sep 17 00:00:00 2001 From: Jeremy Simon Date: Thu, 28 Feb 2002 21:10:42 +0000 Subject: adding modplug Original commit message from CVS: adding modplug --- gst/modplug/libmodplug/load_mt2.cpp | 635 ++++++++++++++++++++++++++++++++++++ 1 file changed, 635 insertions(+) create mode 100644 gst/modplug/libmodplug/load_mt2.cpp (limited to 'gst/modplug/libmodplug/load_mt2.cpp') diff --git a/gst/modplug/libmodplug/load_mt2.cpp b/gst/modplug/libmodplug/load_mt2.cpp new file mode 100644 index 00000000..563839f1 --- /dev/null +++ b/gst/modplug/libmodplug/load_mt2.cpp @@ -0,0 +1,635 @@ +#include "stdafx.h" +#include "sndfile.h" + +//#define MT2DEBUG + +#pragma pack(1) + +typedef struct _MT2FILEHEADER +{ + DWORD dwMT20; // 0x3032544D "MT20" + DWORD dwSpecial; + WORD wVersion; + CHAR szTrackerName[32]; // "MadTracker 2.0" + CHAR szSongName[64]; + WORD nOrders; + WORD wRestart; + WORD wPatterns; + WORD wChannels; + WORD wSamplesPerTick; + BYTE bTicksPerLine; + BYTE bLinesPerBeat; + DWORD fulFlags; // b0=packed patterns + WORD wInstruments; + WORD wSamples; + BYTE Orders[256]; +} MT2FILEHEADER; + +typedef struct _MT2PATTERN +{ + WORD wLines; + DWORD wDataLen; +} MT2PATTERN; + +typedef struct _MT2COMMAND +{ + BYTE note; // 0=nothing, 97=note off + BYTE instr; + BYTE vol; + BYTE pan; + BYTE fxcmd; + BYTE fxparam1; + BYTE fxparam2; +} MT2COMMAND; + +typedef struct _MT2DRUMSDATA +{ + WORD wDrumPatterns; + WORD wDrumSamples[8]; + BYTE DrumPatternOrder[256]; +} MT2DRUMSDATA; + +typedef struct _MT2AUTOMATION +{ + DWORD dwFlags; + DWORD dwEffectId; + DWORD nEnvPoints; +} MT2AUTOMATION; + +typedef struct _MT2INSTRUMENT +{ + CHAR szName[32]; + DWORD dwDataLen; + WORD wSamples; + BYTE GroupsMapping[96]; + BYTE bVibType; + BYTE bVibSweep; + BYTE bVibDepth; + BYTE bVibRate; + WORD wFadeOut; + WORD wNNA; + WORD wInstrFlags; + WORD wEnvFlags1; + WORD wEnvFlags2; +} MT2INSTRUMENT; + +typedef struct _MT2ENVELOPE +{ + BYTE nFlags; + BYTE nPoints; + BYTE nSustainPos; + BYTE nLoopStart; + BYTE nLoopEnd; + BYTE bReserved[3]; + BYTE EnvData[64]; +} MT2ENVELOPE; + +typedef struct _MT2SYNTH +{ + BYTE nSynthId; + BYTE nFxId; + WORD wCutOff; + BYTE nResonance; + BYTE nAttack; + BYTE nDecay; + BYTE bReserved[25]; +} MT2SYNTH; + +typedef struct _MT2SAMPLE +{ + CHAR szName[32]; + DWORD dwDataLen; + DWORD dwLength; + DWORD dwFrequency; + BYTE nQuality; + BYTE nChannels; + BYTE nFlags; + BYTE nLoop; + DWORD dwLoopStart; + DWORD dwLoopEnd; + WORD wVolume; + BYTE nPan; + BYTE nBaseNote; + WORD wSamplesPerBeat; +} MT2SAMPLE; + +typedef struct _MT2GROUP +{ + BYTE nSmpNo; + BYTE nVolume; // 0-128 + BYTE nFinePitch; + BYTE Reserved[5]; +} MT2GROUP; + +#pragma pack() + + +static VOID ConvertMT2Command(CSoundFile *that, MODCOMMAND *m, MT2COMMAND *p) +//--------------------------------------------------------------------------- +{ + // Note + m->note = 0; + if (p->note) m->note = (p->note > 96) ? 0xFF : p->note+12; + // Instrument + m->instr = p->instr; + // Volume Column + if ((p->vol >= 0x10) && (p->vol <= 0x90)) + { + m->volcmd = VOLCMD_VOLUME; + m->vol = (p->vol - 0x10) >> 1; + } else + if ((p->vol >= 0xA0) && (p->vol <= 0xAF)) + { + m->volcmd = VOLCMD_VOLSLIDEDOWN; + m->vol = (p->vol & 0x0f); + } else + if ((p->vol >= 0xB0) && (p->vol <= 0xBF)) + { + m->volcmd = VOLCMD_VOLSLIDEUP; + m->vol = (p->vol & 0x0f); + } else + if ((p->vol >= 0xC0) && (p->vol <= 0xCF)) + { + m->volcmd = VOLCMD_FINEVOLDOWN; + m->vol = (p->vol & 0x0f); + } else + if ((p->vol >= 0xD0) && (p->vol <= 0xDF)) + { + m->volcmd = VOLCMD_FINEVOLUP; + m->vol = (p->vol & 0x0f); + } else + { + m->volcmd = 0; + m->vol = 0; + } + // Effects + m->command = 0; + m->param = 0; + if ((p->fxcmd) || (p->fxparam1) || (p->fxparam2)) + { + if (!p->fxcmd) + { + m->command = p->fxparam2; + m->param = p->fxparam1; + that->ConvertModCommand(m); + } else + { + // TODO: MT2 Effects + } + } +} + + +BOOL CSoundFile::ReadMT2(LPCBYTE lpStream, DWORD dwMemLength) +//----------------------------------------------------------- +{ + MT2FILEHEADER *pfh = (MT2FILEHEADER *)lpStream; + DWORD dwMemPos, dwDrumDataPos, dwExtraDataPos; + UINT nDrumDataLen, nExtraDataLen; + MT2DRUMSDATA *pdd; + MT2INSTRUMENT *InstrMap[255]; + MT2SAMPLE *SampleMap[256]; + + if ((!lpStream) || (dwMemLength < sizeof(MT2FILEHEADER)) + || (pfh->dwMT20 != 0x3032544D) + || (pfh->wVersion < 0x0200) || (pfh->wVersion >= 0x0300) + || (pfh->wChannels < 4) || (pfh->wChannels > 64)) return FALSE; + pdd = NULL; + m_nType = MOD_TYPE_MT2; + m_nChannels = pfh->wChannels; + m_nRestartPos = pfh->wRestart; + m_nDefaultSpeed = pfh->bTicksPerLine; + m_nDefaultTempo = 125; + if ((pfh->wSamplesPerTick > 100) && (pfh->wSamplesPerTick < 5000)) + { + m_nDefaultTempo = 110250 / pfh->wSamplesPerTick; + } + for (UINT iOrd=0; iOrdnOrders) ? pfh->Orders[iOrd] : 0xFF); + } + memcpy(m_szNames[0], pfh->szSongName, 32); + m_szNames[0][31] = 0; + dwMemPos = sizeof(MT2FILEHEADER); + nDrumDataLen = *(WORD *)(lpStream + dwMemPos); + dwDrumDataPos = dwMemPos + 2; + if (nDrumDataLen >= 2) pdd = (MT2DRUMSDATA *)(lpStream+dwDrumDataPos); + dwMemPos += 2 + nDrumDataLen; +#ifdef MT2DEBUG + + Log("MT2 v%03X: \"%s\" (flags=%04X)\n", pfh->wVersion, m_szNames[0], pfh->fulFlags); + Log("%d Channels, %d Patterns, %d Instruments, %d Samples\n", pfh->wChannels, pfh->wPatterns, pfh->wInstruments, pfh->wSamples); + Log("Drum Data: %d bytes @%04X\n", nDrumDataLen, dwDrumDataPos); +#endif + if (dwMemPos >= dwMemLength-12) return TRUE; + if (!*(DWORD *)(lpStream+dwMemPos)) dwMemPos += 4; + if (!*(DWORD *)(lpStream+dwMemPos)) dwMemPos += 4; + nExtraDataLen = *(DWORD *)(lpStream+dwMemPos); + dwExtraDataPos = dwMemPos + 4; + dwMemPos += 4; +#ifdef MT2DEBUG + Log("Extra Data: %d bytes @%04X\n", nExtraDataLen, dwExtraDataPos); +#endif + if (dwMemPos + nExtraDataLen >= dwMemLength) return TRUE; + while (dwMemPos+8 < dwExtraDataPos + nExtraDataLen) + { + DWORD dwId = *(DWORD *)(lpStream+dwMemPos); + DWORD dwLen = *(DWORD *)(lpStream+dwMemPos+4); + dwMemPos += 8; + if (dwMemPos + dwLen > dwMemLength) return TRUE; +#ifdef MT2DEBUG + CHAR s[5]; + memcpy(s, &dwId, 4); + s[4] = 0; + Log("pos=0x%04X: %s: %d bytes\n", dwMemPos-8, s, dwLen); +#endif + switch(dwId) + { + // MSG + case 0x0047534D: + if ((dwLen > 3) && (!m_lpszSongComments)) + { + DWORD nTxtLen = dwLen; + if (nTxtLen > 32000) nTxtLen = 32000; + m_lpszSongComments = new char[nTxtLen]; // changed from CHAR + if (m_lpszSongComments) + { + memcpy(m_lpszSongComments, lpStream+dwMemPos+1, nTxtLen-1); + m_lpszSongComments[nTxtLen-1] = 0; + } + } + break; + // SUM -> author name (or "Unregistered") + // TMAP + // TRKS + case 0x534b5254: + break; + } + dwMemPos += dwLen; + } + // Load Patterns + dwMemPos = dwExtraDataPos + nExtraDataLen; + for (UINT iPat=0; iPatwPatterns; iPat++) if (dwMemPos < dwMemLength-6) + { + MT2PATTERN *pmp = (MT2PATTERN *)(lpStream+dwMemPos); + UINT wDataLen = (pmp->wDataLen + 1) & ~1; + dwMemPos += 6; + if (dwMemPos + wDataLen > dwMemLength) break; + UINT nLines = pmp->wLines; + if ((iPat < MAX_PATTERNS) && (nLines > 0) && (nLines <= 256)) + { + #ifdef MT2DEBUG + Log("Pattern #%d @%04X: %d lines, %d bytes\n", iPat, dwMemPos-6, nLines, pmp->wDataLen); + #endif + PatternSize[iPat] = nLines; + Patterns[iPat] = AllocatePattern(nLines, m_nChannels); + if (!Patterns[iPat]) return TRUE; + MODCOMMAND *m = Patterns[iPat]; + UINT len = wDataLen; + if (pfh->fulFlags & 1) // Packed Patterns + { + BYTE *p = (BYTE *)(lpStream+dwMemPos); + UINT pos = 0, row=0, ch=0; + while (pos < len) + { + MT2COMMAND cmd; + UINT infobyte = p[pos++]; + UINT rptcount = 0; + if (infobyte == 0xff) + { + rptcount = p[pos++]; + infobyte = p[pos++]; + #if 0 + Log("(%d.%d) FF(%02X).%02X\n", row, ch, rptcount, infobyte); + } else + { + Log("(%d.%d) %02X\n", row, ch, infobyte); + #endif + } + if (infobyte & 0x7f) + { + UINT patpos = row*m_nChannels+ch; + cmd.note = cmd.instr = cmd.vol = cmd.pan = cmd.fxcmd = cmd.fxparam1 = cmd.fxparam2 = 0; + if (infobyte & 1) cmd.note = p[pos++]; + if (infobyte & 2) cmd.instr = p[pos++]; + if (infobyte & 4) cmd.vol = p[pos++]; + if (infobyte & 8) cmd.pan = p[pos++]; + if (infobyte & 16) cmd.fxcmd = p[pos++]; + if (infobyte & 32) cmd.fxparam1 = p[pos++]; + if (infobyte & 64) cmd.fxparam2 = p[pos++]; + #ifdef MT2DEBUG + if (cmd.fxcmd) + { + Log("(%d.%d) MT2 FX=%02X.%02X.%02X\n", row, ch, cmd.fxcmd, cmd.fxparam1, cmd.fxparam2); + } + #endif + ConvertMT2Command(this, &m[patpos], &cmd); + } + row += rptcount+1; + while (row >= nLines) { row-=nLines; ch++; } + if (ch >= m_nChannels) break; + } + } else + { + MT2COMMAND *p = (MT2COMMAND *)(lpStream+dwMemPos); + UINT n = 0; + while ((len > sizeof(MT2COMMAND)) && (n < m_nChannels*nLines)) + { + ConvertMT2Command(this, m, p); + len -= sizeof(MT2COMMAND); + n++; + p++; + m++; + } + } + } + dwMemPos += wDataLen; + } + // Skip Drum Patterns + if (pdd) + { + #ifdef MT2DEBUG + Log("%d Drum Patterns at offset 0x%08X\n", pdd->wDrumPatterns, dwMemPos); + #endif + for (UINT iDrm=0; iDrmwDrumPatterns; iDrm++) + { + if (dwMemPos > dwMemLength-2) return TRUE; + UINT nLines = *(WORD *)(lpStream+dwMemPos); + #ifdef MT2DEBUG + if (nLines != 64) Log("Drum Pattern %d: %d Lines @%04X\n", iDrm, nLines, dwMemPos); + #endif + dwMemPos += 2 + nLines * 32; + } + } + // Automation + if (pfh->fulFlags & 2) + { + #ifdef MT2DEBUG + Log("Automation at offset 0x%08X\n", dwMemPos); + #endif + UINT nAutoCount = m_nChannels; + if (pfh->fulFlags & 0x10) nAutoCount++; // Master Automation + if ((pfh->fulFlags & 0x08) && (pdd)) nAutoCount += 8; // Drums Automation + nAutoCount *= pfh->wPatterns; + for (UINT iAuto=0; iAuto= dwMemLength) return TRUE; + MT2AUTOMATION *pma = (MT2AUTOMATION *)(lpStream+dwMemPos); + dwMemPos += (pfh->wVersion <= 0x201) ? 4 : 8; + for (UINT iEnv=0; iEnv<14; iEnv++) + { + if (pma->dwFlags & (1 << iEnv)) + { + #ifdef MT2DEBUG + UINT nPoints = *(DWORD *)(lpStream+dwMemPos); + Log(" Env[%d/%d] %04X @%04X: %d points\n", iAuto, nAutoCount, 1 << iEnv, dwMemPos-8, nPoints); + #endif + dwMemPos += 260; + } + } + } + } + // Load Instruments +#ifdef MT2DEBUG + Log("Loading instruments at offset 0x%08X\n", dwMemPos); +#endif + memset(InstrMap, 0, sizeof(InstrMap)); + m_nInstruments = (pfh->wInstruments < MAX_INSTRUMENTS) ? pfh->wInstruments : MAX_INSTRUMENTS-1; + for (UINT iIns=1; iIns<=255; iIns++) + { + if (dwMemPos+36 > dwMemLength) return TRUE; + MT2INSTRUMENT *pmi = (MT2INSTRUMENT *)(lpStream+dwMemPos); + INSTRUMENTHEADER *penv = NULL; + if (iIns <= m_nInstruments) + { + penv = new INSTRUMENTHEADER; + Headers[iIns] = penv; + if (penv) + { + memset(penv, 0, sizeof(INSTRUMENTHEADER)); + memcpy(penv->name, pmi->szName, 32); + penv->nGlobalVol = 64; + penv->nPan = 128; + for (UINT i=0; i<120; i++) + { + penv->NoteMap[i] = i+1; + } + } + } + #ifdef MT2DEBUG + if (iIns <= pfh->wInstruments) Log(" Instrument #%d at offset %04X: %d bytes\n", iIns, dwMemPos, pmi->dwDataLen); + #endif + if (((LONG)pmi->dwDataLen > 0) && (dwMemPos + pmi->dwDataLen + 40 <= dwMemLength)) + { + InstrMap[iIns-1] = pmi; + if (penv) + { + penv->nFadeOut = pmi->wFadeOut; + penv->nNNA = pmi->wNNA & 3; + penv->nDCT = (pmi->wNNA>>8) & 3; + penv->nDNA = (pmi->wNNA>>12) & 3; + MT2ENVELOPE *pehdr[4]; + WORD *pedata[4]; + if (pfh->wVersion <= 0x201) + { + DWORD dwEnvPos = dwMemPos + sizeof(MT2INSTRUMENT) - 4; + pehdr[0] = (MT2ENVELOPE *)(lpStream+dwEnvPos); + pehdr[1] = (MT2ENVELOPE *)(lpStream+dwEnvPos+8); + pehdr[2] = pehdr[3] = NULL; + pedata[0] = (WORD *)(lpStream+dwEnvPos+16); + pedata[1] = (WORD *)(lpStream+dwEnvPos+16+64); + pedata[2] = pedata[3] = NULL; + } else + { + DWORD dwEnvPos = dwMemPos + sizeof(MT2INSTRUMENT); + for (UINT i=0; i<4; i++) + { + if (pmi->wEnvFlags1 & (1<EnvData; + dwEnvPos += sizeof(MT2ENVELOPE); + } else + { + pehdr[i] = NULL; + pedata[i] = NULL; + } + } + } + // Load envelopes + for (UINT iEnv=0; iEnv<4; iEnv++) if (pehdr[iEnv]) + { + MT2ENVELOPE *pme = pehdr[iEnv]; + WORD *pEnvPoints = NULL; + BYTE *pEnvData = NULL; + #ifdef MT2DEBUG + Log(" Env %d.%d @%04X: %d points\n", iIns, iEnv, (UINT)(((BYTE *)pme)-lpStream), pme->nPoints); + #endif + switch(iEnv) + { + // Volume Envelope + case 0: + if (pme->nFlags & 1) penv->dwFlags |= ENV_VOLUME; + if (pme->nFlags & 2) penv->dwFlags |= ENV_VOLSUSTAIN; + if (pme->nFlags & 4) penv->dwFlags |= ENV_VOLLOOP; + penv->nVolEnv = (pme->nPoints > 16) ? 16 : pme->nPoints; + penv->nVolSustainBegin = penv->nVolSustainEnd = pme->nSustainPos; + penv->nVolLoopStart = pme->nLoopStart; + penv->nVolLoopEnd = pme->nLoopEnd; + pEnvPoints = penv->VolPoints; + pEnvData = penv->VolEnv; + break; + + // Panning Envelope + case 1: + if (pme->nFlags & 1) penv->dwFlags |= ENV_PANNING; + if (pme->nFlags & 2) penv->dwFlags |= ENV_PANSUSTAIN; + if (pme->nFlags & 4) penv->dwFlags |= ENV_PANLOOP; + penv->nPanEnv = (pme->nPoints > 16) ? 16 : pme->nPoints; + penv->nPanSustainBegin = penv->nPanSustainEnd = pme->nSustainPos; + penv->nPanLoopStart = pme->nLoopStart; + penv->nPanLoopEnd = pme->nLoopEnd; + pEnvPoints = penv->PanPoints; + pEnvData = penv->PanEnv; + break; + + // Pitch/Filter envelope + default: + if (pme->nFlags & 1) penv->dwFlags |= (iEnv==3) ? (ENV_PITCH|ENV_FILTER) : ENV_PITCH; + if (pme->nFlags & 2) penv->dwFlags |= ENV_PITCHSUSTAIN; + if (pme->nFlags & 4) penv->dwFlags |= ENV_PITCHLOOP; + penv->nPitchEnv = (pme->nPoints > 16) ? 16 : pme->nPoints; + penv->nPitchSustainBegin = penv->nPitchSustainEnd = pme->nSustainPos; + penv->nPitchLoopStart = pme->nLoopStart; + penv->nPitchLoopEnd = pme->nLoopEnd; + pEnvPoints = penv->PitchPoints; + pEnvData = penv->PitchEnv; + } + // Envelope data + if ((pEnvPoints) && (pEnvData) && (pedata[iEnv])) + { + WORD *psrc = pedata[iEnv]; + for (UINT i=0; i<16; i++) + { + pEnvPoints[i] = psrc[i*2]; + pEnvData[i] = (BYTE)psrc[i*2+1]; + } + } + } + } + dwMemPos += pmi->dwDataLen + 36; + if (pfh->wVersion > 0x201) dwMemPos += 4; // ? + } else + { + dwMemPos += 36; + } + } +#ifdef MT2DEBUG + Log("Loading samples at offset 0x%08X\n", dwMemPos); +#endif + memset(SampleMap, 0, sizeof(SampleMap)); + m_nSamples = (pfh->wSamples < MAX_SAMPLES) ? pfh->wSamples : MAX_SAMPLES-1; + for (UINT iSmp=1; iSmp<=256; iSmp++) + { + if (dwMemPos+36 > dwMemLength) return TRUE; + MT2SAMPLE *pms = (MT2SAMPLE *)(lpStream+dwMemPos); + #ifdef MT2DEBUG + if (iSmp <= m_nSamples) Log(" Sample #%d at offset %04X: %d bytes\n", iSmp, dwMemPos, pms->dwDataLen); + #endif + if (iSmp < MAX_SAMPLES) + { + memcpy(m_szNames[iSmp], pms->szName, 32); + } + if (pms->dwDataLen > 0) + { + SampleMap[iSmp-1] = pms; + if (iSmp < MAX_SAMPLES) + { + MODINSTRUMENT *psmp = &Ins[iSmp]; + psmp->nGlobalVol = 64; + psmp->nVolume = (pms->wVolume >> 7); + psmp->nPan = (pms->nPan == 0x80) ? 128 : (pms->nPan^0x80); + psmp->nLength = pms->dwLength; + psmp->nC4Speed = pms->dwFrequency; + psmp->nLoopStart = pms->dwLoopStart; + psmp->nLoopEnd = pms->dwLoopEnd; + FrequencyToTranspose(psmp); + psmp->RelativeTone -= pms->nBaseNote - 49; + psmp->nC4Speed = TransposeToFrequency(psmp->RelativeTone, psmp->nFineTune); + if (pms->nQuality == 2) { psmp->uFlags |= CHN_16BIT; psmp->nLength >>= 1; } + if (pms->nChannels == 2) { psmp->nLength >>= 1; } + if (pms->nLoop == 1) psmp->uFlags |= CHN_LOOP; + if (pms->nLoop == 2) psmp->uFlags |= CHN_LOOP|CHN_PINGPONGLOOP; + } + dwMemPos += pms->dwDataLen + 36; + } else + { + dwMemPos += 36; + } + } +#ifdef MT2DEBUG + Log("Loading groups at offset 0x%08X\n", dwMemPos); +#endif + for (UINT iMap=0; iMap<255; iMap++) if (InstrMap[iMap]) + { + if (dwMemPos+8 > dwMemLength) return TRUE; + MT2INSTRUMENT *pmi = InstrMap[iMap]; + INSTRUMENTHEADER *penv = NULL; + if (iMapwSamples; iGrp++) + { + if (penv) + { + MT2GROUP *pmg = (MT2GROUP *)(lpStream+dwMemPos); + for (UINT i=0; i<96; i++) + { + if (pmi->GroupsMapping[i] == iGrp) + { + UINT nSmp = pmg->nSmpNo+1; + penv->Keyboard[i+12] = (BYTE)nSmp; + if (nSmp <= m_nSamples) + { + Ins[nSmp].nVibType = pmi->bVibType; + Ins[nSmp].nVibSweep = pmi->bVibSweep; + Ins[nSmp].nVibDepth = pmi->bVibDepth; + Ins[nSmp].nVibRate = pmi->bVibRate; + } + } + } + } + dwMemPos += 8; + } + } +#ifdef MT2DEBUG + Log("Loading sample data at offset 0x%08X\n", dwMemPos); +#endif + for (UINT iData=0; iData<256; iData++) if ((iData < m_nSamples) && (SampleMap[iData])) + { + MT2SAMPLE *pms = SampleMap[iData]; + MODINSTRUMENT *psmp = &Ins[iData+1]; + if (!(pms->nFlags & 5)) + { + if (psmp->nLength > 0) + { + #ifdef MT2DEBUG + Log(" Reading sample #%d at offset 0x%04X (len=%d)\n", iData+1, dwMemPos, psmp->nLength); + #endif + UINT rsflags; + + if (pms->nChannels == 2) + rsflags = (psmp->uFlags & CHN_16BIT) ? RS_STPCM16D : RS_STPCM8D; + else + rsflags = (psmp->uFlags & CHN_16BIT) ? RS_PCM16D : RS_PCM8D; + + dwMemPos += ReadSample(psmp, rsflags, (LPCSTR)(lpStream+dwMemPos), dwMemLength-dwMemPos); + } + } else + if (dwMemPos+4 < dwMemLength) + { + UINT nNameLen = *(DWORD *)(lpStream+dwMemPos); + dwMemPos += nNameLen + 16; + } + if (dwMemPos+4 >= dwMemLength) break; + } + return TRUE; +} -- cgit v1.2.1