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