summaryrefslogtreecommitdiff
path: root/apps/plugins/mikmod/load_xm.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/mikmod/load_xm.c')
-rw-r--r--apps/plugins/mikmod/load_xm.c129
1 files changed, 70 insertions, 59 deletions
diff --git a/apps/plugins/mikmod/load_xm.c b/apps/plugins/mikmod/load_xm.c
index ffbd6dff4d..3eb0803668 100644
--- a/apps/plugins/mikmod/load_xm.c
+++ b/apps/plugins/mikmod/load_xm.c
@@ -6,12 +6,12 @@
6 it under the terms of the GNU Library General Public License as 6 it under the terms of the GNU Library General Public License as
7 published by the Free Software Foundation; either version 2 of 7 published by the Free Software Foundation; either version 2 of
8 the License, or (at your option) any later version. 8 the License, or (at your option) any later version.
9 9
10 This program is distributed in the hope that it will be useful, 10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Library General Public License for more details. 13 GNU Library General Public License for more details.
14 14
15 You should have received a copy of the GNU Library General Public 15 You should have received a copy of the GNU Library General Public
16 License along with this library; if not, write to the Free Software 16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
@@ -20,7 +20,7 @@
20 20
21/*============================================================================== 21/*==============================================================================
22 22
23 $Id: load_xm.c,v 1.5 2008/02/29 18:49:03 denis111 Exp $ 23 $Id$
24 24
25 Fasttracker (XM) module loader 25 Fasttracker (XM) module loader
26 26
@@ -59,7 +59,7 @@ typedef struct XMHEADER {
59 UWORD numchn; /* Number of channels (2,4,6,8,10,...,32) */ 59 UWORD numchn; /* Number of channels (2,4,6,8,10,...,32) */
60 UWORD numpat; /* Number of patterns (max 256) */ 60 UWORD numpat; /* Number of patterns (max 256) */
61 UWORD numins; /* Number of instruments (max 128) */ 61 UWORD numins; /* Number of instruments (max 128) */
62 UWORD flags; 62 UWORD flags;
63 UWORD tempo; /* Default tempo */ 63 UWORD tempo; /* Default tempo */
64 UWORD bpm; /* Default BPM */ 64 UWORD bpm; /* Default BPM */
65 UBYTE orders[256]; /* Pattern order table */ 65 UBYTE orders[256]; /* Pattern order table */
@@ -129,7 +129,7 @@ typedef struct XMNOTE {
129static XMNOTE *xmpat=NULL; 129static XMNOTE *xmpat=NULL;
130static XMHEADER *mh=NULL; 130static XMHEADER *mh=NULL;
131 131
132/* increment unit for sample array MikMod_reallocation */ 132/* increment unit for sample array reallocation */
133#define XM_SMPINCR 64 133#define XM_SMPINCR 64
134static ULONG *nextwav=NULL; 134static ULONG *nextwav=NULL;
135static XMWAVHEADER *wh=NULL,*s=NULL; 135static XMWAVHEADER *wh=NULL,*s=NULL;
@@ -155,6 +155,7 @@ static int XM_Init(void)
155static void XM_Cleanup(void) 155static void XM_Cleanup(void)
156{ 156{
157 MikMod_free(mh); 157 MikMod_free(mh);
158 mh=NULL;
158} 159}
159 160
160static int XM_ReadNote(XMNOTE* n) 161static int XM_ReadNote(XMNOTE* n)
@@ -359,8 +360,8 @@ static int LoadPatterns(int dummypat)
359 return 0; 360 return 0;
360 361
361 /* when packsize is 0, don't try to load a pattern.. it's empty. */ 362 /* when packsize is 0, don't try to load a pattern.. it's empty. */
362 if(ph.packsize) 363 if(ph.packsize)
363 for(u=0;u<ph.numrows;u++) 364 for(u=0;u<ph.numrows;u++)
364 for(v=0;v<of.numchn;v++) { 365 for(v=0;v<of.numchn;v++) {
365 if(!ph.packsize) break; 366 if(!ph.packsize) break;
366 367
@@ -443,11 +444,17 @@ static void FixEnvelope(ENVPT *cur, int pts)
443 444
444static int LoadInstruments(void) 445static int LoadInstruments(void)
445{ 446{
446 int t,u, ck; 447 long filend,ck;
448 int t,u;
447 INSTRUMENT *d; 449 INSTRUMENT *d;
448 ULONG next=0; 450 ULONG next=0;
449 UWORD wavcnt=0; 451 UWORD wavcnt=0;
450 452
453 ck = _mm_ftell(modreader);
454 _mm_fseek(modreader,0,SEEK_END);
455 filend = _mm_ftell(modreader);
456 _mm_fseek(modreader,ck,SEEK_SET);
457
451 if(!AllocInstruments()) return 0; 458 if(!AllocInstruments()) return 0;
452 d=of.instruments; 459 d=of.instruments;
453 for(t=0;t<of.numins;t++,d++) { 460 for(t=0;t<of.numins;t++,d++) {
@@ -461,12 +468,9 @@ static int LoadInstruments(void)
461 ih.size = _mm_read_I_ULONG(modreader); 468 ih.size = _mm_read_I_ULONG(modreader);
462 headend += ih.size; 469 headend += ih.size;
463 ck = _mm_ftell(modreader); 470 ck = _mm_ftell(modreader);
464 _mm_fseek(modreader,0,SEEK_END); 471 if ((headend<0) || (filend<headend) || (headend<ck)) {
465 if ((headend<0) || (_mm_ftell(modreader)<headend) || (headend<ck)) {
466 _mm_fseek(modreader,ck,SEEK_SET);
467 break; 472 break;
468 } 473 }
469 _mm_fseek(modreader,ck,SEEK_SET);
470 _mm_read_string(ih.name, 22, modreader); 474 _mm_read_string(ih.name, 22, modreader);
471 ih.type = _mm_read_UBYTE(modreader); 475 ih.type = _mm_read_UBYTE(modreader);
472 ih.numsmp = _mm_read_I_UWORD(modreader); 476 ih.numsmp = _mm_read_I_UWORD(modreader);
@@ -500,7 +504,11 @@ static int LoadInstruments(void)
500 504
501 /* read the remainder of the header 505 /* read the remainder of the header
502 (2 bytes for 1.03, 22 for 1.04) */ 506 (2 bytes for 1.03, 22 for 1.04) */
503 if (headend>=_mm_ftell(modreader)) for(u=headend-_mm_ftell(modreader);u;u--) (void)_mm_read_UBYTE(modreader); 507 if (headend>=_mm_ftell(modreader)) {
508 for(u=headend-_mm_ftell(modreader);u;u--) {
509 _mm_skip_BYTE(modreader);
510 }
511 }
504 512
505 /* we can't trust the envelope point count here, as some 513 /* we can't trust the envelope point count here, as some
506 modules have incorrect values (K_OSPACE.XM reports 32 volume 514 modules have incorrect values (K_OSPACE.XM reports 32 volume
@@ -509,8 +517,8 @@ static int LoadInstruments(void)
509 if(pth.panpts>XMENVCNT/2) pth.panpts=XMENVCNT/2; 517 if(pth.panpts>XMENVCNT/2) pth.panpts=XMENVCNT/2;
510 518
511 if((_mm_eof(modreader))||(pth.volpts>XMENVCNT/2)||(pth.panpts>XMENVCNT/2)) { 519 if((_mm_eof(modreader))||(pth.volpts>XMENVCNT/2)||(pth.panpts>XMENVCNT/2)) {
512 if(nextwav) { MikMod_free(nextwav);nextwav=NULL; } 520 MikMod_free(nextwav);nextwav=NULL;
513 if(wh) { MikMod_free(wh);wh=NULL; } 521 MikMod_free(wh);wh=NULL;
514 _mm_errno = MMERR_LOADING_SAMPLEINFO; 522 _mm_errno = MMERR_LOADING_SAMPLEINFO;
515 return 0; 523 return 0;
516 } 524 }
@@ -519,7 +527,7 @@ static int LoadInstruments(void)
519 d->samplenumber[u]=pth.what[u]+of.numsmp; 527 d->samplenumber[u]=pth.what[u]+of.numsmp;
520 d->volfade = pth.volfade; 528 d->volfade = pth.volfade;
521 529
522#if defined __STDC__ || defined _MSC_VER || defined MPW_C 530#if defined __STDC__ || defined _MSC_VER || defined __WATCOMC__ || defined MPW_C
523#define XM_ProcessEnvelope(name) \ 531#define XM_ProcessEnvelope(name) \
524 for (u = 0; u < (XMENVCNT >> 1); u++) { \ 532 for (u = 0; u < (XMENVCNT >> 1); u++) { \
525 d-> name##env[u].pos = pth. name##env[u << 1]; \ 533 d-> name##env[u].pos = pth. name##env[u << 1]; \
@@ -560,7 +568,7 @@ static int LoadInstruments(void)
560 \ 568 \
561 if ((d-> name/**/flg&EF_ON)&&(d-> name/**/pts<2)) \ 569 if ((d-> name/**/flg&EF_ON)&&(d-> name/**/pts<2)) \
562 d-> name/**/flg&=~EF_ON 570 d-> name/**/flg&=~EF_ON
563#endif 571#endif
564 572
565 XM_ProcessEnvelope(vol); 573 XM_ProcessEnvelope(vol);
566 XM_ProcessEnvelope(pan); 574 XM_ProcessEnvelope(pan);
@@ -577,15 +585,23 @@ static int LoadInstruments(void)
577 everything over */ 585 everything over */
578 if(mh->version>0x0103) next = 0; 586 if(mh->version>0x0103) next = 0;
579 for(u=0;u<ih.numsmp;u++,s++) { 587 for(u=0;u<ih.numsmp;u++,s++) {
588 /* XM sample header is 40 bytes: make sure we won't hit EOF */
589 /* Note: last instrument is at the end of file in version 0x0104 */
590 if(_mm_ftell(modreader)+40>filend) {
591 MikMod_free(nextwav);MikMod_free(wh);
592 nextwav=NULL;wh=NULL;
593 _mm_errno = MMERR_LOADING_SAMPLEINFO;
594 return 0;
595 }
580 /* Allocate more room for sample information if necessary */ 596 /* Allocate more room for sample information if necessary */
581 if(of.numsmp+u==wavcnt) { 597 if(of.numsmp+u==wavcnt) {
582 wavcnt+=XM_SMPINCR; 598 wavcnt+=XM_SMPINCR;
583 if(!(nextwav=MikMod_realloc(nextwav,wavcnt*sizeof(ULONG)))){ 599 if(!(nextwav=(ULONG*)MikMod_realloc(nextwav,wavcnt*sizeof(ULONG)))){
584 if(wh) { MikMod_free(wh);wh=NULL; } 600 MikMod_free(wh);wh=NULL;
585 _mm_errno = MMERR_OUT_OF_MEMORY; 601 _mm_errno = MMERR_OUT_OF_MEMORY;
586 return 0; 602 return 0;
587 } 603 }
588 if(!(wh=MikMod_realloc(wh,wavcnt*sizeof(XMWAVHEADER)))) { 604 if(!(wh=(XMWAVHEADER*)MikMod_realloc(wh,wavcnt*sizeof(XMWAVHEADER)))) {
589 MikMod_free(nextwav);nextwav=NULL; 605 MikMod_free(nextwav);nextwav=NULL;
590 _mm_errno = MMERR_OUT_OF_MEMORY; 606 _mm_errno = MMERR_OUT_OF_MEMORY;
591 return 0; 607 return 0;
@@ -610,13 +626,6 @@ static int LoadInstruments(void)
610 626
611 nextwav[of.numsmp+u]=next; 627 nextwav[of.numsmp+u]=next;
612 next+=s->length; 628 next+=s->length;
613
614 if(_mm_eof(modreader)) {
615 MikMod_free(nextwav);MikMod_free(wh);
616 nextwav=NULL;wh=NULL;
617 _mm_errno = MMERR_LOADING_SAMPLEINFO;
618 return 0;
619 }
620 } 629 }
621 630
622 if(mh->version>0x0103) { 631 if(mh->version>0x0103) {
@@ -628,15 +637,15 @@ static int LoadInstruments(void)
628 } else { 637 } else {
629 /* read the remainder of the header */ 638 /* read the remainder of the header */
630 ck = _mm_ftell(modreader); 639 ck = _mm_ftell(modreader);
631 _mm_fseek(modreader,0,SEEK_END); 640 if ((headend<0) || (filend<headend) || (headend<ck)) {
632 if ((headend<0) || (_mm_ftell(modreader)<headend) || (headend<ck)) {
633 _mm_fseek(modreader,ck,SEEK_SET);
634 break; 641 break;
635 } 642 }
636 _mm_fseek(modreader,ck,SEEK_SET); 643 for(u=headend-_mm_ftell(modreader);u;u--) {
637 for(u=headend-_mm_ftell(modreader);u;u--) (void)_mm_read_UBYTE(modreader); 644 _mm_skip_BYTE(modreader);
645 }
638 646
639 if(_mm_eof(modreader)) { 647 /* last instrument is at the end of file in version 0x0104 */
648 if(_mm_eof(modreader) && (mh->version<0x0104 || t<of.numins-1)) {
640 MikMod_free(nextwav);MikMod_free(wh); 649 MikMod_free(nextwav);MikMod_free(wh);
641 nextwav=NULL;wh=NULL; 650 nextwav=NULL;wh=NULL;
642 _mm_errno = MMERR_LOADING_SAMPLEINFO; 651 _mm_errno = MMERR_LOADING_SAMPLEINFO;
@@ -648,8 +657,8 @@ static int LoadInstruments(void)
648 657
649 /* sanity check */ 658 /* sanity check */
650 if(!of.numsmp) { 659 if(!of.numsmp) {
651 if(nextwav) { MikMod_free(nextwav);nextwav=NULL; } 660 MikMod_free(nextwav);nextwav=NULL;
652 if(wh) { MikMod_free(wh);wh=NULL; } 661 MikMod_free(wh);wh=NULL;
653 _mm_errno = MMERR_LOADING_SAMPLEINFO; 662 _mm_errno = MMERR_LOADING_SAMPLEINFO;
654 return 0; 663 return 0;
655 } 664 }
@@ -664,17 +673,15 @@ static int XM_Load(int curious)
664 int t,u; 673 int t,u;
665 int dummypat=0; 674 int dummypat=0;
666 char tracker[21],modtype[60]; 675 char tracker[21],modtype[60];
667 (void)curious; 676 (void)curious;
668 677
669 /* try to read module header */ 678 /* try to read module header */
670 _mm_read_string(mh->id,17,modreader); 679 _mm_read_string(mh->id,17,modreader);
671 _mm_read_string(mh->songname,21,modreader); 680 _mm_read_string(mh->songname,21,modreader);
672 _mm_read_string(mh->trackername,20,modreader); 681 _mm_read_string(mh->trackername,20,modreader);
673 mh->version =_mm_read_I_UWORD(modreader); 682 mh->version =_mm_read_I_UWORD(modreader);
674 if((mh->version<0x102)||(mh->version>0x104)) { 683 if(mh->version < 0x102 || mh->version > 0x104)
675 _mm_errno=MMERR_NOT_A_MODULE; 684 goto bad_xm;
676 return 0;
677 }
678 mh->headersize =_mm_read_I_ULONG(modreader); 685 mh->headersize =_mm_read_I_ULONG(modreader);
679 mh->songlength =_mm_read_I_UWORD(modreader); 686 mh->songlength =_mm_read_I_UWORD(modreader);
680 mh->restart =_mm_read_I_UWORD(modreader); 687 mh->restart =_mm_read_I_UWORD(modreader);
@@ -684,23 +691,25 @@ static int XM_Load(int curious)
684 mh->flags =_mm_read_I_UWORD(modreader); 691 mh->flags =_mm_read_I_UWORD(modreader);
685 mh->tempo =_mm_read_I_UWORD(modreader); 692 mh->tempo =_mm_read_I_UWORD(modreader);
686 mh->bpm =_mm_read_I_UWORD(modreader); 693 mh->bpm =_mm_read_I_UWORD(modreader);
687 if(!mh->bpm) { 694 if(mh->numchn > 64) goto bad_xm;
688 _mm_errno=MMERR_NOT_A_MODULE; 695 if(mh->tempo > 32 || mh->bpm < 32 || mh->bpm > 255)
689 return 0; 696 goto bad_xm;
690 } 697 if(mh->songlength > 256 || mh->headersize < 20 || mh->headersize > 20+256)
691 _mm_read_UBYTES(mh->orders,mh->headersize-20,modreader); 698 goto bad_xm;
692 699 if(mh->numpat > 256 || mh->numins > 255 || mh->restart > 255)
693 if(_mm_eof(modreader)) { 700 goto bad_xm;
694 _mm_errno = MMERR_LOADING_HEADER; 701/* _mm_read_UBYTES(mh->orders,256,modreader);*/
695 return 0; 702/* _mm_read_UBYTES(mh->orders,mh->headersize-20,modreader);*/
696 } 703 _mm_read_UBYTES(mh->orders,mh->songlength,modreader);
704 if(_mm_fseek(modreader, mh->headersize+60, SEEK_SET) || _mm_eof(modreader))
705 goto bad_hdr;
697 706
698 /* set module variables */ 707 /* set module variables */
699 of.initspeed = mh->tempo; 708 of.initspeed = mh->tempo;
700 of.inittempo = mh->bpm; 709 of.inittempo = mh->bpm;
701 strncpy(tracker,mh->trackername,20);tracker[20]=0; 710 strncpy(tracker,mh->trackername,20);tracker[20]=0;
702 for(t=20;(tracker[t]<=' ')&&(t>=0);t--) tracker[t]=0; 711 for(t=20;(t>=0)&&(tracker[t]<=' ');t--) tracker[t]=0;
703 712
704 /* some modules have the tracker name empty */ 713 /* some modules have the tracker name empty */
705 if (!tracker[0]) 714 if (!tracker[0])
706 strcpy(tracker,"Unknown tracker"); 715 strcpy(tracker,"Unknown tracker");
@@ -712,7 +721,7 @@ static int XM_Load(int curious)
712 sprintf(modtype,"%s (XM format %d.%02d)", 721 sprintf(modtype,"%s (XM format %d.%02d)",
713 tracker,mh->version>>8,mh->version&0xff); 722 tracker,mh->version>>8,mh->version&0xff);
714#endif 723#endif
715 of.modtype = StrDup(modtype); 724 of.modtype = MikMod_strdup(modtype);
716 of.numchn = mh->numchn; 725 of.numchn = mh->numchn;
717 of.numpat = mh->numpat; 726 of.numpat = mh->numpat;
718 of.numtrk = (UWORD)of.numpat*of.numchn; /* get number of channels */ 727 of.numtrk = (UWORD)of.numpat*of.numchn; /* get number of channels */
@@ -720,8 +729,7 @@ static int XM_Load(int curious)
720 of.numpos = mh->songlength; /* copy the songlength */ 729 of.numpos = mh->songlength; /* copy the songlength */
721 of.reppos = mh->restart<mh->songlength?mh->restart:0; 730 of.reppos = mh->restart<mh->songlength?mh->restart:0;
722 of.numins = mh->numins; 731 of.numins = mh->numins;
723 of.flags |= UF_XMPERIODS | UF_INST | UF_NOWRAP | UF_FT2QUIRKS | 732 of.flags |= UF_XMPERIODS | UF_INST | UF_NOWRAP | UF_FT2QUIRKS | UF_PANNING;
724 UF_PANNING;
725 if(mh->flags&1) of.flags |= UF_LINEAR; 733 if(mh->flags&1) of.flags |= UF_LINEAR;
726 of.bpmlimit = 32; 734 of.bpmlimit = 32;
727 735
@@ -802,16 +810,19 @@ static int XM_Load(int curious)
802 MikMod_free(wh);MikMod_free(nextwav); 810 MikMod_free(wh);MikMod_free(nextwav);
803 wh=NULL;nextwav=NULL; 811 wh=NULL;nextwav=NULL;
804 return 1; 812 return 1;
813
814bad_hdr: _mm_errno = MMERR_LOADING_HEADER; return 0;
815bad_xm: _mm_errno = MMERR_NOT_A_MODULE; return 0;
805} 816}
806 817
807static CHAR *XM_LoadTitle(void) 818static CHAR *XM_LoadTitle(void)
808{ 819{
809 CHAR s[21]; 820 CHAR str[21];
810 821
811 _mm_fseek(modreader,17,SEEK_SET); 822 _mm_fseek(modreader,17,SEEK_SET);
812 if(!_mm_read_UBYTES(s,21,modreader)) return NULL; 823 if(!_mm_read_UBYTES(str, 21, modreader)) return NULL;
813 824
814 return(DupStr(s,21,1)); 825 return(DupStr(str,21,1));
815} 826}
816 827
817/*========== Loader information */ 828/*========== Loader information */