1 /* OpenCP Module Player
2  * copyright (c) '94-'10 Niklas Beisert <nbeisert@physik.tu-muenchen.de>
3  * copyright (c) '04-'21 Stian Skjelstad <stian.skjelstad@gmail.com>
4  *
5  * XMPlay file type detection routines for the fileselector
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  *
21  * revision history: (please note changes here)
22  *  -kb980717   Tammo Hinrichs <opencp@groove.org>
23  *    -first release
24  *    -separated this code from gmdptype.cpp
25  *    -added 0x1a and version number checking
26  *    -added MXM file type
27  */
28 
29 #include "config.h"
30 #include <string.h>
31 #include <stdlib.h>
32 #include "types.h"
33 #include "filesel/filesystem.h"
34 #include "filesel/mdb.h"
35 
36 #define _EXT_MAX 5
37 
getext(char * ext,const char * name)38 static void getext(char *ext, const char *name)
39 {
40 	int i;
41 	name+=8;
42 	for (i=0; i<(_EXT_MAX-1); i++)
43 		if (*name==' ')
44 			break;
45 		else
46 			*ext++=*name++;
47 	*ext=0;
48 }
49 
xmpGetModuleType(const char * buf,const char * ext)50 static unsigned char xmpGetModuleType(const char *buf, const char *ext)
51 {
52 
53 	if (!strcasecmp(ext, ".WOW")&&(*(uint32_t *)(buf+1080)==int32_little(0x2E4B2E4D)))
54 	{
55 		return mtWOW;
56 	}
57 
58 	switch (int32_little(*(uint32_t *)(buf+1080)))
59 	{
60 		case 0x2E4B2E4D: case 0x214B214D: case 0x2E542E4E: case 0x34544C46:
61 		case 0x4E484331: case 0x4E484332: case 0x4E484333: case 0x4E484334:
62 		case 0x4E484335: case 0x4E484336: case 0x4E484337: case 0x4E484338:
63 		case 0x4E484339: case 0x48433031: case 0x48433131: case 0x48433231:
64 		case 0x48433331: case 0x48433431: case 0x48433531: case 0x48433631:
65 		case 0x48433731: case 0x48433831: case 0x48433931: case 0x48433032:
66 		case 0x48433132: case 0x48433232: case 0x48433332: case 0x48433432:
67 		case 0x48433532: case 0x48433632: case 0x48433732: case 0x48433832:
68 		case 0x48433932: case 0x48433033: case 0x48433133: case 0x48433233:
69 		{
70 			return mtMOD;
71 		}
72 	}
73 
74 	if (!memcmp(buf, "Extended Module: ", 17)/* && buf[37]==0x1a*/) /* some malformed trackers doesn't save the magic 0x1a at offset 37 */
75 	{
76 		return mtXM;
77 	}
78 
79 	if (!memcmp(buf, "MXM\n", 4))
80 	{
81 		return mtMXM;
82 	}
83 
84 	if (!strcasecmp(ext, ".MOD"))
85 	{
86 		int i,j;
87 
88 		/* Check title for ASCII */
89 		for (i=0; i<20; i++)
90 		{
91 			if (buf[i]) /* string is zero-terminated */
92 			{
93 				break;
94 			} else {
95 				if (buf[i]<0x20) /* non-ASCII?, can not be mtM15/mtM31 */
96 				{
97 					goto notM15_M31;
98 				}
99 			}
100 		}
101 
102 		/* Check instruments for ASCII*/
103 		for (i=0; i<31; i++)
104 		{
105 			for (j=0; j<21; j++)
106 			{
107 				if (!buf[20+i*30+j]) /* string is zero-terminated */
108 				{
109 					break;
110 				} else {
111 					if (buf[20+i*30+j]<0x20) /* non-ASCII? */
112 					{
113 						if (i<15)
114 						{
115 							goto notM15_M31;
116 						}
117 						return mtM15; /* we had atleast 15 instruments */
118 					}
119 				}
120 			}
121 		}
122 		return mtM31;
123 	}
124 notM15_M31:
125 	return mtUnRead;
126 }
127 
128 
xmpReadMemInfo(struct moduleinfostruct * m,const char * buf,size_t len)129 static int xmpReadMemInfo(struct moduleinfostruct *m, const char *buf, size_t len)
130 {
131 	char ext[_EXT_MAX];
132 	int type;
133 	typedef struct __attribute__((packed))
134 	{
135 		char sig[17];
136 		char name[20];
137 		char eof;
138 		char tracker[20];
139 		uint16_t ver;
140 		uint32_t hdrsize;
141 	} head1;
142 	head1 *xmhdr;
143 
144 	if (!memcmp(buf, "ziRCONia", 8))
145 	{
146 		strcpy(m->modname, "MMCMPed module");
147 		return 0;
148 	}
149 
150 	getext(ext, m->name);
151 
152 	if ((type=xmpGetModuleType(buf, ext))==mtUnRead)
153 		return 0;
154 
155 	m->modtype=type;
156 
157 	switch (type)
158 	{
159 		case mtM15: case mtM31:
160 			m->channels=4;
161 			memcpy(m->modname, buf+0, 20);
162 			m->modname[20]=0;
163 			memset(&m->composer, 0, sizeof(m->composer));
164 			return 1;
165 
166 		case mtMOD:
167 			switch (int32_little(*(uint32_t *)(buf+1080)))
168 			{
169 				case 0x2E4B2E4D: /* M.K. */
170 				case 0x214B214D: /* M!K! */
171 				case 0x2E542E4E: /* N.T. */
172 				case 0x34544C46: m->channels=4; break;  /* FLT4 */
173 				case 0x4E484331: m->channels=1; break;  /* 1CHN */
174 				case 0x4E484332: m->channels=2; break;  /* 2CHN */
175 				case 0x4E484333: m->channels=3; break;  /* 3CHN */
176 				case 0x4E484334: m->channels=4; break;  /* 4CHN */
177 				case 0x4E484335: m->channels=5; break;  /* 5CHN */
178 				case 0x4E484336: m->channels=6; break;  /* 6CHN */
179 				case 0x4E484337: m->channels=7; break;  /* 7CHN */
180 				case 0x4E484338: m->channels=8; break;  /* 8CHN */
181 				case 0x4E484339: m->channels=9; break;  /* 9CHN */
182 				case 0x48433031: m->channels=10; break; /* 10CH */
183 				case 0x48433131: m->channels=11; break; /* 11CH */
184 				case 0x48433231: m->channels=12; break; /* 12CH */
185 				case 0x48433331: m->channels=13; break; /* 13CH */
186 				case 0x48433431: m->channels=14; break; /* 14CH */
187 				case 0x48433531: m->channels=15; break; /* 15CH */
188 				case 0x48433631: m->channels=16; break; /* 16CH */
189 				case 0x48433731: m->channels=17; break; /* 17CH */
190 				case 0x48433831: m->channels=18; break; /* 18CH */
191 				case 0x48433931: m->channels=19; break; /* 19CH */
192 				case 0x48433032: m->channels=20; break; /* 20CH */
193 				case 0x48433132: m->channels=21; break; /* 21CH */
194 				case 0x48433232: m->channels=22; break; /* 22CH */
195 				case 0x48433332: m->channels=23; break; /* 23CH */
196 				case 0x48433432: m->channels=24; break; /* 24CH */
197 				case 0x48433532: m->channels=25; break; /* 25CH */
198 				case 0x48433632: m->channels=26; break; /* 26CH */
199 				case 0x48433732: m->channels=27; break; /* 27CH */
200 				case 0x48433832: m->channels=28; break; /* 28CH */
201 				case 0x48433932: m->channels=29; break; /* 29CH */
202 				case 0x48433033: m->channels=30; break; /* 30CH */
203 				case 0x48433133: m->channels=31; break; /* 31CH */
204 				case 0x48433233: m->channels=32; break; /* 32CH */
205 			}
206 
207 			memcpy(m->modname, buf+0, 20);
208 			m->modname[20]=0;
209 			memset(&m->composer, 0, sizeof(m->composer));
210 			return 1;
211 
212 		case mtXM:
213 			xmhdr =  (head1 *)buf;
214 			if (xmhdr->ver<int16_little(0x104))
215 			{
216 				m->modtype=0xFF;
217 				strcpy(m->modname,"too old version");
218 				memset(&m->composer, 0, sizeof(m->composer));
219 				return 0;
220 			} else {
221 				memcpy(m->modname, xmhdr->name, 20);
222 				m->modname[20]=0;
223 				m->channels=buf[68];
224 			}
225 			memset(&m->composer, 0, sizeof(m->composer));
226 			return 1;
227 
228 		case mtMXM:
229 			strcpy(m->modname,"MXMPlay module");
230 			m->channels=buf[12];
231 			memset(&m->composer, 0, sizeof(m->composer));
232 			return 1;
233 	}
234 	return 0;
235 }
236 
xmpReadInfo(struct moduleinfostruct * m,struct ocpfilehandle_t * fp,const char * mem,size_t len)237 static int xmpReadInfo(struct moduleinfostruct *m, struct ocpfilehandle_t *fp, const char *mem, size_t len)
238 {
239 	return xmpReadMemInfo (m, mem, len);
240 }
241 
242 struct mdbreadinforegstruct xmpReadInfoReg = {xmpReadMemInfo, xmpReadInfo, 0 MDBREADINFOREGSTRUCT_TAIL};
243