summaryrefslogtreecommitdiff
path: root/audio/stymulator/files/patch-stsoundlib_Ymload.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'audio/stymulator/files/patch-stsoundlib_Ymload.cpp')
-rw-r--r--audio/stymulator/files/patch-stsoundlib_Ymload.cpp647
1 files changed, 647 insertions, 0 deletions
diff --git a/audio/stymulator/files/patch-stsoundlib_Ymload.cpp b/audio/stymulator/files/patch-stsoundlib_Ymload.cpp
new file mode 100644
index 000000000000..e3b1d0dfbc49
--- /dev/null
+++ b/audio/stymulator/files/patch-stsoundlib_Ymload.cpp
@@ -0,0 +1,647 @@
+--- stsoundlib/Ymload.cpp.orig 2016-07-26 16:04:42 UTC
++++ stsoundlib/Ymload.cpp
+@@ -51,61 +51,98 @@ static void signeSample(ymu8 *ptr,yms32
+ }
+ }
+
+-char *mstrdup(char *in)
++void myFree(void **pPtr)
++{
++ if (*pPtr) free(*pPtr);
++ *pPtr = NULL;
++}
++
++char *mstrdup(const char *in)
+ {
+ char *out = (char*)malloc(strlen(in)+1);
+ if (out) strcpy(out,in);
+ return out;
+ }
+
+-ymu32 readMotorolaDword(ymu8 **ptr)
++ymu32 readMotorolaDword(ymu8 **ptr, ymint *ptr_size)
+ {
+-ymu32 n;
++ymu32 n = 0;
+ ymu8 *p = *ptr;
+-
+- n = (p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3];
+- p+=4;
+- *ptr = p;
++ if (*ptr_size>=4)
++ {
++ n = (p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3];
++ p+=4;
++ *ptr = p;
++ }
++ (*ptr_size)+=4;
+ return n;
+ }
+
+-ymu16 readMotorolaWord(ymu8 **ptr)
++ymu16 readMotorolaWord(ymu8 **ptr, ymint *ptr_size)
+ {
+-ymu16 n;
++ymu16 n = 0;
+ ymu8 *p = *ptr;
+-
+- n = (p[0]<<8)|p[1];
+- p+=2;
+- *ptr = p;
++ if (*ptr_size>=2)
++ {
++ n = (p[0]<<8)|p[1];
++ p+=2;
++ *ptr = p;
++ }
++ (*ptr_size)+=2;
+ return n;
+ }
+
+-ymchar *readNtString(ymchar **ptr)
++ymchar *readNtString(ymchar **ptr, ymint *ptr_size)
+ {
+ ymchar *p;
++ymint len = 0;
+
+- p = mstrdup(*ptr);
+- (*ptr) += strlen(*ptr)+1;
++ if (*ptr_size<=0)
++ {
++ (*ptr_size)-=1;
++ return mstrdup("");
++ }
++ p=*ptr;
++ while(!*p)
++ {
++ p++;
++ ptr_size--;
++ len++;
++ if (*ptr_size==0)
++ {
++ (*ptr_size)-=1;
++ return mstrdup("");
++ }
++ }
++
++ p = mstrdup(*ptr);
++ (*ptr) += len+1;
+ return p;
+ }
+
+-yms32 ReadLittleEndian32(ymu8 *pLittle)
++yms32 ReadLittleEndian32(ymu8 *pLittle, ymint ptr_size)
+ {
+- yms32 v = ( (pLittle[0]<<0) |
++ yms32 v = 0;
++ if (ptr_size>=4)
++ {
++ v = ( (pLittle[0]<<0) |
+ (pLittle[1]<<8) |
+ (pLittle[2]<<16) |
+ (pLittle[3]<<24));
+-
++ }
+ return v;
+ }
+
+-yms32 ReadBigEndian32(ymu8 *pBig)
++yms32 ReadBigEndian32(ymu8 *pBig, ymint ptr_size)
+ {
+- yms32 v = ( (pBig[0]<<24) |
++ yms32 v = 0;
++ if (ptr_size>=4)
++ {
++ v = ( (pBig[0]<<24) |
+ (pBig[1]<<16) |
+ (pBig[2]<<8) |
+- (pBig[3]<<0));
+-
++ (pBig[3]<<0));
++ }
+ return v;
+ }
+
+@@ -114,6 +151,13 @@ unsigned char *CYmMusic::depackFile(void
+ lzhHeader_t *pHeader;
+ ymu8 *pNew;
+ ymu8 *pSrc;
++ ymint ptr_left = fileSize;
++ ymint dummy;
++
++ if (ptr_left < (ymint)sizeof(lzhHeader_t))
++ {
++ return pBigMalloc;
++ }
+
+ pHeader = (lzhHeader_t*)pBigMalloc;
+
+@@ -123,8 +167,6 @@ unsigned char *CYmMusic::depackFile(void
+ return pBigMalloc;
+ }
+
+- fileSize = (ymu32)-1;
+-
+ if (pHeader->level != 0) // NOTE: Endianness works because value is 0
+ { // Compression LH5, header !=0 : Error.
+ free(pBigMalloc);
+@@ -133,7 +175,8 @@ unsigned char *CYmMusic::depackFile(void
+ return NULL;
+ }
+
+- fileSize = ReadLittleEndian32((ymu8*)&pHeader->original);
++ dummy = 4;
++ fileSize = ReadLittleEndian32((ymu8*)&pHeader->original, dummy);
+ pNew = (ymu8*)malloc(fileSize);
+ if (!pNew)
+ {
+@@ -144,10 +187,20 @@ unsigned char *CYmMusic::depackFile(void
+ }
+
+ pSrc = pBigMalloc+sizeof(lzhHeader_t)+pHeader->name_lenght; // NOTE: Endianness works because name_lenght is a byte
++ ptr_left -= sizeof(lzhHeader_t)+pHeader->name_lenght;
+
+ pSrc += 2; // skip CRC16
++ ptr_left -= 2;
+
+- const int packedSize = ReadLittleEndian32((ymu8*)&pHeader->packed);
++ dummy = 4;
++ const int packedSize = ReadLittleEndian32((ymu8*)&pHeader->packed, dummy);
++
++ if (packedSize > ptr_left)
++ {
++ setLastError("File too small");
++ free(pNew);
++ return pBigMalloc;
++ }
+
+ // alloc space for depacker and depack data
+ CLzhDepacker *pDepacker = new CLzhDepacker;
+@@ -229,19 +282,29 @@ ymbool CYmMusic::ymDecode(void)
+ {
+ ymu8 *pUD;
+ ymu8 *ptr;
++ ymint ptr_size = fileSize;
+ ymint skip;
+ ymint i;
+ ymu32 sampleSize;
+ yms32 tmp;
+ ymu32 id;
+-
+
+- id = ReadBigEndian32((unsigned char*)pBigMalloc);
++ if (ptr_size < 4)
++ {
++ setLastError("File too small");
++ return YMFALSE;
++ }
++ id = ReadBigEndian32((unsigned char*)pBigMalloc, ptr_size);
+ switch (id)
+ {
+- case 'YM2!': // MADMAX specific.
++ case 0x594d3221 /*'YM2!'*/: // MADMAX specific.
+ songType = YM_V2;
+ nbFrame = (fileSize-4)/14;
++ if (nbFrame == 0)
++ {
++ setLastError("No frames in file");
++ return YMFALSE;
++ }
+ loopFrame = 0;
+ ymChip.setClock(ATARI_CLOCK);
+ setPlayerRate(50);
+@@ -256,9 +319,14 @@ ymbool CYmMusic::ymDecode(void)
+ pSongPlayer = mstrdup("YM-Chip driver.");
+ break;
+
+- case 'YM3!': // Standart YM-Atari format.
++ case 0x594d3321 /*'YM3!'*/: // Standart YM-Atari format.
+ songType = YM_V3;
+ nbFrame = (fileSize-4)/14;
++ if (nbFrame == 0)
++ {
++ setLastError("No frames in file");
++ return YMFALSE;
++ }
+ loopFrame = 0;
+ ymChip.setClock(ATARI_CLOCK);
+ setPlayerRate(50);
+@@ -273,11 +341,24 @@ ymbool CYmMusic::ymDecode(void)
+ pSongPlayer = mstrdup("YM-Chip driver.");
+ break;
+
+- case 'YM3b': // Standart YM-Atari format + Loop info.
++ case 0x594d3362 /*'YM3b'*/: // Standart YM-Atari format + Loop info.
++ if (ptr_size < 4)
++ {
++ setLastError("File too small");
++ return YMFALSE;
++ }
+ pUD = (ymu8*)(pBigMalloc+fileSize-4);
+ songType = YM_V3;
+- nbFrame = (fileSize-4)/14;
+- loopFrame = ReadLittleEndian32(pUD);
++ nbFrame = (fileSize-8)/14;
++ if (nbFrame == 0)
++ {
++ setLastError("No frames in file");
++ return YMFALSE;
++ }
++ {
++ ymint dummy = 4;
++ loopFrame = ReadLittleEndian32(pUD, dummy);
++ }
+ ymChip.setClock(ATARI_CLOCK);
+ setPlayerRate(50);
+ pDataStream = pBigMalloc+4;
+@@ -291,35 +372,62 @@ ymbool CYmMusic::ymDecode(void)
+ pSongPlayer = mstrdup("YM-Chip driver.");
+ break;
+
+- case 'YM4!': // Extended ATARI format.
++ case 0x594d3421 /*'YM4!'*/: // Extended ATARI format.
+ setLastError("No more YM4! support. Use YM5! format.");
+ return YMFALSE;
+ break;
+
+- case 'YM5!': // Extended YM2149 format, all machines.
+- case 'YM6!': // Extended YM2149 format, all machines.
++ case 0x594d3521 /*'YM5!'*/: // Extended YM2149 format, all machines.
++ case 0x594d3621 /*'YM6!'*/: // Extended YM2149 format, all machines.
++ if (ptr_size < 12)
++ {
++ setLastError("File too small");
++ return YMFALSE;
++ }
+ if (strncmp((const char*)(pBigMalloc+4),"LeOnArD!",8))
+ {
+ setLastError("Not a valid YM format !");
+ return YMFALSE;
+ }
+ ptr = pBigMalloc+12;
+- nbFrame = readMotorolaDword(&ptr);
+- setAttrib(readMotorolaDword(&ptr));
+- nbDrum = readMotorolaWord(&ptr);
+- ymChip.setClock(readMotorolaDword(&ptr));
+- setPlayerRate(readMotorolaWord(&ptr));
+- loopFrame = readMotorolaDword(&ptr);
+- skip = readMotorolaWord(&ptr);
++ ptr_size -= 12;
++ nbFrame = readMotorolaDword(&ptr, &ptr_size);
++ setAttrib(readMotorolaDword(&ptr, &ptr_size));
++ nbDrum = readMotorolaWord(&ptr, &ptr_size);
++ ymChip.setClock(readMotorolaDword(&ptr, &ptr_size));
++ setPlayerRate(readMotorolaWord(&ptr, &ptr_size));
++ loopFrame = readMotorolaDword(&ptr, &ptr_size);
++ skip = readMotorolaWord(&ptr, &ptr_size);
+ ptr += skip;
++ ptr_size -= skip;
++ if (ptr_size <= 0)
++ {
++ setLastError("File too small");
++ return YMFALSE;
++ }
+ if (nbDrum>0)
+ {
+- pDrumTab=(digiDrum_t*)malloc(nbDrum*sizeof(digiDrum_t));
++ pDrumTab=(digiDrum_t*)calloc(nbDrum, sizeof(digiDrum_t));
+ for (i=0;i<nbDrum;i++)
+ {
+- pDrumTab[i].size = readMotorolaDword(&ptr);
++ pDrumTab[i].size = readMotorolaDword(&ptr, &ptr_size);
++ if (ptr_size <= 0)
++ {
++ setLastError("File too small");
++ goto error_out;
++ }
+ if (pDrumTab[i].size)
+ {
++ if (pDrumTab[i].size >= 0x80000000)
++ {
++ setLastError("To big drumtab");
++ goto error_out;
++ }
++ if (ptr_size<(ymint)pDrumTab[i].size)
++ {
++ setLastError("File too small");
++ goto error_out;
++ }
+ pDrumTab[i].pData = (ymu8*)malloc(pDrumTab[i].size);
+ memcpy(pDrumTab[i].pData,ptr,pDrumTab[i].size);
+ if (attrib&A_DRUM4BITS)
+@@ -328,23 +436,26 @@ ymbool CYmMusic::ymDecode(void)
+ ymu8 *pw = pDrumTab[i].pData;
+ for (j=0;j<pDrumTab[i].size;j++)
+ {
+- *pw++ = ymVolumeTable[(*pw)&15]>>7;
++ *pw = ymVolumeTable[(*pw)&15]>>7;
++ pw++;
+ }
+ }
+ ptr += pDrumTab[i].size;
+- }
+- else
+- {
+- pDrumTab[i].pData = NULL;
++ ptr_size -= pDrumTab[i].size;
+ }
+ }
+ attrib &= (~A_DRUM4BITS);
+ }
+- pSongName = readNtString((char**)&ptr);
+- pSongAuthor = readNtString((char**)&ptr);
+- pSongComment = readNtString((char**)&ptr);
++ pSongName = readNtString((char**)&ptr, &ptr_size);
++ pSongAuthor = readNtString((char**)&ptr, &ptr_size);
++ pSongComment = readNtString((char**)&ptr, &ptr_size);
++ if (ptr_size <= 0)
++ {
++ setLastError("File too small");
++ goto error_out;
++ }
+ songType = YM_V5;
+- if (id=='YM6!')
++ if (id==0x594d3621/*'YM6!'*/)
+ {
+ songType = YM_V6;
+ pSongType = mstrdup("YM 6");
+@@ -353,13 +464,28 @@ ymbool CYmMusic::ymDecode(void)
+ {
+ pSongType = mstrdup("YM 5");
+ }
++ if ((nbFrame >= 0x08000000) || (nbFrame < 0))
++ {
++ setLastError("Too many frames");
++ goto error_out;
++ }
++ if (ptr_size < (ymint)(nbFrame * 16))
++ {
++ setLastError("File too small");
++ goto error_out;
++ }
+ pDataStream = ptr;
+ streamInc = 16;
+ setAttrib(A_STREAMINTERLEAVED|A_TIMECONTROL);
+ pSongPlayer = mstrdup("YM-Chip driver.");
+ break;
+
+- case 'MIX1': // ATARI Remix digit format.
++ case 0x4d495831 /*'MIX1'*/: // ATARI Remix digit format.
++ if (ptr_size < 12)
++ {
++ setLastError("File too small");
++ return YMFALSE;
++ }
+
+ if (strncmp((const char*)(pBigMalloc+4),"LeOnArD!",8))
+ {
+@@ -367,23 +493,50 @@ ymbool CYmMusic::ymDecode(void)
+ return YMFALSE;
+ }
+ ptr = pBigMalloc+12;
++ ptr_size -= 12;
+ songType = YM_MIX1;
+- tmp = readMotorolaDword(&ptr);
++ tmp = readMotorolaDword(&ptr, &ptr_size);
+ setAttrib(0);
+ if (tmp&1) setAttrib(A_DRUMSIGNED);
+- sampleSize = readMotorolaDword(&ptr);
+- nbMixBlock = readMotorolaDword(&ptr);
++ sampleSize = readMotorolaDword(&ptr, &ptr_size);
++ nbMixBlock = readMotorolaDword(&ptr, &ptr_size);
++ if (ptr_size <= 0)
++ {
++ setLastError("File too small");
++ goto error_out;
++ }
++ if (sampleSize <= 0)
++ {
++ setLastError("Invalid sampleSize");
++ goto error_out;
++ }
++ if (nbMixBlock <= 0)
++ {
++ setLastError("Invalid number of mixblocks");
++ goto error_out;
++ }
+ pMixBlock = (mixBlock_t*)malloc(nbMixBlock*sizeof(mixBlock_t));
+ for (i=0;i<nbMixBlock;i++)
+ { // Lecture des block-infos.
+- pMixBlock[i].sampleStart = readMotorolaDword(&ptr);
+- pMixBlock[i].sampleLength = readMotorolaDword(&ptr);
+- pMixBlock[i].nbRepeat = readMotorolaWord(&ptr);
+- pMixBlock[i].replayFreq = readMotorolaWord(&ptr);
++ pMixBlock[i].sampleStart = readMotorolaDword(&ptr, &ptr_size);
++ pMixBlock[i].sampleLength = readMotorolaDword(&ptr, &ptr_size);
++ pMixBlock[i].nbRepeat = readMotorolaWord(&ptr, &ptr_size);
++ pMixBlock[i].replayFreq = readMotorolaWord(&ptr, &ptr_size);
++ }
++ pSongName = readNtString((char**)&ptr, &ptr_size);
++ pSongAuthor = readNtString((char**)&ptr, &ptr_size);
++ pSongComment = readNtString((char**)&ptr, &ptr_size);
++
++ if (sampleSize>=0x80000000)
++ {
++ setLastError("Invalid sampleSize");
++ goto error_out;
++ }
++ if (ptr_size < (ymint)sampleSize)
++ {
++ setLastError("File too small");
++ goto error_out;
+ }
+- pSongName = readNtString((char**)&ptr);
+- pSongAuthor = readNtString((char**)&ptr);
+- pSongComment = readNtString((char**)&ptr);
+
+ pBigSampleBuffer = (unsigned char*)malloc(sampleSize);
+ memcpy(pBigSampleBuffer,ptr,sampleSize);
+@@ -400,8 +553,8 @@ ymbool CYmMusic::ymDecode(void)
+
+ break;
+
+- case 'YMT1': // YM-Tracker
+- case 'YMT2': // YM-Tracker
++ case 0x594d5431 /*'YMT1'*/: // YM-Tracker
++ case 0x594d5432 /*'YMT2'*/: // YM-Tracker
+ /*;
+ ; Format du YM-Tracker-1
+ ;
+@@ -418,33 +571,55 @@ ymbool CYmMusic::ymDecode(void)
+ ; NT Music comment
+ ; nb digi *
+ */
++ if (ptr_size < 12)
++ {
++ setLastError("File too small");
++ return YMFALSE;
++ }
++
+ if (strncmp((const char*)(pBigMalloc+4),"LeOnArD!",8))
+ {
+ setLastError("Not a valid YM format !");
+ return YMFALSE;
+ }
+ ptr = pBigMalloc+12;
++ ptr_size -= 12;
+ songType = YM_TRACKER1;
+- nbVoice = readMotorolaWord(&ptr);
+- setPlayerRate(readMotorolaWord(&ptr));
+- nbFrame= readMotorolaDword(&ptr);
+- loopFrame = readMotorolaDword(&ptr);
+- nbDrum = readMotorolaWord(&ptr);
+- attrib = readMotorolaDword(&ptr);
+- pSongName = readNtString((char**)&ptr);
+- pSongAuthor = readNtString((char**)&ptr);
+- pSongComment = readNtString((char**)&ptr);
++ nbVoice = readMotorolaWord(&ptr, &ptr_size);
++ setPlayerRate(readMotorolaWord(&ptr, &ptr_size));
++ nbFrame= readMotorolaDword(&ptr, &ptr_size);
++ loopFrame = readMotorolaDword(&ptr, &ptr_size);
++ nbDrum = readMotorolaWord(&ptr, &ptr_size);
++ attrib = readMotorolaDword(&ptr, &ptr_size);
++ pSongName = readNtString((char**)&ptr, &ptr_size);
++ pSongAuthor = readNtString((char**)&ptr, &ptr_size);
++ pSongComment = readNtString((char**)&ptr, &ptr_size);
++ if (ptr_size < 0)
++ {
++ setLastError("File too small");
++ return YMFALSE;
++ }
+ if (nbDrum>0)
+ {
+- pDrumTab=(digiDrum_t*)malloc(nbDrum*sizeof(digiDrum_t));
++ pDrumTab=(digiDrum_t*)calloc(nbDrum, sizeof(digiDrum_t));
+ for (i=0;i<(ymint)nbDrum;i++)
+ {
+- pDrumTab[i].size = readMotorolaWord(&ptr);
++ pDrumTab[i].size = readMotorolaWord(&ptr, &ptr_size);
++ if (ptr_size < 0)
++ {
++ setLastError("File too small");
++ goto error_out;
++ }
+ pDrumTab[i].repLen = pDrumTab[i].size;
+- if ('YMT2' == id)
++ if (0x594d5432/*'YMT2'*/ == id)
+ {
+- pDrumTab[i].repLen = readMotorolaWord(&ptr); // repLen
+- readMotorolaWord(&ptr); // flag
++ pDrumTab[i].repLen = readMotorolaWord(&ptr, &ptr_size); // repLen
++ readMotorolaWord(&ptr, &ptr_size); // flag
++ if (ptr_size < 0)
++ {
++ setLastError("File too small");
++ goto error_out;
++ }
+ }
+ if (pDrumTab[i].repLen>pDrumTab[i].size)
+ {
+@@ -453,19 +628,27 @@ ymbool CYmMusic::ymDecode(void)
+
+ if (pDrumTab[i].size)
+ {
++ if (pDrumTab[i].size >= 0x80000000)
++ {
++ setLastError("Drumtab to big");
++ goto error_out;
++ }
++ if (ptr_size<(ymint)pDrumTab[i].size)
++ {
++ setLastError("File too small");
++ goto error_out;
++ }
++
+ pDrumTab[i].pData = (ymu8*)malloc(pDrumTab[i].size);
+ memcpy(pDrumTab[i].pData,ptr,pDrumTab[i].size);
+ ptr += pDrumTab[i].size;
+- }
+- else
+- {
+- pDrumTab[i].pData = NULL;
++ ptr_size -= pDrumTab[i].size;
+ }
+ }
+ }
+
+ ymTrackerFreqShift = 0;
+- if ('YMT2' == id)
++ if (0x594d5432/*'YMT2'*/ == id)
+ {
+ ymTrackerFreqShift = (attrib>>28)&15;
+ attrib &= 0x0fffffff;
+@@ -476,18 +659,33 @@ ymbool CYmMusic::ymDecode(void)
+ pSongType = mstrdup("YM-T1");
+ }
+
++ if ((nbVoice > MAX_VOICE) || (nbVoice < 0))
++ {
++ setLastError("Too many voices");
++ goto error_out;
++ }
++ if ((nbFrame >= (ymint)(0x80000000 / (MAX_VOICE * (sizeof(ymTrackerLine_t))))) || (nbFrame < 0)) /* ymTrackerLine_t has a 2^N size */
++ {
++ setLastError("Too many frames");
++ goto error_out;
++ }
++ if (ptr_size < (ymint)(sizeof(ymTrackerLine_t) * nbVoice * nbFrame))
++ {
++ setLastError("File too small");
++ goto error_out;
++ }
+
+ pDataStream = ptr;
+ ymChip.setClock(ATARI_CLOCK);
+
+ ymTrackerInit(100); // 80% de volume maxi.
+- streamInc = 16;
++ streamInc = 16; /* not needed, since this is only used for YMx formats */
+ setTimeControl(YMTRUE);
+ pSongPlayer = mstrdup("Universal Tracker");
+ break;
+
+ default:
+- setLastError("Unknow YM format !");
++ setLastError("Unknown YM format !");
+ return YMFALSE;
+ break;
+ }
+@@ -498,6 +696,25 @@ ymbool CYmMusic::ymDecode(void)
+ }
+
+ return YMTRUE;
++error_out:
++ for (i=0;i<nbDrum;i++)
++ {
++ if (pDrumTab[i].pData)
++ myFree((void **)&pDrumTab[i].pData);
++ }
++ if (nbDrum>0)
++ {
++ myFree((void **)&pDrumTab);
++ nbDrum=0;
++ }
++ myFree((void **)&pSongName);
++ myFree((void **)&pSongAuthor);
++ myFree((void **)&pSongComment);
++ myFree((void **)&pSongType); /* <- never needed, but we keep it for purity */
++ myFree((void **)&pSongPlayer); /* <- never needed, but we keep it for purity */
++ myFree((void **)&pMixBlock);
++ myFree((void **)&pBigSampleBuffer); /* <- never needed, but we keep it for purity */
++ return YMFALSE;
+ }
+
+
+@@ -645,12 +862,6 @@ ymbool CYmMusic::loadMemory(void *pBlock
+ return YMTRUE;
+ }
+
+-void myFree(void **pPtr)
+-{
+- if (*pPtr) free(*pPtr);
+- *pPtr = NULL;
+-}
+-
+ void CYmMusic::unLoad(void)
+ {
+