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 struct
29 {
30 uint32_t offset;
31 uint16_t length;
32 } Instruments[31];
33
34 #if 0
35 typedef struct __attribute__((packed))
36 {
37 char name[20];
38 char tracker[8];
39 uint8_t sig,type;
40 uint8_t maj, min;
41 uint8_t it, pats, gv;
42 char reserved[13];
43 } FileHeader;
44 #endif
45
DumpPrefix(unsigned char * mem,int len,int base,int baselen)46 void DumpPrefix (unsigned char *mem, int len, int base, int baselen)
47 {
48 int i;
49 printf ("[%s%08x%s]%s", FONT_BRIGHT_BLUE, base, FONT_RESET, FONT_BRIGHT_PURPLE);
50 for (i=0; i < baselen; i++)
51 {
52 if (base+i >= len)
53 {
54 printf (" \?\?");
55 } else {
56 printf (" %02x", mem[base+i]);
57 }
58 }
59 switch (baselen)
60 {
61 case 2: printf ( "%s ", FONT_RESET); break;
62 case 1: printf ( "%s ", FONT_RESET); break;
63 case 0: printf ( "%s ", FONT_RESET); break;
64 default: printf ("%s\n ", FONT_RESET); break;
65 }
66 }
67
DumpInstrument(unsigned char * mem,int len,int base,int instrument)68 int DumpInstrument (unsigned char *mem, int len, int base, int instrument)
69 {
70 uint16_t ParaPtr;
71 uint16_t Length;
72 uint16_t LoopStart;
73 uint16_t LoopEnd;
74 uint16_t C3Spd;
75 uint16_t LengthPara;
76 int i;
77
78 printf ("[%sINSTRUMENT %02d / PCM Sample%s]\n", FONT_BRIGHT_CYAN, instrument + 1, FONT_RESET);
79
80 DumpPrefix (mem, len, base + 0x00, 12);
81 if ((base + 31) >= len)
82 {
83 fprintf (stderr, "\n%sERROR: Ran out of data (I #1)%s\n", FONT_BRIGHT_RED, FONT_RESET);
84 return -1;
85 }
86 printf ("FileName: \"");
87 for (i=0; i < 12; i++)
88 {
89 if (!mem[base + 0x00 + i])
90 {
91 break;
92 }
93 putchar (mem[base + 0x00 + i]);
94 }
95 printf("\"\n");
96
97
98 DumpPrefix (mem, len, base + 0x0c, 1);
99 if ((base + 0x0c) >= len)
100 {
101 fprintf (stderr, "\n%sERROR: Ran out of data (I #2)%s\n", FONT_BRIGHT_RED, FONT_RESET);
102 return -1;
103 }
104 printf ("Type: %s%s%s\n",
105 (mem[base+0x0c] == 0x00) ? FONT_BRIGHT_GREEN : FONT_BRIGHT_RED,
106 (mem[base+0x0c] == 0x00) ? "PCM Sample" : "Unknown",
107 FONT_RESET);
108
109
110 DumpPrefix (mem, len, base + 0x0d, 1);
111 if ((base + 0x0d) >= len)
112 {
113 fprintf (stderr, "\n%sERROR: Ran out of data (I #3)%s\n", FONT_BRIGHT_RED, FONT_RESET);
114 return -1;
115 }
116 printf ("Disk: %d\n", mem[base+0x0d]);
117
118
119 DumpPrefix (mem, len, base + 0x0e, 2);
120 if ((base + 0x0e) >= len)
121 {
122 fprintf (stderr, "\n%sERROR: Ran out of data (I #4)%s\n", FONT_BRIGHT_RED, FONT_RESET);
123 return -1;
124 }
125 ParaPtr = uint16_little (((uint16_t *)(mem + base + 0x0e))[0]);
126 printf ("MemSeg: paraptr 0x%04x => 0x%08x\n", ParaPtr, ParaPtr << 4);
127 Instruments[instrument].offset = ParaPtr << 4;
128
129
130 DumpPrefix (mem, len, base + 0x10, 2);
131 if ((base + 0x10 + 1) >= len)
132 {
133 fprintf (stderr, "\n%sERROR: Ran out of data (I #5)%s\n", FONT_BRIGHT_RED, FONT_RESET);
134 return -1;
135 }
136 Length = uint16_little (((uint16_t *)(mem + base + 0x10))[0]);
137 printf ("Length: %d %s%s%s\n", (int)Length, Length>64000 ? FONT_BRIGHT_RED : FONT_BRIGHT_GREEN, (Length>64000) ? " Sample too long, will be cropped at 64000" : "", FONT_RESET);
138 Instruments[instrument].length = Length;
139
140
141 DumpPrefix (mem, len, base + 0x12, 2);
142 if ((base + 0x12 + 1) >= len)
143 {
144 fprintf (stderr, "\n%sERROR: Ran out of data (I #6)%s\n", FONT_BRIGHT_RED, FONT_RESET);
145 return -1;
146 }
147 LoopStart = uint16_little (((uint16_t *)(mem + base + 0x12))[0]);
148 printf ("Loop-Start: %d %s%s%s\n", (int)LoopStart, (LoopStart>Length) ? FONT_BRIGHT_RED : FONT_BRIGHT_GREEN, (LoopStart>Length) ? " LoopStart > Length" : "", FONT_RESET);
149
150
151 DumpPrefix (mem, len, base + 0x14, 2);
152 if ((base + 0x14 + 1) >= len)
153 {
154 fprintf (stderr, "\n%sERROR: Ran out of data (I #7)%s\n", FONT_BRIGHT_RED, FONT_RESET);
155 return -1;
156 }
157 LoopEnd = uint16_little (((uint16_t *)(mem + base + 0x14))[0]);
158 printf ("Loop-End: %d %s%s%s\n", (int)LoopEnd,
159 ((LoopEnd>(Length+1)) && (LoopEnd != 0xffff)) ? FONT_BRIGHT_RED : FONT_BRIGHT_GREEN,
160 ((LoopEnd>(Length+1)) && (LoopEnd != 0xffff)) ? " LoopEnd > Length + 1" : (LoopEnd == 0xffff) ? "No loop" : "", FONT_RESET);
161
162
163 DumpPrefix (mem, len, base + 0x16, 1);
164 if ((base + 0x16) >= len)
165 {
166 fprintf (stderr, "\n%sERROR: Ran out of data (I #8)%s\n", FONT_BRIGHT_RED, FONT_RESET);
167 return -1;
168 }
169 printf ("Volume: %d %s%s%s\n", mem[base+0x16], (mem[base+0x16] > 64) ? FONT_BRIGHT_RED : FONT_BRIGHT_GREEN, (mem[base+0x16] > 64) ? " This is greater than 64" : "", FONT_RESET);
170
171
172 DumpPrefix (mem, len, base + 0x17, 1);
173 if ((base + 0x17) >= len)
174 {
175 fprintf (stderr, "\n%sERROR: Ran out of data (I #9)%s\n", FONT_BRIGHT_RED, FONT_RESET);
176 return -1;
177 }
178 printf ("Reserved/unused\n");
179
180
181 DumpPrefix (mem, len, base + 0x18, 2);
182 if ((base + 0x18+1) >= len)
183 {
184 fprintf (stderr, "\n%sERROR: Ran out of data (I #10)%s\n", FONT_BRIGHT_RED, FONT_RESET);
185 return -1;
186 }
187 C3Spd = uint32_little (((uint16_t *)(mem + base + 0x18))[0]);
188 printf ("C3 Sample Rate: %d\n", C3Spd);
189
190
191 DumpPrefix (mem, len, base + 0x1a, 4);
192 if ((base + 0x1a + 3) >= len)
193 {
194 fprintf (stderr, "\n%sERROR: Ran out of data (I #11)%s\n", FONT_BRIGHT_RED, FONT_RESET);
195 return -1;
196 }
197 printf ("Reserved / Internal use / leave at 0\n");
198
199
200 DumpPrefix (mem, len, base + 0x1e, 2);
201 if ((base + 0x1e + 1) >= len)
202 {
203 fprintf (stderr, "\n%sERROR: Ran out of data (I #12)%s\n", FONT_BRIGHT_RED, FONT_RESET);
204 return -1;
205 }
206 LengthPara = uint16_little (((uint16_t *)(mem + base + 0x1e))[0]);
207 printf ("Length-Para: %d (not used)\n", LengthPara);
208
209 return 0;
210 }
211
print_note(unsigned char note)212 void print_note (unsigned char note)
213 {
214 char *text[16] = {"C-", "C#", "D-", "D#", "E-", "F-", "F#", "G-", "G#", "A-", "A#", "B-", "?c", "?d", "?e", "?f"};
215
216 if (note == 0xfe)
217 {
218 printf ("-0-");
219 if (savepatterns)
220 {
221 fprintf (savepatterns, "-0-");
222 }
223 return;
224 }
225 if (note >= 0x60)
226 {
227 printf ("...");
228 if (savepatterns)
229 {
230 fprintf (savepatterns, "...");
231 }
232 return;
233 }
234
235 if ((note & 0x0f) >= 12) printf ("%s", FONT_BRIGHT_RED);
236 printf ("%s", text[note & 0x0f]);
237 if (savepatterns)
238 {
239 fprintf (savepatterns, "%s", text[note & 0x0f]);
240 }
241 if ((note & 0x0f) >= 12) printf ("%s", FONT_RESET);
242
243 printf ("%d", note >> 4);
244 if (savepatterns)
245 {
246 fprintf (savepatterns, "%d", note>>4);
247 }
248 }
249
DumpPattern(unsigned char * mem,int len,int base,int pattern)250 int DumpPattern (unsigned char *mem, int len, int base, int pattern)
251 {
252 int offset = 0;
253 int i;
254
255 printf ("[%sPATTERN %d%s]\n", FONT_BRIGHT_CYAN, pattern, FONT_RESET);
256 if (savepatterns)
257 {
258 fprintf (savepatterns, "PATTERN %d\n", pattern);
259 }
260
261 for (i=0; i < 64; i++)
262 {
263 int j;
264
265 do {
266 int preoffset = offset; /* so we can rewind */
267
268 for (j=0; j < 4; j++)
269 {
270 if (base+preoffset >= len)
271 {
272 if (offset != len)
273 {
274 DumpPrefix (mem, len, base + offset, len - offset);
275 }
276 fprintf (stderr, "\n%sERROR: Ran out of data (P #1)%s\n", FONT_BRIGHT_RED, FONT_RESET);
277 return -1;
278 }
279 switch (mem[base + preoffset])
280 {
281 case 0xfb:
282 case 0xfc:
283 case 0xfd:
284 preoffset += 1;
285 break;
286 default:
287 preoffset += 4;
288 if ((base + preoffset - 1) >= len)
289 {
290 if (offset != len)
291 {
292 DumpPrefix (mem, len, base + offset, len - offset);
293 }
294 fprintf (stderr, "\n%sERROR: Ran out of data (P #2)%s\n", FONT_BRIGHT_RED, FONT_RESET);
295 return -1;
296 }
297 break;
298 }
299 }
300
301 DumpPrefix (mem, len, base + offset, preoffset - offset);
302 } while (0);
303
304 printf ("%02X |", i);
305 if (savepatterns)
306 {
307 fprintf (savepatterns, "%02X |", i);
308 }
309
310 for (j=0; j < 4; j++)
311 {
312 uint8_t note, insvol, volcmd, cmdinf;
313 switch (mem[base+offset])
314 {
315 case 0xfb:
316 offset += 1;
317 note = insvol = volcmd = cmdinf = 0x00;
318 break;
319 case 0xfc:
320 offset += 1;
321 printf (" ... .. .. .00 |");
322 if (savepatterns)
323 {
324 fprintf (savepatterns, " ... .. .. .00 |");
325 }
326 goto next;
327 case 0xfd: offset += 1; printf(" -0- .. .. .00 |"); goto next;
328 default: note=mem[base + offset++]; insvol=mem[base + offset++]; volcmd=mem[base + offset++]; cmdinf=mem[base + offset++]; break;
329 }
330
331 printf (" ");
332 if (savepatterns)
333 {
334 fprintf (savepatterns, " ");
335 }
336
337 print_note(note);
338
339 printf (" ");
340 if (savepatterns)
341 {
342 fprintf (savepatterns, " ");
343 }
344
345 if ((insvol >> 3) == 0)
346 {
347 printf ("..");
348 if (savepatterns)
349 {
350 fprintf (savepatterns, "..");
351 }
352 } else {
353 printf ("%02d", insvol>>3);
354 if (savepatterns)
355 {
356 fprintf (savepatterns, "%02d", insvol>>3);
357 }
358 }
359
360 printf (" ");
361 if (savepatterns)
362 {
363 fprintf (savepatterns, " ");
364 }
365
366 if (((insvol & 0x07) | ((volcmd & 0xf0) >> 1)) > 64)
367 {
368 printf ("..");
369 if (savepatterns)
370 {
371 fprintf (savepatterns, "..");
372 }
373 } else {
374 printf ("%02d", (insvol & 0x07) | ((volcmd & 0xf0) >> 1));
375 if (savepatterns)
376 {
377 fprintf (savepatterns, "%02d", (insvol & 0x07) | ((volcmd & 0xf0) >> 1));
378 }
379 }
380
381 printf (" ");
382 if (savepatterns)
383 {
384 fprintf (savepatterns, " ");
385 }
386
387 printf ("%c%02X |", ".ABCDEFGHIJKLMNO"[volcmd & 0x0f], cmdinf);
388 if (savepatterns)
389 {
390 fprintf (savepatterns, "%c%02X |", ".ABCDEFGHIJKLMNO"[volcmd & 0x0f], cmdinf);
391 }
392
393 next: {};
394 }
395
396 printf ("\n");
397 if (savepatterns)
398 {
399 fprintf (savepatterns, "\n");
400 }
401 }
402
403 return offset;
404 }
405
DumpHeader(unsigned char * mem,int len)406 int DumpHeader (unsigned char *mem, int len)
407 {
408 int i, j;
409
410 if (len < 0x30)
411 {
412 fprintf (stderr, "%sERROR: len < sizeof(FileHeader)%s\n", FONT_BRIGHT_RED, FONT_RESET);
413 return 1;
414 }
415
416 printf ("[%sHEADER%s]\n", FONT_BRIGHT_CYAN, FONT_RESET);
417
418 /* hdr.name */
419 DumpPrefix (mem, len, 0x00, 20);
420 printf ("Name: \"");
421 for (i=0; i < 20; i++)
422 {
423 if (!mem[0x00+i])
424 break;
425 printf ("%c", (char)mem[0x00+i]);
426 }
427 printf ("\"\n");
428
429 DumpPrefix (mem, len, 0x14, 8);
430 printf ("Tracker: \"");
431 j=0;
432 for (i=0; i < 8; i++)
433 {
434 if ((mem[0x14+i] < 0x20) || (mem[0x14+i] >= 0x80))
435 {
436 j = 1;
437 }
438 }
439 for (i=0; i < 8; i++)
440 {
441 if (!mem[0x14+i])
442 break;
443 printf ("%c", (char)mem[0x14+i]);
444 }
445 printf ("\" %s%s%s\n",
446 j ? FONT_BRIGHT_RED : FONT_BRIGHT_GREEN,
447 j ? "Non-ASCII" : "OK",
448 FONT_RESET);
449
450 DumpPrefix (mem, len, 0x1c, 1);
451 printf ("Signature: %s%s%s\n",
452 (mem[0x1c] == 0x1A) ? FONT_BRIGHT_GREEN : (mem[0x1c] == 0x02) ? FONT_BRIGHT_YELLOW : FONT_BRIGHT_RED,
453 (mem[0x1c] == 0x1A) ? "OK" : (mem[0x1c] == 0x02) ? "Known invalid value" : "Failed!!!!",
454 FONT_RESET);
455
456 DumpPrefix (mem, len, 0x1d, 1);
457 printf ("Type: ");
458 switch (mem[0x1d])
459 {
460 case 1: printf ("STM song w/o samples\n"); break;
461 case 2: printf ("STM module\n"); break;
462 case 16: printf ("S3M module, FAILED !!!!!\n"); return 1;
463 default: printf ("Unknown, FAILED !!!!!\n"); return 1;
464 }
465
466 DumpPrefix (mem, len, 0x1e, 2);
467 printf ("Version: %d.%d\n", mem[0x1e], mem[0x1f]);
468
469 DumpPrefix (mem, len, 0x20, 1);
470 printf ("Initial Tempo: %d\n", mem[0x20]);
471
472 DumpPrefix (mem, len, 0x21, 1);
473 printf ("Patterns: %d\n", mem[0x21]);
474
475 DumpPrefix (mem, len, 0x22, 1);
476 printf ("Global Volume: %d\n", mem[0x22]);
477
478 DumpPrefix (mem, len, 0x23, 13);
479 printf ("(Reserved/not used)\n");
480
481 return 0;
482 }
483
DumpOrders(unsigned char * mem,int len,int count,int pats)484 int DumpOrders (unsigned char *mem, int len, int count, int pats)
485 {
486 int i;
487
488 printf ("[%sORDERS%s]\n", FONT_BRIGHT_CYAN, FONT_RESET);
489 for (i=0; i < count; i++)
490 {
491 if ((i&15) != 0)
492 {
493 putchar (' ');
494 } else {
495 DumpPrefix (mem, len, 0x410 + i, 16);
496 if ((0x410 + i + 16) > len)
497 {
498 fprintf (stderr, "\n%sERROR: Ran out of data (S #1)%s\n", FONT_BRIGHT_RED, FONT_RESET);
499 return -1;
500 }
501 };
502
503 if ( mem[0x410+i]==99 )
504 {
505 printf ("99(ignore)");
506 } else if (mem[0x410+i]==255)
507 {
508 printf ("255(EOS)"); // End Of Song
509 } else if (mem[0x410+i]>=pats)
510 {
511 printf("%s%d(out of range)%s", FONT_BRIGHT_RED, mem[0x410+i], FONT_RESET);
512 } else {
513 printf ("%d", mem[0x410+i]);
514 }
515 if ((i&15) == 15)
516 {
517 putchar ('\n');
518 }
519 }
520 if ((i&15) != 0)
521 {
522 printf ("\n");
523 }
524
525 return 0;
526 }
527
ParseSTM(unsigned char * mem,int len)528 int ParseSTM (unsigned char *mem, int len)
529 {
530 int i;
531 int patternlen = 0;
532
533 if (DumpHeader (mem, len))
534 {
535 return -1;
536 }
537
538 for (i=0; i < 31; i++)
539 {
540 if (DumpInstrument (mem, len, 0x30 + i*0x20, i))
541 {
542 return -1;
543 }
544 }
545
546 if (DumpOrders (mem, len, mem[0x1f]?128:64, mem[0x21]))
547 {
548 return -1;
549 }
550
551 for (i=0; i < mem[0x21]; i++)
552 {
553 int retval = DumpPattern (mem, len, 0x30 + 0x20*31 + (mem[0x1f]?128:64) + patternlen, i);
554 if (retval < 0)
555 {
556 return -1;
557 }
558 patternlen += DumpPattern (mem, len, 0x30 + 0x20*31 + (mem[0x1f]?128:64) + patternlen, i);
559 }
560 if (savepatterns)
561 {
562 fclose (savepatterns);
563 }
564
565 for (i=0; i < 31; i++)
566 {
567 if (Instruments[i].length > 0)
568 {
569 printf ("[%sINSTRUMENT %02x SAMPLE DATA%s]\n", FONT_BRIGHT_CYAN, i + 1, FONT_RESET);
570
571 printf ("[%s%08x-%08x%s]%s\n", FONT_BRIGHT_BLUE, Instruments[i].offset, Instruments[i].offset + Instruments[i].length - 1, FONT_RESET, FONT_RESET);
572 if (savesamples)
573 {
574 if ((Instruments[i].offset + Instruments[i].length) > len)
575 {
576 printf ("%sWARNING: Unable to store instrument %d, missing data\n%s", FONT_BRIGHT_YELLOW, i + 1, FONT_RESET);
577 } else {
578 char filename[33];
579 int fd;
580 snprintf (filename, sizeof (filename), "Instrument %02d.signed 8bit.sample", i+1);
581 fd = open (filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
582 if (fd < 0)
583 {
584 printf ("%sWARNING: Unable to open %s%s\n", FONT_BRIGHT_YELLOW, filename, FONT_RESET);
585 } else {
586 write (fd, mem + Instruments[i].offset, Instruments[i].length);
587 close (fd);
588 printf ("Saved %s\n", filename);
589 }
590 }
591 }
592 }
593 }
594
595 return 0;
596 }
597
598
main(int argc,char * argv[])599 int main(int argc, char *argv[])
600 {
601 struct stat st;
602 size_t ps = sysconf(_SC_PAGE_SIZE);
603 int fd;
604 size_t data_mmaped_len;
605 unsigned char *data;
606 int c;
607 char *color = "auto";
608 int help = 0;
609
610 while (1)
611 {
612 int option_index = 0;
613 static struct option long_options[] =
614 {
615 {"color", optional_argument, 0, 0},
616 {"help", no_argument, 0, 'h'},
617 {"savepatterns", no_argument, 0, 'p'},
618 {"savesamples", no_argument, 0, 's'},
619 {0, 0, 0, 0}
620 };
621
622 c = getopt_long(argc, argv, "hsp", long_options, &option_index);
623 if (c == -1)
624 break;
625
626 switch (c)
627 {
628 case 0:
629 if (option_index == 0)
630 {
631 color = optarg;
632 }
633 break;
634 case 'p':
635 if (!savepatterns)
636 {
637 savepatterns = fopen ("patterns.txt", "w");
638 if (!savepatterns)
639 {
640 fprintf (stderr, "Unable to open patterns.txt for writing: %s\n", strerror (errno));
641 return 1;
642 }
643 }
644 break;
645 case 's':
646 savesamples = 1;
647 break;
648 case 'h':
649 help = 1;
650 break;
651 case '?':
652 help = 3;
653 break;
654 default:
655 printf("?? getopt returned character code 0%o ??\n", c);
656 }
657 }
658
659 if (optind != (argc-1))
660 {
661 help = 4;
662 }
663
664 if (!color)
665 {
666 usecolor = 1;
667 } else if (!strcmp (color, "auto"))
668 {
669 usecolor = isatty ( 1 );
670 } else if ((strcmp (color, "never")) && (strcmp (color, "no")))
671 {
672 usecolor = 1;
673 } else {
674 usecolor = 0;
675 }
676
677 if (help)
678 {
679 fprintf (stderr, "Usage:\n%s [--color=auto/never/on] [--savesamples -s] [--savepatterns -p] [--help] file.stm (%d)\n", argv[0], help);
680 return 1;
681 }
682
683 fd = open (argv[optind], O_RDONLY);
684 if (fd < 0)
685 {
686 perror ("open()");
687 return 0;
688 }
689 if (fstat(fd, &st))
690 {
691 perror("fstat()");
692 close (fd);
693 return 0;
694 }
695 if (!st.st_size)
696 {
697 fprintf (stderr, "Zero-size file\n");
698 close (fd);
699 return 0;
700 }
701
702 // s.data_len = st.st_size;
703 data_mmaped_len = roundup (st.st_size, ps);
704 data = mmap (0, data_mmaped_len, PROT_READ|PROT_WRITE, MAP_FILE|MAP_PRIVATE, fd, 0);
705
706 if (data == MAP_FAILED)
707 {
708 perror ("mmap() failed");
709 close (fd);
710 return 0;
711 }
712
713 if (usecolor)
714 {
715 FONT_RESET = "\033[0m";
716 FONT_BRIGHT_BLACK = "\033[30;1m";
717 FONT_BRIGHT_RED = "\033[31;1m";
718 FONT_BRIGHT_GREEN = "\033[32;1m";
719 FONT_BRIGHT_YELLOW = "\033[33;1m";
720 FONT_BRIGHT_BLUE = "\033[34;1m";
721 FONT_BRIGHT_PURPLE = "\033[35;1m";
722 FONT_BRIGHT_CYAN = "\033[36;1m";
723 }
724
725 if (ParseSTM (data, st.st_size))
726 {
727 goto failed;
728 }
729
730 failed:
731 munmap (data, data_mmaped_len);
732 close (fd);
733 return 0;
734 }
735