1 /* $Id: file_read.c,v 1.13 2006/09/16 10:18:38 toad32767 Exp $ */
2 /**
3 ** 2005, 2006 by Marco Trillo
4 ** This file is part of UModPlayer, and is released by
5 ** its autors to the Public Domain.
6 ** In case it's not legally possible, its autors grant
7 ** anyone the right to use, redistribute and modify
8 ** this software for any purpose, without any conditions,
9 ** unless such conditions are required by law.
10 **
11 ** THIS FILE COMES WITHOUT ANY WARRANTY. THE AUTHORS
12 ** SHALL NOT BE LIABLE FOR ANY DAMAGE RESULTING BY THE
13 ** USE OR MISUSE OF THIS SOFTWARE.
14 **/
15
16 /*
17 * =====================
18 * FILE-RELATED STUFF
19 * =====================
20 */
21
22 #include <sys/time.h>
23 #include <termios.h>
24
25 #include <messages.h>
26 #include <umodplayer.h>
27 #include <text.h>
28 #include <file_read.h>
29 #include <file_write.h>
30 #include <coresound.h>
31 #include <playlist.h>
32 #include <modtypes.h>
33
34 #include <sys/stat.h>
35
36 /*
37 * Safe variants of malloc(), realloc(),
38 * strcopyof(), and ReadString().
39 */
40 LOCAL void *
safe_alloc(size_t size)41 safe_alloc(size_t size)
42 {
43 void *ptr = malloc(size);
44 if (ptr == NULL) {
45 error("%s", MESSAGE_NO_MEMORY);
46 exit(UM_ERR_MEMORY);
47 }
48 return ptr;
49 }
50 LOCAL char *
safecopyof(char * s)51 safecopyof(char *s)
52 {
53 char *ptr = strcopyof(s);
54 if (ptr == NULL) {
55 error("%s", MESSAGE_NO_MEMORY);
56 exit(UM_ERR_MEMORY);
57 }
58 return ptr;
59 }
60 LOCAL char *
SafeReadString()61 SafeReadString()
62 {
63 char *s = ReadString();
64 if (s == NULL) {
65 error("%s", MESSAGE_NO_MEMORY);
66 exit(UM_ERR_MEMORY);
67 }
68 return s;
69 }
70
71 /*
72 * `file.name' is the global variable specifying the module name.
73 * Set `file.name' to NULL if failed.
74 *
75 * If `file.malloc' is TRUE, then `file.name' must be free()'d
76 * before being set to NULL.
77 */
78 EXPORT void
ULoadFile()79 ULoadFile()
80 {
81 int fd;
82 unsigned long remaining, buflen = 0, bufpos;
83 uint8_t *buffer;
84 struct stat buf;
85
86 if (file.name == NULL) {
87 return;
88 }
89
90 TrimString(file.name);
91
92 if (stat(file.name, &buf) == -1) {
93 error("CAN'T stat(\"%s\"): %s\n", file.name, strerror(errno));
94 goto cleanup;
95 }
96
97 buflen = (unsigned long) (buf.st_size);
98 if (buflen == 0) {
99 error("size of \"%s\" is zero!\n", file.name);
100 goto cleanup;
101 }
102
103 fd = open(file.name, O_RDONLY);
104 if (fd == -1) {
105 error("CAN'T open(\"%s\"): %s\n", file.name, strerror(errno));
106 goto cleanup;
107 }
108
109 buffer = (uint8_t *) safe_alloc((size_t) buflen);
110
111 remaining = buflen;
112 bufpos = 0;
113 while (remaining > 0) {
114 long bytes_read;
115
116 if ((bytes_read = (long) read(fd, buffer + bufpos, (size_t) remaining)) < 1) {
117 error("CAN'T read(): %s\n", strerror(errno));
118 free(buffer);
119 close(fd);
120 goto cleanup;
121 }
122
123 remaining -= bytes_read;
124 bufpos += bytes_read;
125 }
126
127 close(fd);
128
129 file.mod = ModPlug_Load(buffer, buflen);
130 free(buffer);
131 if (file.mod == NULL) {
132 goto cleanup;
133 }
134
135 DrawInfoTable();
136
137 return;
138
139 cleanup:
140 if (file.malloc == TRUE) {
141 free(file.name);
142 }
143 file.malloc = FALSE;
144 file.name = NULL;
145
146 return;
147 }
148
149 EXPORT void
UFreeFile()150 UFreeFile()
151 {
152 if (file.name != NULL) {
153 ModPlug_Unload(file.mod);
154 if (file.malloc == TRUE)
155 free(file.name);
156 file.malloc = FALSE;
157 file.name = NULL;
158 }
159 return;
160 }
161
162 EXPORT void
DisplayCurPos()163 DisplayCurPos()
164 {
165 notice("Order: %d - Pattern: %d - Row: %d\n",
166 ModPlug_GetCurrentOrder(file.mod),
167 ModPlug_GetCurrentPattern(file.mod),
168 ModPlug_GetCurrentRow(file.mod)
169 );
170 return;
171 }
172
173 EXPORT void
DrawInfoTable()174 DrawInfoTable()
175 {
176 WTable table;
177 int bytes_out;
178
179 if (sets.verbosity == 0)
180 return;
181
182 rr = (char **) safe_alloc(7 * sizeof(char *));
183 bytes_out = ModPlug_GetLength(file.mod);
184 bytes_out /= 1000;
185 rr[0] = (char *) safe_alloc(10);
186 sprintf(rr[0], "%d:%02d", bytes_out / 60, bytes_out % 60);
187 rr[1] = safecopyof(DetermineType());
188 rr[2] = (char *) safe_alloc(20);
189 sprintf(rr[2], "%d instruments", ModPlug_NumInstruments(file.mod));
190 rr[3] = (char *) safe_alloc(16);
191 sprintf(rr[3], "%d samples", ModPlug_NumSamples(file.mod));
192 rr[4] = (char *) safe_alloc(18);
193 sprintf(rr[4], "%d channels", ModPlug_NumChannels(file.mod));
194 rr[5] = (char *) safe_alloc(18);
195 sprintf(rr[5], "%d patterns", ModPlug_NumPatterns(file.mod));
196 rr[6] = (char *) ModPlug_GetName(file.mod);
197
198 bytes_out = CalcLen(rr, 7) + 1;
199 TableSetOptions(&table, 1, 6, 2, MAXVAL(bytes_out, 13), 0, TABLE_LEFT_ALIGN);
200 TableSetCaption(&table, rr[6]);
201 TableUseTheme(&table, sets.appareance);
202 TableInitCallback(&table, MyTextCallback);
203
204 DrawTable(table);
205
206 for (bytes_out = 0; bytes_out < 6; ++bytes_out)
207 free(rr[bytes_out]);
208 free(rr);
209
210 return;
211 }
212
213 EXPORT void
ExportSong()214 ExportSong()
215 {
216 char *p, *q;
217 unsigned long len;
218 char y;
219
220 printf(MESSAGE_EXPORT);
221 fflush(stdout);
222
223 p = SafeReadString();
224 TrimString(p);
225
226 if (*p == 0) {
227 free(p);
228 return;
229 }
230 for (;;) {
231 startpos = endpos = 0;
232 puts(MESSAGE_FORMATS);
233 puts(MESSAGE_PRESS_ENTER);
234 puts("================ Audio export options =================");
235 puts("a) Export audio as WAVE (WAV), 16-bit");
236 puts("b) Export audio as Audio IFF (AIFF), 16-bit");
237 puts("c) Export audio as Audio IFF (AIFF), 24-bit");
238 puts("d) Export audio as Audio IFF (AIFF), 32-bit");
239 puts("e) Export audio as raw system-endian 16-bit PCM");
240 puts("f) Export audio as raw little-endian 16-bit PCM");
241 puts("g) Export audio as raw big-endian 16-bit PCM\n");
242 puts("=============== Module export options =================");
243 puts("h) Convert to Impulse Tracker (IT)\n");
244 puts("=======================================================");
245 puts("(audio will be exported using current sound options)");
246 fputs(MESSAGE_FORMAT, stdout);
247 fflush(stdout);
248 q = SafeReadString();
249 if (*q == '\0') {
250 free(p);
251 free(q);
252 return;
253 }
254 if (*q == 'a') {
255 len = (unsigned long) WriteWAV(p);
256 if (len < 1) {
257 error("%s\n", MESSAGE_EXPORT_ERROR);
258 }
259 free(p);
260 free(q);
261 return;
262 }
263 if (*q == 'b' || *q == 'c' || *q == 'd') {
264 int ret = 0;
265
266 if (*q == 'b')
267 ret = WriteAIFF(p, 16);
268 else if (*q == 'c')
269 ret = WriteAIFF(p, 24);
270 else if (*q == 'd')
271 ret = WriteAIFF(p, 32);
272 if (ret < 1) {
273 puts(MESSAGE_EXPORT_ERROR);
274 }
275 free(p);
276 free(q);
277 return;
278 }
279 if (*q == 'e') {
280 len = WritePCM(p, EXPORT_SYS_ENDIAN);
281 if (len < 1) {
282 error("%s\n", MESSAGE_EXPORT_ERROR);
283 }
284 free(p);
285 free(q);
286 return;
287 }
288 if (*q == 'f') {
289 len = WritePCM(p, EXPORT_LTE_ENDIAN);
290 if (len < 1) {
291 error("%s\n", MESSAGE_EXPORT_ERROR);
292 }
293 free(p);
294 free(q);
295 return;
296 }
297 if (*q == 'g') {
298 len = WritePCM(p, EXPORT_BIG_ENDIAN);
299 if (len < 1) {
300 error("%s\n", MESSAGE_EXPORT_ERROR);
301 }
302 free(p);
303 free(q);
304 return;
305 }
306 if (*q == 'h') {
307 #ifdef MODPLUG_CAN_SAVE
308 y = ModPlug_ExportIT(file.mod, p);
309 #else
310 error("ModPlug compiled without 'save' support\n");
311 y = 0;
312 #endif
313 if (y != 1) {
314 error("%s\n", MESSAGE_EXPORT_ERROR);
315 } else {
316 notice("%s\n", MESSAGE_DONE);
317 }
318 free(p);
319 free(q);
320 return;
321 }
322 free(q);
323 }
324
325
326 return;
327 }
328
329 LOCAL void
ErrorDispatch(int ret,char * data)330 ErrorDispatch(int ret, char *data)
331 {
332 switch (ret) {
333 case UM_ERR_NOITEM:
334 error("%s\n", MESSAGE_CANT_FIND_ITEM);
335 break;
336 case UM_ERR_IO:
337 error("I/O error: %s: %s\n", data, strerror(errno));
338 break;
339 case UM_ERR_MEMORY:
340 error("Memory error: %s\n", strerror(errno));
341 break;
342 case UM_ERR_INTERNAL:
343 error("Internal error (%s)\n", data);
344 break;
345 case UM_OK:
346 return;
347 default:
348 error("Unknown error: %d. Please report this bug.\n", ret);
349 }
350 }
351
352 LOCAL void
PlayListLoadFolder()353 PlayListLoadFolder()
354 {
355 char path[1024];
356
357 getcwd(path, 1024);
358 ErrorDispatch(list_from_dir(path), path);
359 }
360
361 LOCAL void
PlayListSaveFile(char * finame)362 PlayListSaveFile(char *finame)
363 {
364 ErrorDispatch(save_list(finame), finame);
365 }
366
367 LOCAL void
PlayListLoadFile(char * finame)368 PlayListLoadFile(char *finame)
369 {
370 ErrorDispatch(load_list(finame), finame);
371 }
372
373 /*
374 * wait 2 seconds for a key, to interrupt the playlist course
375 */
376 LOCAL int
PlayListWaitForKey()377 PlayListWaitForKey()
378 {
379 int keyHit;
380 fd_set fds;
381 struct timeval tv;
382 struct termios term, _term;
383
384 tcgetattr(0, &_term);
385 memcpy(&term, &_term, sizeof(term));
386 cfmakeraw(&term);
387 tcsetattr(0, TCSANOW, &term);
388 FD_ZERO(&fds);
389 FD_SET(0, &fds);
390 tv.tv_sec = 2;
391 tv.tv_usec = 0;
392 keyHit = select(1, &fds, NULL, NULL, &tv);
393 tcsetattr(0, TCSANOW, &_term);
394
395 return keyHit;
396 }
397
398 EXPORT void
PlayList()399 PlayList()
400 {
401 char *s, pathbuf[512];
402
403 getcwd(pathbuf, 512);
404 puts(MESSAGE_PRESS_ENTER);
405 puts("a) Import playlist from current dir.");
406 puts("b) Load a saved playlist");
407 puts("c) New Playlist");
408 fputs(MESSAGE_OPTION, stdout);
409 fflush(stdout);
410 s = SafeReadString();
411 if (*s == '\0') {
412 free(s);
413 return;
414 }
415
416 switch (*s) {
417 case 'a':
418 PlayListLoadFolder();
419 break;
420
421 case 'b':
422 printf(MESSAGE_FILENAME);
423 fflush(stdout);
424 free(s);
425 s = SafeReadString();
426 if (*s == '\0') {
427 free(s);
428 return;
429 }
430 PlayListLoadFile(s);
431 break;
432
433 case 'c':
434 break;
435
436 default:
437 free(s);
438 return;
439 }
440
441 free(s);
442 print_list();
443 for (;;) {
444 puts(MESSAGE_PRESS_ENTER);
445 puts("p) PLAY");
446 puts("s) SAVE");
447 puts("n) NEW ITEM");
448 puts("d) DELETE ITEM");
449 puts("m) MOVE ITEM");
450 puts("v) VIEW ITEMS");
451 puts("q) QUIT");
452 printf(MESSAGE_OPTION);
453 fflush(stdout);
454 s = SafeReadString();
455 if (*s == '\0') {
456 free(s);
457 continue;
458 }
459
460 switch (*s) {
461 case 'q':
462 if (s != NULL)
463 free(s);
464
465 warning("playlist will be deleted. are you sure [y/n]? ");
466 fflush(stderr);
467 s = SafeReadString();
468
469 if (*s != 'y') {
470 free(s);
471 break;
472 }
473 free(s);
474 delete_list();
475 return;
476
477 /* PLAY */
478 case 'p':
479 {
480 struct playlist *p = next_playlist(NULL);
481
482 while (p != NULL) {
483 UFreeFile(); /* free current loaded file */
484 file.name = p->path;
485 file.malloc = FALSE;
486 if (file.name != NULL)
487 ULoadFile(); /* load the new file */
488 if (file.name != NULL) {
489 (void) CoreSound_StartMonitor(); /* play */
490
491 /* play finished */
492 puts(MESSAGE_STOP_PLAYLIST);
493 usleep(50000);
494 if (PlayListWaitForKey())
495 break;
496 }
497 p = next_playlist(p);
498 }
499 free(s);
500 break;
501 }
502 /* SAVE */
503 case 's':
504 free(s);
505 printf(MESSAGE_FILENAME);
506 fflush(stdout);
507 s = ReadString();
508 if (s == NULL) {
509 error("%s", MESSAGE_NO_MEMORY);
510 break;
511 }
512 if (*s == 0) {
513 free(s);
514 break;
515 }
516 PlayListSaveFile(s);
517 free(s);
518 break;
519 /* NEW ITEM */
520 case 'n':
521 {
522 struct playlist *p;
523 char *name, buf[1024];
524 int ret;
525
526 free(s);
527 printf(MESSAGE_FILENAME);
528 fflush(stdout);
529 s = ReadString();
530 if (s == NULL) {
531 error("%s", MESSAGE_NO_MEMORY);
532 break;
533 }
534 if (*s == '\0') {
535 free(s);
536 break;
537 }
538 /* convert relative paths into absolute paths */
539 TrimString(s);
540 if (s[0] != '/') {
541 snprintf(buf, 1024, "%s/%s", pathbuf, s);
542 free(s);
543 s = safecopyof(buf);
544 }
545 p = new_playlist();
546 if (p == NULL) {
547 error("%s", MESSAGE_NO_MEMORY);
548 exit(UM_ERR_MEMORY);
549 }
550 p->path = s;
551 name = safecopyof(s);
552 ret = item_get_info(p, name, buf, 1024);
553 free(name);
554 break;
555 }
556 /* DELETE ITEM */
557 case 'd':
558 {
559 int no;
560 struct playlist *p;
561
562 asknum_d:
563 free(s);
564 fputs("delete item number [first item is 0; press ENTER to cancel]? ", stdout);
565 fflush(stdout);
566 s = ReadString();
567 if (s == NULL) {
568 error("%s", MESSAGE_NO_MEMORY);
569 break;
570 }
571 if (*s == '\0') {
572 free(s);
573 break;
574 }
575
576 no = atoi(s);
577 p = find_playlist(no);
578 if (p == NULL) {
579 puts(MESSAGE_CANT_FIND_ITEM);
580 goto asknum_d; /* ask again */
581 }
582
583 delete_playlist(p);
584 free(s);
585 break;
586 }
587 /* MOVE ITEM */
588 case 'm':
589 {
590 int from, to;
591
592 free(s);
593 fputs("move item number [first item is 0; press ENTER to cancel]? ", stdout);
594 fflush(stdout);
595 s = ReadString();
596 if (s == NULL) {
597 error("%s", MESSAGE_NO_MEMORY);
598 break;
599 }
600 if (*s == '\0') {
601 free(s);
602 break;
603 }
604 from = atoi(s);
605 free(s);
606
607 fputs("new position for the item [start at 0; ENTER to cancel]? ", stdout);
608 fflush(stdout);
609 s = ReadString();
610 if (s == NULL) {
611 error("%s", MESSAGE_NO_MEMORY);
612 continue;
613 }
614 if (*s == '\0') {
615 free(s);
616 continue;
617 }
618
619 to = atoi(s);
620 ErrorDispatch(move_playlist(from, to), s);
621 free(s);
622 break;
623 }
624 /* PRINT PLAYLIST */
625 case 'v':
626 free(s);
627 print_list();
628 break;
629 }
630 }
631 return;
632 }
633
634 EXPORT char *
DetermineType()635 DetermineType()
636 {
637 int type;
638
639 type = ModPlug_GetModuleType(file.mod);
640 switch (type) {
641 case MOD_TYPE_MOD:
642 return "Amiga Module (MOD)";
643 break;
644 case MOD_TYPE_S3M:
645 return "Scream Tracker 3 (S3M)";
646 break;
647 case MOD_TYPE_XM:
648 return "Extended Module (XM)";
649 break;
650 case MOD_TYPE_MED:
651 return "OctaMED (MED)";
652 break;
653 case MOD_TYPE_MTM:
654 return "MultiTracker (MTM)";
655 break;
656 case MOD_TYPE_IT:
657 return "Impulse Tracker (IT)";
658 break;
659 case MOD_TYPE_669:
660 return "Composer 669 (669)";
661 break;
662 case MOD_TYPE_ULT:
663 return "ULT";
664 break;
665 case MOD_TYPE_STM:
666 return "Scream Tracker (STM)";
667 break;
668 case MOD_TYPE_FAR:
669 return "Farandole (FAR)";
670 break;
671 case MOD_TYPE_WAV:
672 return "Wave Audio (WAV)";
673 break;
674 case MOD_TYPE_AMF:
675 return "AMF";
676 break;
677 case MOD_TYPE_AMS:
678 return "AMS";
679 break;
680 case MOD_TYPE_DSM:
681 return "DSM";
682 break;
683 case MOD_TYPE_MDL:
684 return "MDL";
685 break;
686 case MOD_TYPE_OKT:
687 return "OKT";
688 break;
689 case MOD_TYPE_MID:
690 return "MIDI (MID)";
691 break;
692 case MOD_TYPE_DMF:
693 return "DMF";
694 break;
695 case MOD_TYPE_PTM:
696 return "PTM";
697 break;
698 case MOD_TYPE_DBM:
699 return "DBM";
700 break;
701 case MOD_TYPE_MT2:
702 return "MT2";
703 break;
704 case MOD_TYPE_AMF0:
705 return "AMF";
706 break;
707 case MOD_TYPE_PSM:
708 return "PSM";
709 break;
710 case MOD_TYPE_J2B:
711 return "J2B";
712 break;
713 case MOD_TYPE_UMX:
714 return "Unreal Pack (UMX)";
715 break;
716 default:
717 return "Unknown";
718 }
719 }
720
721
722