/* $Id: file_read.c,v 1.13 2006/09/16 10:18:38 toad32767 Exp $ */ /** ** 2005, 2006 by Marco Trillo ** This file is part of UModPlayer, and is released by ** its autors to the Public Domain. ** In case it's not legally possible, its autors grant ** anyone the right to use, redistribute and modify ** this software for any purpose, without any conditions, ** unless such conditions are required by law. ** ** THIS FILE COMES WITHOUT ANY WARRANTY. THE AUTHORS ** SHALL NOT BE LIABLE FOR ANY DAMAGE RESULTING BY THE ** USE OR MISUSE OF THIS SOFTWARE. **/ /* * ===================== * FILE-RELATED STUFF * ===================== */ #include #include #include #include #include #include #include #include #include #include #include /* * Safe variants of malloc(), realloc(), * strcopyof(), and ReadString(). */ LOCAL void * safe_alloc(size_t size) { void *ptr = malloc(size); if (ptr == NULL) { error("%s", MESSAGE_NO_MEMORY); exit(UM_ERR_MEMORY); } return ptr; } LOCAL char * safecopyof(char *s) { char *ptr = strcopyof(s); if (ptr == NULL) { error("%s", MESSAGE_NO_MEMORY); exit(UM_ERR_MEMORY); } return ptr; } LOCAL char * SafeReadString() { char *s = ReadString(); if (s == NULL) { error("%s", MESSAGE_NO_MEMORY); exit(UM_ERR_MEMORY); } return s; } /* * `file.name' is the global variable specifying the module name. * Set `file.name' to NULL if failed. * * If `file.malloc' is TRUE, then `file.name' must be free()'d * before being set to NULL. */ EXPORT void ULoadFile() { int fd; unsigned long remaining, buflen = 0, bufpos; uint8_t *buffer; struct stat buf; if (file.name == NULL) { return; } TrimString(file.name); if (stat(file.name, &buf) == -1) { error("CAN'T stat(\"%s\"): %s\n", file.name, strerror(errno)); goto cleanup; } buflen = (unsigned long) (buf.st_size); if (buflen == 0) { error("size of \"%s\" is zero!\n", file.name); goto cleanup; } fd = open(file.name, O_RDONLY); if (fd == -1) { error("CAN'T open(\"%s\"): %s\n", file.name, strerror(errno)); goto cleanup; } buffer = (uint8_t *) safe_alloc((size_t) buflen); remaining = buflen; bufpos = 0; while (remaining > 0) { long bytes_read; if ((bytes_read = (long) read(fd, buffer + bufpos, (size_t) remaining)) < 1) { error("CAN'T read(): %s\n", strerror(errno)); free(buffer); close(fd); goto cleanup; } remaining -= bytes_read; bufpos += bytes_read; } close(fd); file.mod = ModPlug_Load(buffer, buflen); free(buffer); if (file.mod == NULL) { goto cleanup; } DrawInfoTable(); return; cleanup: if (file.malloc == TRUE) { free(file.name); } file.malloc = FALSE; file.name = NULL; return; } EXPORT void UFreeFile() { if (file.name != NULL) { ModPlug_Unload(file.mod); if (file.malloc == TRUE) free(file.name); file.malloc = FALSE; file.name = NULL; } return; } EXPORT void DisplayCurPos() { notice("Order: %d - Pattern: %d - Row: %d\n", ModPlug_GetCurrentOrder(file.mod), ModPlug_GetCurrentPattern(file.mod), ModPlug_GetCurrentRow(file.mod) ); return; } EXPORT void DrawInfoTable() { WTable table; int bytes_out; if (sets.verbosity == 0) return; rr = (char **) safe_alloc(7 * sizeof(char *)); bytes_out = ModPlug_GetLength(file.mod); bytes_out /= 1000; rr[0] = (char *) safe_alloc(10); sprintf(rr[0], "%d:%02d", bytes_out / 60, bytes_out % 60); rr[1] = safecopyof(DetermineType()); rr[2] = (char *) safe_alloc(20); sprintf(rr[2], "%d instruments", ModPlug_NumInstruments(file.mod)); rr[3] = (char *) safe_alloc(16); sprintf(rr[3], "%d samples", ModPlug_NumSamples(file.mod)); rr[4] = (char *) safe_alloc(18); sprintf(rr[4], "%d channels", ModPlug_NumChannels(file.mod)); rr[5] = (char *) safe_alloc(18); sprintf(rr[5], "%d patterns", ModPlug_NumPatterns(file.mod)); rr[6] = (char *) ModPlug_GetName(file.mod); bytes_out = CalcLen(rr, 7) + 1; TableSetOptions(&table, 1, 6, 2, MAXVAL(bytes_out, 13), 0, TABLE_LEFT_ALIGN); TableSetCaption(&table, rr[6]); TableUseTheme(&table, sets.appareance); TableInitCallback(&table, MyTextCallback); DrawTable(table); for (bytes_out = 0; bytes_out < 6; ++bytes_out) free(rr[bytes_out]); free(rr); return; } EXPORT void ExportSong() { char *p, *q; unsigned long len; char y; printf(MESSAGE_EXPORT); fflush(stdout); p = SafeReadString(); TrimString(p); if (*p == 0) { free(p); return; } for (;;) { startpos = endpos = 0; puts(MESSAGE_FORMATS); puts(MESSAGE_PRESS_ENTER); puts("================ Audio export options ================="); puts("a) Export audio as WAVE (WAV), 16-bit"); puts("b) Export audio as Audio IFF (AIFF), 16-bit"); puts("c) Export audio as Audio IFF (AIFF), 24-bit"); puts("d) Export audio as Audio IFF (AIFF), 32-bit"); puts("e) Export audio as raw system-endian 16-bit PCM"); puts("f) Export audio as raw little-endian 16-bit PCM"); puts("g) Export audio as raw big-endian 16-bit PCM\n"); puts("=============== Module export options ================="); puts("h) Convert to Impulse Tracker (IT)\n"); puts("======================================================="); puts("(audio will be exported using current sound options)"); fputs(MESSAGE_FORMAT, stdout); fflush(stdout); q = SafeReadString(); if (*q == '\0') { free(p); free(q); return; } if (*q == 'a') { len = (unsigned long) WriteWAV(p); if (len < 1) { error("%s\n", MESSAGE_EXPORT_ERROR); } free(p); free(q); return; } if (*q == 'b' || *q == 'c' || *q == 'd') { int ret = 0; if (*q == 'b') ret = WriteAIFF(p, 16); else if (*q == 'c') ret = WriteAIFF(p, 24); else if (*q == 'd') ret = WriteAIFF(p, 32); if (ret < 1) { puts(MESSAGE_EXPORT_ERROR); } free(p); free(q); return; } if (*q == 'e') { len = WritePCM(p, EXPORT_SYS_ENDIAN); if (len < 1) { error("%s\n", MESSAGE_EXPORT_ERROR); } free(p); free(q); return; } if (*q == 'f') { len = WritePCM(p, EXPORT_LTE_ENDIAN); if (len < 1) { error("%s\n", MESSAGE_EXPORT_ERROR); } free(p); free(q); return; } if (*q == 'g') { len = WritePCM(p, EXPORT_BIG_ENDIAN); if (len < 1) { error("%s\n", MESSAGE_EXPORT_ERROR); } free(p); free(q); return; } if (*q == 'h') { #ifdef MODPLUG_CAN_SAVE y = ModPlug_ExportIT(file.mod, p); #else error("ModPlug compiled without 'save' support\n"); y = 0; #endif if (y != 1) { error("%s\n", MESSAGE_EXPORT_ERROR); } else { notice("%s\n", MESSAGE_DONE); } free(p); free(q); return; } free(q); } return; } LOCAL void ErrorDispatch(int ret, char *data) { switch (ret) { case UM_ERR_NOITEM: error("%s\n", MESSAGE_CANT_FIND_ITEM); break; case UM_ERR_IO: error("I/O error: %s: %s\n", data, strerror(errno)); break; case UM_ERR_MEMORY: error("Memory error: %s\n", strerror(errno)); break; case UM_ERR_INTERNAL: error("Internal error (%s)\n", data); break; case UM_OK: return; default: error("Unknown error: %d. Please report this bug.\n", ret); } } LOCAL void PlayListLoadFolder() { char path[1024]; getcwd(path, 1024); ErrorDispatch(list_from_dir(path), path); } LOCAL void PlayListSaveFile(char *finame) { ErrorDispatch(save_list(finame), finame); } LOCAL void PlayListLoadFile(char *finame) { ErrorDispatch(load_list(finame), finame); } /* * wait 2 seconds for a key, to interrupt the playlist course */ LOCAL int PlayListWaitForKey() { int keyHit; fd_set fds; struct timeval tv; struct termios term, _term; tcgetattr(0, &_term); memcpy(&term, &_term, sizeof(term)); cfmakeraw(&term); tcsetattr(0, TCSANOW, &term); FD_ZERO(&fds); FD_SET(0, &fds); tv.tv_sec = 2; tv.tv_usec = 0; keyHit = select(1, &fds, NULL, NULL, &tv); tcsetattr(0, TCSANOW, &_term); return keyHit; } EXPORT void PlayList() { char *s, pathbuf[512]; getcwd(pathbuf, 512); puts(MESSAGE_PRESS_ENTER); puts("a) Import playlist from current dir."); puts("b) Load a saved playlist"); puts("c) New Playlist"); fputs(MESSAGE_OPTION, stdout); fflush(stdout); s = SafeReadString(); if (*s == '\0') { free(s); return; } switch (*s) { case 'a': PlayListLoadFolder(); break; case 'b': printf(MESSAGE_FILENAME); fflush(stdout); free(s); s = SafeReadString(); if (*s == '\0') { free(s); return; } PlayListLoadFile(s); break; case 'c': break; default: free(s); return; } free(s); print_list(); for (;;) { puts(MESSAGE_PRESS_ENTER); puts("p) PLAY"); puts("s) SAVE"); puts("n) NEW ITEM"); puts("d) DELETE ITEM"); puts("m) MOVE ITEM"); puts("v) VIEW ITEMS"); puts("q) QUIT"); printf(MESSAGE_OPTION); fflush(stdout); s = SafeReadString(); if (*s == '\0') { free(s); continue; } switch (*s) { case 'q': if (s != NULL) free(s); warning("playlist will be deleted. are you sure [y/n]? "); fflush(stderr); s = SafeReadString(); if (*s != 'y') { free(s); break; } free(s); delete_list(); return; /* PLAY */ case 'p': { struct playlist *p = next_playlist(NULL); while (p != NULL) { UFreeFile(); /* free current loaded file */ file.name = p->path; file.malloc = FALSE; if (file.name != NULL) ULoadFile(); /* load the new file */ if (file.name != NULL) { (void) CoreSound_StartMonitor(); /* play */ /* play finished */ puts(MESSAGE_STOP_PLAYLIST); usleep(50000); if (PlayListWaitForKey()) break; } p = next_playlist(p); } free(s); break; } /* SAVE */ case 's': free(s); printf(MESSAGE_FILENAME); fflush(stdout); s = ReadString(); if (s == NULL) { error("%s", MESSAGE_NO_MEMORY); break; } if (*s == 0) { free(s); break; } PlayListSaveFile(s); free(s); break; /* NEW ITEM */ case 'n': { struct playlist *p; char *name, buf[1024]; int ret; free(s); printf(MESSAGE_FILENAME); fflush(stdout); s = ReadString(); if (s == NULL) { error("%s", MESSAGE_NO_MEMORY); break; } if (*s == '\0') { free(s); break; } /* convert relative paths into absolute paths */ TrimString(s); if (s[0] != '/') { snprintf(buf, 1024, "%s/%s", pathbuf, s); free(s); s = safecopyof(buf); } p = new_playlist(); if (p == NULL) { error("%s", MESSAGE_NO_MEMORY); exit(UM_ERR_MEMORY); } p->path = s; name = safecopyof(s); ret = item_get_info(p, name, buf, 1024); free(name); break; } /* DELETE ITEM */ case 'd': { int no; struct playlist *p; asknum_d: free(s); fputs("delete item number [first item is 0; press ENTER to cancel]? ", stdout); fflush(stdout); s = ReadString(); if (s == NULL) { error("%s", MESSAGE_NO_MEMORY); break; } if (*s == '\0') { free(s); break; } no = atoi(s); p = find_playlist(no); if (p == NULL) { puts(MESSAGE_CANT_FIND_ITEM); goto asknum_d; /* ask again */ } delete_playlist(p); free(s); break; } /* MOVE ITEM */ case 'm': { int from, to; free(s); fputs("move item number [first item is 0; press ENTER to cancel]? ", stdout); fflush(stdout); s = ReadString(); if (s == NULL) { error("%s", MESSAGE_NO_MEMORY); break; } if (*s == '\0') { free(s); break; } from = atoi(s); free(s); fputs("new position for the item [start at 0; ENTER to cancel]? ", stdout); fflush(stdout); s = ReadString(); if (s == NULL) { error("%s", MESSAGE_NO_MEMORY); continue; } if (*s == '\0') { free(s); continue; } to = atoi(s); ErrorDispatch(move_playlist(from, to), s); free(s); break; } /* PRINT PLAYLIST */ case 'v': free(s); print_list(); break; } } return; } EXPORT char * DetermineType() { int type; type = ModPlug_GetModuleType(file.mod); switch (type) { case MOD_TYPE_MOD: return "Amiga Module (MOD)"; break; case MOD_TYPE_S3M: return "Scream Tracker 3 (S3M)"; break; case MOD_TYPE_XM: return "Extended Module (XM)"; break; case MOD_TYPE_MED: return "OctaMED (MED)"; break; case MOD_TYPE_MTM: return "MultiTracker (MTM)"; break; case MOD_TYPE_IT: return "Impulse Tracker (IT)"; break; case MOD_TYPE_669: return "Composer 669 (669)"; break; case MOD_TYPE_ULT: return "ULT"; break; case MOD_TYPE_STM: return "Scream Tracker (STM)"; break; case MOD_TYPE_FAR: return "Farandole (FAR)"; break; case MOD_TYPE_WAV: return "Wave Audio (WAV)"; break; case MOD_TYPE_AMF: return "AMF"; break; case MOD_TYPE_AMS: return "AMS"; break; case MOD_TYPE_DSM: return "DSM"; break; case MOD_TYPE_MDL: return "MDL"; break; case MOD_TYPE_OKT: return "OKT"; break; case MOD_TYPE_MID: return "MIDI (MID)"; break; case MOD_TYPE_DMF: return "DMF"; break; case MOD_TYPE_PTM: return "PTM"; break; case MOD_TYPE_DBM: return "DBM"; break; case MOD_TYPE_MT2: return "MT2"; break; case MOD_TYPE_AMF0: return "AMF"; break; case MOD_TYPE_PSM: return "PSM"; break; case MOD_TYPE_J2B: return "J2B"; break; case MOD_TYPE_UMX: return "Unreal Pack (UMX)"; break; default: return "Unknown"; } }