1 #include "config.h"
2 #include <errno.h>
3 #include <fcntl.h>
4 #include <getopt.h>
5 #include <string.h>
6 #include <stdio.h>
7 #include <sys/mman.h>
8 #include <sys/types.h>
9 #include <sys/stat.h>
10 #include <unistd.h>
11 #include "types.h"
12 
13 #define roundup(x,y) (((x) + (y) - 1) & ~((y) - 1))
14 
15 int usecolor = 0;
16 int savesamples = 0;
17 FILE *savepatterns = 0;
18 
19 char *FONT_RESET = "";
20 char *FONT_BRIGHT_BLACK = "";
21 char *FONT_BRIGHT_RED = "";
22 char *FONT_BRIGHT_GREEN = "";
23 char *FONT_BRIGHT_YELLOW = "";
24 char *FONT_BRIGHT_BLUE = "";
25 char *FONT_BRIGHT_PURPLE = "";
26 char *FONT_BRIGHT_CYAN = "";
27 
28 #if 0
29 
30 struct
31 {
32 	uint32_t offset;
33 	uint16_t length;
34 } Instruments[31];
35 
36 #if 0
37 typedef struct __attribute__((packed))
38 {
39 	char name[20];
40 	char tracker[8];
41 	uint8_t sig,type;
42 	uint8_t maj, min;
43 	uint8_t it, pats, gv;
44 	char reserved[13];
45 } FileHeader;
46 #endif
47 
48 #endif
49 
DumpPrefix(unsigned char * mem,int len,int base,int baselen)50 int DumpPrefix (unsigned char *mem, int len, int base, int baselen)
51 {
52 	int retval = 0;
53 	int i;
54 	printf ("[%s%08x%s]%s", FONT_BRIGHT_BLUE, base, FONT_RESET, FONT_BRIGHT_PURPLE);
55 	for (i=0; i < baselen; i++)
56 	{
57 		if (base+i >= len)
58 		{
59 			printf (" \?\?");
60 			retval = -1;
61 		} else {
62 			printf (" %02x", mem[base+i]);
63 		}
64 	}
65 	switch (baselen)
66 	{
67 		case 3:  printf (                     "%s ", FONT_RESET); break;
68 		case 2:  printf (                  "%s    ", FONT_RESET); break;
69 		case 1:  printf (               "%s       ", FONT_RESET); break;
70 		case 0:  printf (            "%s          ", FONT_RESET); break;
71 		default: printf ("%s\n                    ", FONT_RESET); break;
72 	}
73 	if (retval) { printf ("%sRAN OUT OF DATA%s\n", FONT_BRIGHT_RED, FONT_RESET); }
74 	return retval;
75 }
76 
DumpInstrument(unsigned char * mem,int len,int base,int instrument)77 int DumpInstrument (unsigned char *mem, int len, int base, int instrument)
78 {
79 	uint16_t samplelength;
80 	uint16_t loopstart;
81 	uint16_t looplength;
82 	int i;
83 
84 	printf ("[%sINSTRUMENT %02d / PCM Sample%s]\n", FONT_BRIGHT_CYAN, instrument + 1, FONT_RESET);
85 
86 	if (DumpPrefix (mem, len, base + 0x00, 22)) return -1;
87 	printf ("Name: \"");
88 	for (i=0; i < 22; i++)
89 	{
90 		if (!mem[base + 0x00 + i])
91 		{
92 			break;
93 		}
94 		putchar (mem[base + 0x00 + i]);
95 	}
96 	printf("\"\n");
97 
98 	if (DumpPrefix (mem, len, base + 22, 2)) return -1;
99 	samplelength = (mem[base+22] << 8) | mem[base+23];
100 	printf ("SampleLength: %d\n", (int)samplelength);
101 
102 	if (DumpPrefix (mem, len, base + 24, 1)) return -1;
103 	printf ("FineTuning: %d", (int)(int8_t)((mem[base + 24] & 0x0f)|((mem[base+24]&0x08)?0xf0:0x00)));
104 	if (mem[base+24]&0xf0) printf ("%s (WARNING, the upper nibble is not zero)%s", FONT_BRIGHT_YELLOW, FONT_RESET);
105 	printf("\n");
106 
107 	if (DumpPrefix (mem, len, base + 25, 1)) return -1;
108 	printf ("Volume: %d", mem[base+25]);
109 	if (mem[base+25] > 64)
110 	{
111 		printf ("%s (WARNING, value out of range)%s", FONT_BRIGHT_YELLOW, FONT_RESET);
112 	}
113 	printf("\n");
114 
115 	if (DumpPrefix (mem, len, base + 26, 2)) return -1;
116 	loopstart = (mem[base+26] << 8) | mem[base+27];
117 	printf ("LoopStart: %d", (int)loopstart);
118 	if ((samplelength && (loopstart > samplelength)) && ((!samplelength) && (loopstart > 1)))
119 	{
120 		printf ("%s (WARNING, value out of range)%s", FONT_BRIGHT_YELLOW, FONT_RESET);
121 	}
122 	printf ("\n");
123 
124 	if (DumpPrefix (mem, len, base + 26, 2)) return -1;
125 	looplength = (mem[base+26] << 8) | mem[base+27];
126 	printf ("LoopLength: %d", (int)looplength);
127 	if ((samplelength && ((int)loopstart + looplength > samplelength)) && ((!samplelength) && (looplength > 0)))
128 	{
129 		printf ("%s (WARNING, value out of range)%s", FONT_BRIGHT_YELLOW, FONT_RESET);
130 	}
131 	printf ("\n");
132 
133 	return 0;
134 }
135 
136 #if 0
137 void print_note (unsigned char note)
138 {
139 	char *text[16] = {"C-", "C#", "D-", "D#", "E-", "F-", "F#", "G-", "G#", "A-", "A#", "B-", "?c", "?d", "?e", "?f"};
140 
141 	if (note == 0xfe)
142 	{
143 		printf ("-0-");
144 		if (savepatterns)
145 		{
146 			fprintf (savepatterns, "-0-");
147 		}
148 		return;
149 	}
150 	if (note >= 0x60)
151 	{
152 		printf ("...");
153 		if (savepatterns)
154 		{
155 			fprintf (savepatterns, "...");
156 		}
157 		return;
158 	}
159 
160 	if ((note & 0x0f) >= 12) printf ("%s", FONT_BRIGHT_RED);
161 	printf ("%s", text[note & 0x0f]);
162 	if (savepatterns)
163 	{
164 		fprintf (savepatterns, "%s", text[note & 0x0f]);
165 	}
166 	if ((note & 0x0f) >= 12) printf ("%s", FONT_RESET);
167 
168 	printf ("%d", note >> 4);
169 	if (savepatterns)
170 	{
171 		fprintf (savepatterns, "%d", note>>4);
172 	}
173 }
174 #endif
175 
DumpPattern(unsigned char * mem,int len,int base,int channels)176 int DumpPattern (unsigned char *mem, int len, int base, int channels)
177 {
178 	int i;
179 
180 	for (i=0; i < 64; i++)
181 	{
182 		int j;
183 
184 		if (DumpPrefix (mem, len, base, channels * 4)) return -1;
185 
186 		printf("%02X |", i);
187 		if (savepatterns)
188 		{
189 			fprintf (savepatterns, "%02X | ", i);
190 		}
191 
192 		for (j=0; j < channels; j++)
193 		{
194 			uint8_t instrument = (mem[base] & 0xf0) | (mem[base+2]>>4);
195 			uint16_t period = ((mem[base] & 0x0f) << 8) | mem[base+1];
196 			uint8_t effect = mem[base+2] & 0x0f;
197 			uint8_t param = mem[base+3];
198 			base += 4;
199 
200 			if (period)
201 			{
202 				printf (" %03X ", period);
203 			} else {
204 				printf (" ... ");
205 			}
206 
207 			if (instrument)
208 			{
209 				printf ("%02X ", instrument);
210 			} else {
211 				printf (".. ");
212 			}
213 
214 			printf ("%01X%02X |", effect, param);
215 
216 			if (savepatterns)
217 			{
218 				if (period)
219 				{
220 					fprintf (savepatterns, " %03X ", period);
221 				} else {
222 					fprintf (savepatterns, " ... ");
223 				}
224 
225 				if (instrument)
226 				{
227 					fprintf (savepatterns, "%02X ", instrument);
228 				} else {
229 					fprintf (savepatterns, ".. ");
230 				}
231 
232 				fprintf (savepatterns, "%01X%02X |", effect, param);
233 			}
234 		}
235 		printf("\n");
236 		if (savepatterns)
237 		{
238 			fprintf (savepatterns, "\n");
239 		}
240 	}
241 
242 	return 0;
243 }
244 
DumpPatterns(unsigned char * mem,int len,int ofs,int channels,int patterns)245 int DumpPatterns (unsigned char *mem, int len, int ofs, int channels, int patterns)
246 {
247 	int i;
248 
249 	for (i=0; i < patterns; i++)
250 	{
251 		printf ("[%sPATTERN %d%s]\n", FONT_BRIGHT_CYAN, i, FONT_RESET);
252 		if (savepatterns)
253 		{
254 			fprintf (savepatterns, "PATTERN %d\n", i);
255 		}
256 		if (DumpPattern(mem, len, ofs + i * channels * 256, channels)) return -1;
257 	}
258 
259 	return 0;
260 }
261 
262 #if 0
263 int DumpHeader (unsigned char *mem, int len)
264 {
265 	int i, j;
266 
267 	if (len < 0x30)
268 	{
269 		fprintf (stderr, "%sERROR: len < sizeof(FileHeader)%s\n", FONT_BRIGHT_RED, FONT_RESET);
270 		return 1;
271 	}
272 
273 	printf ("[%sHEADER%s]\n", FONT_BRIGHT_CYAN, FONT_RESET);
274 
275 	/* hdr.name */
276 	DumpPrefix (mem, len, 0x00, 20);
277 	printf ("Name: \"");
278 	for (i=0; i < 20; i++)
279 	{
280 		if (!mem[0x00+i])
281 			break;
282 		printf ("%c", (char)mem[0x00+i]);
283 	}
284 	printf ("\"\n");
285 
286 	DumpPrefix (mem, len, 0x14, 8);
287 	printf ("Tracker: \"");
288 	j=0;
289 	for (i=0; i < 8; i++)
290 	{
291 		if ((mem[0x14+i] < 0x20) || (mem[0x14+i] >= 0x80))
292 		{
293 			j = 1;
294 		}
295 	}
296 	for (i=0; i < 8; i++)
297 	{
298 		if (!mem[0x14+i])
299 			break;
300 		printf ("%c", (char)mem[0x14+i]);
301 	}
302 	printf ("\" %s%s%s\n",
303 		j ? FONT_BRIGHT_RED : FONT_BRIGHT_GREEN,
304 		j ? "Non-ASCII" : "OK",
305 		FONT_RESET);
306 
307 	DumpPrefix (mem, len, 0x1c, 1);
308 	printf ("Signature: %s%s%s\n",
309 		(mem[0x1c] == 0x1A) ? FONT_BRIGHT_GREEN : (mem[0x1c] == 0x02) ? FONT_BRIGHT_YELLOW : FONT_BRIGHT_RED,
310 		(mem[0x1c] == 0x1A) ? "OK" : (mem[0x1c] == 0x02) ? "Known invalid value" : "Failed!!!!",
311 		FONT_RESET);
312 
313 	DumpPrefix (mem, len, 0x1d, 1);
314 	printf ("Type: ");
315 	switch (mem[0x1d])
316 	{
317 		case  1: printf ("STM song w/o samples\n"); break;
318 		case  2: printf ("STM module\n"); break;
319 		case 16: printf ("S3M module, FAILED !!!!!\n"); return 1;
320 		default: printf ("Unknown, FAILED !!!!!\n"); return 1;
321 	}
322 
323 	DumpPrefix (mem, len, 0x1e, 2);
324 	printf ("Version: %d.%d\n", mem[0x1e], mem[0x1f]);
325 
326 	DumpPrefix (mem, len, 0x20, 1);
327 	printf ("Initial Tempo: %d\n", mem[0x20]);
328 
329 	DumpPrefix (mem, len, 0x21, 1);
330 	printf ("Patterns: %d\n", mem[0x21]);
331 
332 	DumpPrefix (mem, len, 0x22, 1);
333 	printf ("Global Volume: %d\n", mem[0x22]);
334 
335 	DumpPrefix (mem, len, 0x23, 13);
336 	printf ("(Reserved/not used)\n");
337 
338 	return 0;
339 }
340 
341 #endif
342 
DumpOrders(unsigned char * mem,int len,int ofs,int count)343 int DumpOrders (unsigned char *mem, int len, int ofs, int count)
344 {
345 	int MaxOrder = 0;
346 	int i;
347 
348 	printf ("[%sORDERS%s]\n", FONT_BRIGHT_CYAN, FONT_RESET);
349 
350 	if (DumpPrefix (mem, len, ofs, count)) return -1;
351 
352 	for (i=0; i < count; i++)
353 	{
354 		printf ("%d ", mem[ofs+i]);
355 		if (mem[ofs+i] > MaxOrder)
356 		{
357 			MaxOrder = mem[ofs+i];
358 		}
359 	}
360 	printf ("\n");
361 	if (count < 128)
362 	{
363 		if (DumpPrefix (mem, len, ofs + count, 128-count)) return -1;
364 		printf("(");
365 		for (i=count; i < 128; i++)
366 		{
367 			printf ("%d%s", mem[ofs+i], (i!=127)?" ":"");
368 			if (mem[ofs+i] > MaxOrder)
369 			{
370 				MaxOrder = mem[ofs+i];
371 			}
372 		}
373 		printf (")\n");
374 	}
375 
376 	return MaxOrder;
377 }
378 
379 #if 0
380 
381 int ParseSTM (unsigned char *mem, int len)
382 {
383 	int i;
384 	int patternlen = 0;
385 
386 	if (DumpHeader (mem, len))
387 	{
388 		return -1;
389 	}
390 
391 	for (i=0; i < 31; i++)
392 	{
393 		if (DumpInstrument (mem, len, 0x30 + i*0x20, i))
394 		{
395 			return -1;
396 		}
397 	}
398 
399 	if (DumpOrders (mem, len, mem[0x1f]?128:64, mem[0x21]))
400 	{
401 		return -1;
402 	}
403 
404 	for (i=0; i < mem[0x21]; i++)
405 	{
406 		int retval = DumpPattern (mem, len, 0x30 + 0x20*31 + (mem[0x1f]?128:64) + patternlen, i);
407 		if (retval < 0)
408 		{
409 			return -1;
410 		}
411 		patternlen += DumpPattern (mem, len, 0x30 + 0x20*31 + (mem[0x1f]?128:64) + patternlen, i);
412 	}
413 	if (savepatterns)
414 	{
415 		fclose (savepatterns);
416 	}
417 
418 	for (i=0; i < 31; i++)
419 	{
420 		if (Instruments[i].length > 0)
421 		{
422 			printf ("[%sINSTRUMENT %02x SAMPLE DATA%s]\n", FONT_BRIGHT_CYAN, i + 1, FONT_RESET);
423 
424 			printf ("[%s%08x-%08x%s]%s\n", FONT_BRIGHT_BLUE, Instruments[i].offset, Instruments[i].offset + Instruments[i].length - 1, FONT_RESET, FONT_RESET);
425 			if (savesamples)
426 			{
427 				if ((Instruments[i].offset + Instruments[i].length) > len)
428 				{
429 					printf ("%sWARNING: Unable to store instrument %d, missing data\n%s", FONT_BRIGHT_YELLOW, i + 1, FONT_RESET);
430 				} else {
431 					char filename[33];
432 					int fd;
433 					snprintf (filename, sizeof (filename), "Instrument %02d.signed 8bit.sample", i+1);
434 					fd = open (filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
435 					if (fd < 0)
436 					{
437 						printf ("%sWARNING: Unable to open %s%s\n", FONT_BRIGHT_YELLOW, filename, FONT_RESET);
438 					} else {
439 						write (fd, mem + Instruments[i].offset, Instruments[i].length);
440 						close (fd);
441 						printf ("Saved %s\n", filename);
442 					}
443 				}
444 			}
445 		}
446 	}
447 
448 	return 0;
449 }
450 
451 #endif
452 
ParseMOD(unsigned char * mem,int len,int instruments,int channels,int signature)453 int ParseMOD (unsigned char *mem, int len, int instruments, int channels, int signature)
454 {
455 	int i, MaxOrder;
456 	uint8_t NoOrders;
457 	int ofs = 0;
458 
459 	if (DumpPrefix (mem, len, 0, 20)) return -1;
460 	printf ("Name: \"");
461 	for (i=0; i < 20; i++)
462 	{
463 		if (!mem[0x00+i])
464 			break;
465 		printf ("%c", (char)mem[0x00+i]);
466 	}
467 	ofs = 20;
468 	printf ("\"\n");
469 
470 	for (i=0; i < instruments; i++)
471 	{
472 		if (DumpInstrument(mem, len, ofs, i)) return -1;
473 		ofs += 30;
474 	}
475 
476 	if (DumpPrefix (mem, len, ofs, 1)) return -1;
477 	NoOrders = mem[ofs++];
478 	if ((NoOrders < 1) || (NoOrders > 128))
479 	{
480 		printf ("Number of orders: %d %s(OUT OF RANGE)%s\n", (int)NoOrders, FONT_BRIGHT_RED, FONT_RESET);
481 	} else {
482 		printf ("Number of orders: %d\n", (int)NoOrders);
483 	}
484 
485 	if (DumpPrefix (mem, len, ofs, 1)) return -1;
486 	printf ("(Restart position: %d)\n", (int)mem[ofs++]);
487 
488 	MaxOrder = DumpOrders(mem, len, ofs, NoOrders);
489 	if (MaxOrder < 0) return -1;
490 	ofs += 128;
491 
492 	if (signature)
493 	{
494 		if (DumpPrefix (mem, len, ofs, 4)) return -1;
495 		printf ("Signtaure: \"%c%c%c%c\"\n", mem[ofs+0], mem[ofs+1], mem[ofs+2], mem[ofs+3]);
496 		ofs+=4;
497 	}
498 
499 	if (DumpPatterns(mem, len, ofs, channels, MaxOrder + 1)) return -1;
500 
501 	ofs += channels * 256;
502 
503 #if 0
504 	if (DumpSamples(mem, len, ofs, instruments)) return -1;
505 #endif
506 
507 	return 0;
508 }
509 
preParseMOD15(unsigned char * mem,int len,int * channels15instruments)510 int preParseMOD15 (unsigned char *mem, int len, int *channels15instruments)
511 {
512 	int i;
513 	uint32_t samplelengths15 = 0;
514 	int canbe15instruments = 1;
515 	uint8_t highestorder = 0;
516 
517 	if (len < (20 + 15*30))
518 	{
519 		printf ("%sERROR: no space for even 15 instruments, the minimum%s\n", FONT_BRIGHT_RED, FONT_RESET);
520 		return -2;
521 	}
522 
523 	for (i=0; i < 15; i++)
524 	{
525 		uint16_t samplelength = (mem[20+22+i*30] << 8) | mem[20+23+i*30];
526 		uint8_t  finetune = mem[20+24+i*30];
527 		uint8_t  volume = mem[20+25+i*30];
528 		uint16_t repeatstart = (mem[20+26+i*30] << 8) | mem[20+27+i*30];
529 		uint16_t repeatlen = (mem[20+28+i*30] << 8) | mem[20+29+i*30];
530 
531 		if (finetune & 0xf0)
532 		{
533 			printf ("%sWARNING: instrument %d have high nibble in finetuning set%s\n", FONT_BRIGHT_YELLOW, i + 1, FONT_RESET);
534 		}
535 		if (volume > 64)
536 		{
537 			printf ("%sERROR: instrument %d volume is out of range%s\n", FONT_BRIGHT_RED, i + 1, FONT_RESET);
538 			return -2;
539 		}
540 		if (samplelength <= 1)
541 		{
542 			if (repeatlen > 1)
543 			{
544 				printf ("%sERROR: instrument %d looplen is out of range for empty instrument%s\n", FONT_BRIGHT_RED, i + 1, FONT_RESET);
545 				return -2;
546 			}
547 		} else {
548 			if (repeatstart >= samplelength)
549 			{
550 				printf ("%sERROR: instrument %d loopstart is out of range%s\n", FONT_BRIGHT_RED, i + 1, FONT_RESET);
551 				return -2;
552 			}
553 			if (repeatlen > samplelength)
554 			{
555 				printf ("%sERROR: instrument %d looplen is out of range%s\n", FONT_BRIGHT_RED, i + 1, FONT_RESET);
556 				return -2;
557 			}
558 			if (((uint32_t)repeatstart + repeatlen) > samplelength)
559 			{
560 				printf ("%sERROR: instrument %d loopstart + looplen is out of range%s\n", FONT_BRIGHT_RED, i + 1, FONT_RESET);
561 				return -2;
562 			}
563 			samplelengths15 += samplelength;
564 		}
565 		//printf ("15.Instrument: len=%04x loopstart=%04x looplen=%04x volume=%02x finetune=%d\n", samplelength, repeatstart, repeatlen, volume, finetune);
566 	}
567 
568 
569 	if (len < (20 + 15*30 + 130))
570 	{
571 		printf ("%sERROR: No room for order data - can not be 15 instrument format%s\n", FONT_BRIGHT_RED, FONT_RESET);
572 		return -2;
573 	}
574 
575 	if ((mem[20+15*30] < 1) || (mem[20+15*30] > 128))
576 	{
577 		printf ("%sWARNING: Order length (%d) is out of range - can not be 15 instrument format%s\n", FONT_BRIGHT_YELLOW, mem[20+22+15*30], FONT_RESET);
578 		return -1;
579 	}
580 
581 	for (i=0; i < 128; i++)
582 	{
583 		if (mem[20+15*30+2 + i] > highestorder)
584 		{
585 			highestorder = mem[20+15*30+2 + i];
586 		}
587 	}
588 	if (highestorder >= 64)
589 	{
590 		printf ("%sWARNING: Order > 63 not possible in 15 instrument format - can not be 15 instrument file%s\n", FONT_BRIGHT_YELLOW, FONT_RESET);
591 		return -1;
592 	}
593 
594 	if ((20+15*30+2+128+4 + (highestorder+1)*1024) > len)
595 	{
596 		printf ("%sERROR: Not enough space for pattern data - can not be a 15 instrument file%s\n", FONT_BRIGHT_RED, FONT_RESET);
597 		return -1;
598 	}
599 
600 	if ((20+15*30+2+128+4 + (highestorder+1)*1024 + (samplelengths15<<1)) > len)
601 	{
602 		printf ("%sERROR: Not enough space for sample data - can not be a 15 instrument file%s\n", FONT_BRIGHT_RED, FONT_RESET);
603 		return -1;
604 	}
605 
606 	if ((20+15*30+2+128+4 + (highestorder+1)*1024 + (samplelengths15<<1)) != len)
607 	{
608 		printf ("%sWARNING: Got %d bytes extra data for 15 instrument file%s\n", FONT_BRIGHT_YELLOW, len - (20+15*30+2+128+4 + (highestorder+1)*1024 + (samplelengths15<<1)), FONT_RESET);
609 	}
610 
611 	return canbe15instruments;
612 }
613 
preParseMOD31(unsigned char * mem,int len,int * channels31instruments)614 int preParseMOD31 (unsigned char *mem, int len, int *channels31instruments)
615 {
616 	int i;
617 	uint32_t samplelengths31 = 0;
618 	int canbe31instruments = 0;
619 	uint8_t highestorder = 0;
620 
621 	if (len < (20 + 31*30 + 130 + 4))
622 	{
623 		printf ("%sERROR: no space for even 31 instruments, the minimum%s\n", FONT_BRIGHT_RED, FONT_RESET);
624 		return -1;
625 	}
626 
627 	for (i=0; i < 31; i++)
628 	{
629 		uint16_t samplelength = (mem[20+22+i*30] << 8) | mem[20+23+i*30];
630 		uint8_t  finetune = mem[20+24+i*30];
631 		uint8_t  volume = mem[20+25+i*30];
632 		uint16_t repeatstart = (mem[20+26+i*30] << 8) | mem[20+27+i*30];
633 		uint16_t repeatlen = (mem[20+28+i*30] << 8) | mem[20+29+i*30];
634 
635 		if (finetune & 0xf0)
636 		{
637 			printf ("%sWARNING: instrument %d have high nibble in finetuning set%s\n", FONT_BRIGHT_YELLOW, i + 1, FONT_RESET);
638 		}
639 		if (volume > 64)
640 		{
641 			printf ("%sWARNING: instrument %d volume is out of range - can not be 31 instrument file%s\n", FONT_BRIGHT_YELLOW, i + 1, FONT_RESET);
642 			return -1;
643 		}
644 		if (samplelength <= 1)
645 		{
646 			if (repeatlen > 1)
647 			{
648 				printf ("%sWARNING: instrument %d looplen is out of range for empty instrument - can not be 31 instrument file%s\n", FONT_BRIGHT_YELLOW, i + 1, FONT_RESET);
649 				return -1;
650 			}
651 		} else {
652 			if (repeatstart >= samplelength)
653 			{
654 				printf ("%sWARNING: instrument %d loopstart is out of range - can not be 31 instrument file%s\n", FONT_BRIGHT_YELLOW, i + 1, FONT_RESET);
655 				return -1;
656 			}
657 			if (repeatlen > samplelength)
658 			{
659 				printf ("%sWARNING: instrument %d looplen is out of range - can not be 31 instrument file%s\n", FONT_BRIGHT_YELLOW, i + 1, FONT_RESET);
660 				return -1;
661 			}
662 			if (((uint32_t)repeatstart + repeatlen) > samplelength)
663 			{
664 				printf ("%sWARNING: instrument %d loopstart + looplen is out of range - can not be 31 instrument file%s\n", FONT_BRIGHT_YELLOW, i + 1, FONT_RESET);
665 				return -1;
666 			}
667 			samplelengths31 += samplelength;
668 		}
669 		//printf ("31.Instrument: len=%04x loopstart=%04x looplen=%04x volume=%02x finetune=%d\n", samplelength, repeatstart, repeatlen, volume, finetune);
670 	}
671 
672 	if ((mem[20+31*30] < 1) || (mem[20+31*30] > 128))
673 	{
674 		printf ("%sWARNING: Order length (%d) is out of range - can not be 31 instrument format%s\n", FONT_BRIGHT_YELLOW, mem[20+31*30], FONT_RESET);
675 
676 		return -1;
677 	}
678 	for (i=0; i < 128; i++)
679 	{
680 		if (mem[20+31*30+2 + i] > highestorder)
681 		{
682 			highestorder = mem[20+31*30+2 + i];
683 		}
684 	}
685 
686 	if (!memcmp(&mem[20+31*30+2+128], "M.K.", 4))
687 	{
688 		printf ("%sNOTE: got M.K. signature in 31 instrument format%s\n", FONT_BRIGHT_GREEN, FONT_RESET);
689 		canbe31instruments = 1;
690 		if (highestorder >= 64)
691 		{
692 			printf ("%sWARNING: Order > 63 not possible in M.K. format - can not be 31 instrument file%s\n", FONT_BRIGHT_YELLOW, FONT_RESET);
693 			return -1;
694 		}
695 	} else if (!memcmp(&mem[20+31*30+2+128], "M!K!", 4))
696 	{
697 		printf ("%sNOTE: got M!K! signature in 31 instrument format%s\n", FONT_BRIGHT_GREEN, FONT_RESET);
698 		canbe31instruments = 1;
699 		if (highestorder < 64)
700 		{
701 			printf ("%sWARNING: Order < 64 not possible in M!K! format - can not be 31 instrument file%s\n", FONT_BRIGHT_YELLOW, FONT_RESET);
702 			return -1;
703 		}
704 	} else if (!memcmp(&mem[20+31*30+2+128], "FLT4", 4)) { printf ("%sNOTE: got FLT4 - probably StarTrekker 4-channel MOD%s\n",   FONT_BRIGHT_GREEN, FONT_RESET); canbe31instruments = (highestorder < 64); *channels31instruments = 4;
705 	} else if (!memcmp(&mem[20+31*30+2+128], "FLT8", 4)) { printf ("%sNOTE: got FLT8 - probably StarTrekker 8-channel MOD%s\n",   FONT_BRIGHT_GREEN, FONT_RESET); canbe31instruments = (highestorder < 64); *channels31instruments = 8;
706 	} else if (!memcmp(&mem[20+31*30+2+128], "CD81", 4)) { printf ("%sNOTE: got CD81 - probably Oktalyzer for Atari ST?%s\n",     FONT_BRIGHT_GREEN, FONT_RESET); canbe31instruments = (highestorder < 64); *channels31instruments = 8;
707 	} else if (!memcmp(&mem[20+31*30+2+128], "OKTA", 4)) { printf ("%sNOTE: got OKTA - probably Oktalyzer for Atari ST?%s\n",     FONT_BRIGHT_GREEN, FONT_RESET); canbe31instruments = (highestorder < 64); *channels31instruments = 8;
708 	} else if (!memcmp(&mem[20+31*30+2+128], "OCTA", 4)) { printf ("%sNOTE: got OKTA - probably OctaMED%s\n",                     FONT_BRIGHT_GREEN, FONT_RESET); canbe31instruments = (highestorder < 64); *channels31instruments = 8;
709 
710 	} else if (!memcmp(&mem[20+31*30+2+128], "1TDZ", 4)) { printf ("%sNOTE: got 1TDZ - TakeTracker extension for 1 channel%s\n",  FONT_BRIGHT_GREEN, FONT_RESET); canbe31instruments = (highestorder < 64); *channels31instruments = 1;
711 	} else if (!memcmp(&mem[20+31*30+2+128], "2TDZ", 4)) { printf ("%sNOTE: got 2TDZ - TakeTracker extension for 3 channel%s\n",  FONT_BRIGHT_GREEN, FONT_RESET); canbe31instruments = (highestorder < 64); *channels31instruments = 2;
712 	} else if (!memcmp(&mem[20+31*30+2+128], "3TDZ", 4)) { printf ("%sNOTE: got 3TDZ - TakeTracker extension for 3 channel%s\n",  FONT_BRIGHT_GREEN, FONT_RESET); canbe31instruments = (highestorder < 64); *channels31instruments = 3;
713 	} else if (!memcmp(&mem[20+31*30+2+128], "5CHN", 4)) { printf ("%sNOTE: got 5CHN - TakeTracker extension for 5 channel%s\n",  FONT_BRIGHT_GREEN, FONT_RESET); canbe31instruments = (highestorder < 64); *channels31instruments = 5;
714 	} else if (!memcmp(&mem[20+31*30+2+128], "7CHN", 4)) { printf ("%sNOTE: got 7CHN - TakeTracker extension for 7 channel%s\n",  FONT_BRIGHT_GREEN, FONT_RESET); canbe31instruments = (highestorder < 64); *channels31instruments = 7;
715 	} else if (!memcmp(&mem[20+31*30+2+128], "9CHN", 4)) { printf ("%sNOTE: got 9CHN - TakeTracker extension for 9 channel%s\n",  FONT_BRIGHT_GREEN, FONT_RESET); canbe31instruments = (highestorder < 64); *channels31instruments = 9;
716 	} else if (!memcmp(&mem[20+31*30+2+128], "10CN", 4)) { printf ("%sNOTE: got 10CN - TakeTracker extension for 10 channel%s\n", FONT_BRIGHT_GREEN, FONT_RESET); canbe31instruments = (highestorder < 64); *channels31instruments = 10;
717 	} else if (!memcmp(&mem[20+31*30+2+128], "11CN", 4)) { printf ("%sNOTE: got 11CN - TakeTracker extension for 11 channel%s\n", FONT_BRIGHT_GREEN, FONT_RESET); canbe31instruments = (highestorder < 64); *channels31instruments = 11;
718 	} else if (!memcmp(&mem[20+31*30+2+128], "12CN", 4)) { printf ("%sNOTE: got 12CN - TakeTracker extension for 12 channel%s\n", FONT_BRIGHT_GREEN, FONT_RESET); canbe31instruments = (highestorder < 64); *channels31instruments = 12;
719 	} else if (!memcmp(&mem[20+31*30+2+128], "13CN", 4)) { printf ("%sNOTE: got 13CN - TakeTracker extension for 13 channel%s\n", FONT_BRIGHT_GREEN, FONT_RESET); canbe31instruments = (highestorder < 64); *channels31instruments = 13;
720 	} else if (!memcmp(&mem[20+31*30+2+128], "14CN", 4)) { printf ("%sNOTE: got 14CN - TakeTracker extension for 14 channel%s\n", FONT_BRIGHT_GREEN, FONT_RESET); canbe31instruments = (highestorder < 64); *channels31instruments = 14;
721 	} else if (!memcmp(&mem[20+31*30+2+128], "15CN", 4)) { printf ("%sNOTE: got 15CN - TakeTracker extension for 15 channel%s\n", FONT_BRIGHT_GREEN, FONT_RESET); canbe31instruments = (highestorder < 64); *channels31instruments = 15;
722 	} else if (!memcmp(&mem[20+31*30+2+128], "16CN", 4)) { printf ("%sNOTE: got 16CN - TakeTracker extension for 16 channel%s\n", FONT_BRIGHT_GREEN, FONT_RESET); canbe31instruments = (highestorder < 64); *channels31instruments = 16;
723 	} else if (!memcmp(&mem[20+31*30+2+128], "17CN", 4)) { printf ("%sNOTE: got 17CN - TakeTracker extension for 17 channel%s\n", FONT_BRIGHT_GREEN, FONT_RESET); canbe31instruments = (highestorder < 64); *channels31instruments = 17;
724 	} else if (!memcmp(&mem[20+31*30+2+128], "18CN", 4)) { printf ("%sNOTE: got 18CN - TakeTracker extension for 18 channel%s\n", FONT_BRIGHT_GREEN, FONT_RESET); canbe31instruments = (highestorder < 64); *channels31instruments = 18;
725 	} else if (!memcmp(&mem[20+31*30+2+128], "19CN", 4)) { printf ("%sNOTE: got 19CN - TakeTracker extension for 19 channel%s\n", FONT_BRIGHT_GREEN, FONT_RESET); canbe31instruments = (highestorder < 64); *channels31instruments = 19;
726 	} else if (!memcmp(&mem[20+31*30+2+128], "20CN", 4)) { printf ("%sNOTE: got 20CN - TakeTracker extension for 20 channel%s\n", FONT_BRIGHT_GREEN, FONT_RESET); canbe31instruments = (highestorder < 64); *channels31instruments = 20;
727 	} else if (!memcmp(&mem[20+31*30+2+128], "21CN", 4)) { printf ("%sNOTE: got 21CN - TakeTracker extension for 21 channel%s\n", FONT_BRIGHT_GREEN, FONT_RESET); canbe31instruments = (highestorder < 64); *channels31instruments = 21;
728 	} else if (!memcmp(&mem[20+31*30+2+128], "22CN", 4)) { printf ("%sNOTE: got 22CN - TakeTracker extension for 22 channel%s\n", FONT_BRIGHT_GREEN, FONT_RESET); canbe31instruments = (highestorder < 64); *channels31instruments = 22;
729 	} else if (!memcmp(&mem[20+31*30+2+128], "23CN", 4)) { printf ("%sNOTE: got 23CN - TakeTracker extension for 23 channel%s\n", FONT_BRIGHT_GREEN, FONT_RESET); canbe31instruments = (highestorder < 64); *channels31instruments = 23;
730 	} else if (!memcmp(&mem[20+31*30+2+128], "24CN", 4)) { printf ("%sNOTE: got 24CN - TakeTracker extension for 24 channel%s\n", FONT_BRIGHT_GREEN, FONT_RESET); canbe31instruments = (highestorder < 64); *channels31instruments = 24;
731 	} else if (!memcmp(&mem[20+31*30+2+128], "25CN", 4)) { printf ("%sNOTE: got 25CN - TakeTracker extension for 25 channel%s\n", FONT_BRIGHT_GREEN, FONT_RESET); canbe31instruments = (highestorder < 64); *channels31instruments = 25;
732 	} else if (!memcmp(&mem[20+31*30+2+128], "26CN", 4)) { printf ("%sNOTE: got 26CN - TakeTracker extension for 26 channel%s\n", FONT_BRIGHT_GREEN, FONT_RESET); canbe31instruments = (highestorder < 64); *channels31instruments = 26;
733 	} else if (!memcmp(&mem[20+31*30+2+128], "27CN", 4)) { printf ("%sNOTE: got 27CN - TakeTracker extension for 27 channel%s\n", FONT_BRIGHT_GREEN, FONT_RESET); canbe31instruments = (highestorder < 64); *channels31instruments = 27;
734 	} else if (!memcmp(&mem[20+31*30+2+128], "28CN", 4)) { printf ("%sNOTE: got 28CN - TakeTracker extension for 28 channel%s\n", FONT_BRIGHT_GREEN, FONT_RESET); canbe31instruments = (highestorder < 64); *channels31instruments = 28;
735 	} else if (!memcmp(&mem[20+31*30+2+128], "29CN", 4)) { printf ("%sNOTE: got 29CN - TakeTracker extension for 29 channel%s\n", FONT_BRIGHT_GREEN, FONT_RESET); canbe31instruments = (highestorder < 64); *channels31instruments = 29;
736 	} else if (!memcmp(&mem[20+31*30+2+128], "30CN", 4)) { printf ("%sNOTE: got 30CN - TakeTracker extension for 30 channel%s\n", FONT_BRIGHT_GREEN, FONT_RESET); canbe31instruments = (highestorder < 64); *channels31instruments = 30;
737 	} else if (!memcmp(&mem[20+31*30+2+128], "31CN", 4)) { printf ("%sNOTE: got 31CN - TakeTracker extension for 31 channel%s\n", FONT_BRIGHT_GREEN, FONT_RESET); canbe31instruments = (highestorder < 64); *channels31instruments = 31;
738 	} else if (!memcmp(&mem[20+31*30+2+128], "33CN", 4)) { printf ("%sNOTE: got 32CN - TakeTracker extension for 32 channel%s\n", FONT_BRIGHT_GREEN, FONT_RESET); canbe31instruments = (highestorder < 64); *channels31instruments = 32;
739 
740 	} else if (!memcmp(&mem[20+31*30+2+128], "2CHN", 4)) { printf ("%sNOTE: got 2CHN - uncommon 2 channel format%s\n",            FONT_BRIGHT_GREEN, FONT_RESET); canbe31instruments = (highestorder < 64); *channels31instruments = 2;
741 	} else if (!memcmp(&mem[20+31*30+2+128], "6CHN", 4)) { printf ("%sNOTE: got 6CHN - common 6 channel format%s\n",              FONT_BRIGHT_GREEN, FONT_RESET); canbe31instruments = (highestorder < 64); *channels31instruments = 6;
742 	} else if (!memcmp(&mem[20+31*30+2+128], "8CHN", 4)) { printf ("%sNOTE: got 8CHN - common 8 channel format%s\n",              FONT_BRIGHT_GREEN, FONT_RESET); canbe31instruments = (highestorder < 64); *channels31instruments = 8;
743 	} else if (!memcmp(&mem[20+31*30+2+128], "10CH", 4)) { printf ("%sNOTE: got 10CH - common 10 channel format%s\n",              FONT_BRIGHT_GREEN, FONT_RESET); canbe31instruments = (highestorder < 64); *channels31instruments = 10;
744 	} else if (!memcmp(&mem[20+31*30+2+128], "12CH", 4)) { printf ("%sNOTE: got 12CH - common 10 channel format%s\n",              FONT_BRIGHT_GREEN, FONT_RESET); canbe31instruments = (highestorder < 64); *channels31instruments = 12;
745 	} else if (!memcmp(&mem[20+31*30+2+128], "14CH", 4)) { printf ("%sNOTE: got 14CH - common 10 channel format%s\n",              FONT_BRIGHT_GREEN, FONT_RESET); canbe31instruments = (highestorder < 64); *channels31instruments = 14;
746 	} else if (!memcmp(&mem[20+31*30+2+128], "16CH", 4)) { printf ("%sNOTE: got 16CH - common 10 channel format%s\n",              FONT_BRIGHT_GREEN, FONT_RESET); canbe31instruments = (highestorder < 64); *channels31instruments = 16;
747 	} else if (!memcmp(&mem[20+31*30+2+128], "18CH", 4)) { printf ("%sNOTE: got 18CH - common 10 channel format%s\n",              FONT_BRIGHT_GREEN, FONT_RESET); canbe31instruments = (highestorder < 64); *channels31instruments = 18;
748 	} else if (!memcmp(&mem[20+31*30+2+128], "20CH", 4)) { printf ("%sNOTE: got 20CH - common 10 channel format%s\n",              FONT_BRIGHT_GREEN, FONT_RESET); canbe31instruments = (highestorder < 64); *channels31instruments = 20;
749 	} else if (!memcmp(&mem[20+31*30+2+128], "22CH", 4)) { printf ("%sNOTE: got 22CH - common 10 channel format%s\n",              FONT_BRIGHT_GREEN, FONT_RESET); canbe31instruments = (highestorder < 64); *channels31instruments = 22;
750 	} else if (!memcmp(&mem[20+31*30+2+128], "24CH", 4)) { printf ("%sNOTE: got 24CH - common 10 channel format%s\n",              FONT_BRIGHT_GREEN, FONT_RESET); canbe31instruments = (highestorder < 64); *channels31instruments = 24;
751 	} else if (!memcmp(&mem[20+31*30+2+128], "26CH", 4)) { printf ("%sNOTE: got 26CH - common 10 channel format%s\n",              FONT_BRIGHT_GREEN, FONT_RESET); canbe31instruments = (highestorder < 64); *channels31instruments = 26;
752 	} else if (!memcmp(&mem[20+31*30+2+128], "28CH", 4)) { printf ("%sNOTE: got 28CH - common 10 channel format%s\n",              FONT_BRIGHT_GREEN, FONT_RESET); canbe31instruments = (highestorder < 64); *channels31instruments = 28;
753 	} else if (!memcmp(&mem[20+31*30+2+128], "30CH", 4)) { printf ("%sNOTE: got 30CH - common 10 channel format%s\n",              FONT_BRIGHT_GREEN, FONT_RESET); canbe31instruments = (highestorder < 64); *channels31instruments = 30;
754 	} else if (!memcmp(&mem[20+31*30+2+128], "32CH", 4)) { printf ("%sNOTE: got 32CH - common 10 channel format%s\n",              FONT_BRIGHT_GREEN, FONT_RESET); canbe31instruments = (highestorder < 64); *channels31instruments = 32;
755 	} else {
756 		if (
757                     (((mem[20+31*30+2+128] >= 'A') && (mem[20+31*30+2+128] <= 'Z')) ||
758 		     ((mem[20+31*30+2+128] >= '0') && (mem[20+31*30+2+128] <= '9')) ||
759 		      (mem[20+31*30+2+128] == '.')                                     ||
760 		      (mem[20+31*30+2+128] == '!')                                     ||
761 		      (mem[20+31*30+2+128] == '#')) &&
762                     (((mem[20+31*30+2+129] >= 'A') && (mem[20+31*30+2+129] <= 'Z')) ||
763 		     ((mem[20+31*30+2+129] >= '0') && (mem[20+31*30+2+129] <= '9')) ||
764 		      (mem[20+31*30+2+129] == '.')                                     ||
765 		      (mem[20+31*30+2+129] == '!')                                     ||
766 		      (mem[20+31*30+2+129] == '#')) &&
767                     (((mem[20+31*30+2+130] >= 'A') && (mem[20+31*30+2+130] <= 'Z')) ||
768 		     ((mem[20+31*30+2+130] >= '0') && (mem[20+31*30+2+130] <= '9')) ||
769 		      (mem[20+31*30+2+130] == '.')                                     ||
770 		      (mem[20+31*30+2+130] == '!')                                     ||
771 		      (mem[20+31*30+2+130] == '#')) &&
772                     (((mem[20+31*30+2+131] >= 'A') && (mem[20+31*30+2+131] <= 'Z')) ||
773 		     ((mem[20+31*30+2+131] >= '0') && (mem[20+31*30+2+131] <= '9')) ||
774 		      (mem[20+31*30+2+131] == '.')                                     ||
775 		      (mem[20+31*30+2+131] == '!')                                     ||
776 		      (mem[20+31*30+2+131] == '#')))
777 		{
778 			printf ("%sWARNING: Unknown TAG: \"%c%c%c%c\"%s\n", FONT_BRIGHT_YELLOW, mem[20+31*30+2+128], mem[20+31*30+2+129], mem[20+31*30+2+130], mem[20+31*30+2+131], FONT_RESET);
779 			*channels31instruments = 4;
780 			canbe31instruments = 0;
781 		} else {
782 			printf ("%sERROR: Illegal TAG - can not be a 31 instrument file%s\n", FONT_BRIGHT_RED, FONT_RESET);
783 		}
784 	}
785 
786 	if ((20+31*30+2+128+4+ (highestorder+1)*1024) > len)
787 	{
788 		printf ("%sERROR: Not enough space for pattern data - can not be a 31 instrument file%s\n", FONT_BRIGHT_RED, FONT_RESET);
789 		return -1;
790 	}
791 
792 	if ((20+31*30+2+128+4 + (highestorder+1)*1024 + (samplelengths31<<1)) > len)
793 	{
794 		printf ("%sERROR: Not enough space for sample data - can not be a 31 instrument file%s\n", FONT_BRIGHT_RED, FONT_RESET);
795 		return -1;
796 	}
797 
798 	if ((20+31*30+2+128+4 + (highestorder+1)*1024 + (samplelengths31<<1)) != len)
799 	{
800 		printf ("%sWARNING: Got %d bytes extra data for 31 instrument file%s\n", FONT_BRIGHT_YELLOW, len - (20+31*30+2+128+4 + (highestorder+1)*1024 + (samplelengths31<<1)), FONT_RESET);
801 	}
802 
803 	return canbe31instruments;
804 }
805 
806 
preParseMOD(unsigned char * mem,int len,int * instruments,int * channels,int * signature)807 int preParseMOD (unsigned char *mem, int len, int *instruments, int *channels, int *signature)
808 {
809 	int i;
810 
811 	int channels15instruments = 4;
812 	int channels31instruments = 4;
813 	int canbe15instruments;
814 	int canbe31instruments;
815 
816 	if (len < 20)
817 	{
818 		printf ("%sERROR: no space for title%s\n", FONT_BRIGHT_RED, FONT_RESET);
819 		return -1;
820 	}
821 	do
822 	{
823 		int invalid = 0;
824 		int upper = 0;
825 		int lower = 0;
826 		int other = 0;
827 		int hi = 0;
828 		for (i=0; i < 20; i++)
829 		{
830 			if (mem[i] == 0)
831 			{
832 				break;
833 			}
834 			if ((mem[i] < 0x20) || ((mem[i] >= 0x7f) && (mem[i] <= 0x9f)))
835 			{
836 				invalid++;
837 			} else if ((mem[i] >= 'A') && (mem[i] <= 'Z'))
838 			{
839 				upper++;
840 			} else if ((mem[i] >= 'a') && (mem[i] <= 'z'))
841 			{
842 				lower++;
843 			} else if (!(mem[i] & 0x80))
844 			{
845 				other++;
846 			} else {
847 				hi++;
848 			}
849 		}
850 		if (invalid)
851 		{
852 			printf ("Title: contains invalid characters\n");
853 		} else if (hi || lower)
854 		{
855 			printf ("Title: Can not be \"Original Protracker\"\n");
856 		} else if (lower)
857 		{
858 			printf ("Title: Might be \"Original Protracker\"\n");
859 		}
860 	} while (0);
861 
862 	canbe15instruments = preParseMOD15 (mem, len, &channels15instruments);
863 	if (canbe15instruments < -1)
864 	{
865 		return -1;
866 	}
867 	canbe31instruments = preParseMOD31 (mem, len, &channels31instruments);
868 
869 	if (canbe31instruments>0)
870 	{
871 		printf ("%sINFO: File is 31 instruments, %d channels%s\n", FONT_BRIGHT_GREEN, channels31instruments, FONT_RESET);
872 		*instruments = 31; *channels = channels31instruments; *signature = 1;
873 		return 0;
874 	}
875 	if (canbe15instruments>0)
876 	{
877 		printf ("%sINFO: File is 15 instruments, %d channels%s\n", FONT_BRIGHT_GREEN, channels15instruments, FONT_RESET);
878 		*instruments = 15; *channels = channels15instruments; *signature = 0;
879 		return 0;
880 	}
881 	if (canbe31instruments==0)
882 	{
883 		printf ("%sINFO: File is probably 31 instruments, %d channels%s\n", FONT_BRIGHT_GREEN, channels31instruments, FONT_RESET);
884 		*instruments = 31; *channels = channels31instruments; *signature = 1;
885 		return 0;
886 	}
887 	if (canbe15instruments==0)
888 	{
889 		printf ("%sINFO: File is probably 15 instruments, %d channels%s\n", FONT_BRIGHT_GREEN, channels15instruments, FONT_RESET);
890 		*instruments = 15; *channels = channels15instruments; *signature = 0;
891 		return 0;
892 	}
893 
894 	return -1;
895 }
896 
897 #warning TODO N.T. files!
898 
main(int argc,char * argv[])899 int main(int argc, char *argv[])
900 {
901 	struct stat st;
902 	size_t ps = sysconf(_SC_PAGE_SIZE);
903 	int fd;
904 	size_t data_mmaped_len;
905 	unsigned char *data;
906 	int c;
907 	char *color = "auto";
908 	int help = 0;
909 
910 	int instruments = 31;
911 	int channels = 4;
912 	int signature = 1;
913 
914 	while (1)
915 	{
916 		int option_index = 0;
917 		static struct option long_options[] =
918 		{
919 			{"color",        optional_argument, 0, 0},
920 			{"help",         no_argument,       0, 'h'},
921 			{"savepatterns", no_argument,       0, 'p'},
922 			{"savesamples",  no_argument,       0, 's'},
923 			{0,              0,                 0, 0}
924 		};
925 
926 		c = getopt_long(argc, argv, "hsp", long_options, &option_index);
927 		if (c == -1)
928 			break;
929 
930 		switch (c)
931 		{
932 			case 0:
933 				if (option_index == 0)
934 				{
935 					color = optarg;
936 				}
937 				break;
938 			case 'p':
939 				if (!savepatterns)
940 				{
941 					savepatterns = fopen ("patterns.txt", "w");
942 					if (!savepatterns)
943 					{
944 						fprintf (stderr, "Unable to open patterns.txt for writing: %s\n", strerror (errno));
945 						return 1;
946 					}
947 				}
948 				break;
949 			case 's':
950 				savesamples = 1;
951 				break;
952 			case 'h':
953 				help = 1;
954 				break;
955 			case '?':
956 				help = 3;
957 				break;
958 			default:
959 				printf("?? getopt returned character code 0%o ??\n", c);
960 		}
961 	}
962 
963 	if (optind != (argc-1))
964 	{
965 		help = 4;
966 	}
967 
968 	if (!color)
969 	{
970 		usecolor = 1;
971 	} else if (!strcmp (color, "auto"))
972 	{
973 		usecolor = isatty ( 1 );
974 	} else if ((strcmp (color, "never")) && (strcmp (color, "no")))
975 	{
976 		usecolor = 1;
977 	} else {
978 		usecolor = 0;
979 	}
980 
981 	if (help)
982 	{
983 		fprintf (stderr, "Usage:\n%s [--color=auto/never/on] [--savesamples -s] [--savepatterns -p] [--help] file.stm  (%d)\n", argv[0], help);
984 		return 1;
985 	}
986 
987 	fd = open (argv[optind], O_RDONLY);
988 	if (fd < 0)
989 	{
990 		perror ("open()");
991 		return 0;
992 	}
993 	if (fstat(fd, &st))
994 	{
995 		perror("fstat()");
996 		close (fd);
997 		return 0;
998 	}
999 	if (!st.st_size)
1000 	{
1001 		fprintf (stderr, "Zero-size file\n");
1002 		close (fd);
1003 		return 0;
1004 	}
1005 
1006 //	s.data_len = st.st_size;
1007 	data_mmaped_len = roundup (st.st_size, ps);
1008 	data = mmap (0, data_mmaped_len, PROT_READ|PROT_WRITE, MAP_FILE|MAP_PRIVATE, fd, 0);
1009 
1010 	if (data == MAP_FAILED)
1011 	{
1012 		perror ("mmap() failed");
1013 		close (fd);
1014 		return 0;
1015 	}
1016 
1017 	if (usecolor)
1018 	{
1019 		FONT_RESET         = "\033[0m";
1020 		FONT_BRIGHT_BLACK  = "\033[30;1m";
1021 		FONT_BRIGHT_RED    = "\033[31;1m";
1022 		FONT_BRIGHT_GREEN  = "\033[32;1m";
1023 		FONT_BRIGHT_YELLOW = "\033[33;1m";
1024 		FONT_BRIGHT_BLUE   = "\033[34;1m";
1025 		FONT_BRIGHT_PURPLE = "\033[35;1m";
1026 		FONT_BRIGHT_CYAN   = "\033[36;1m";
1027 	}
1028 
1029 	if (preParseMOD (data, st.st_size, &instruments, &channels, &signature))
1030 	{
1031 		goto failed;
1032 	}
1033 	ParseMOD (data, st.st_size, instruments, channels, signature);
1034 
1035 failed:
1036 	munmap (data, data_mmaped_len);
1037 	close (fd);
1038 	return 0;
1039 }
1040