/* $Id: modinfo.c,v 1.4 2006/09/15 13:34:06 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. **/ #include #include #include #include /* Number of instruments of a MODULE */ EXPORT int number_instruments(MODULE * modfile) { unsigned char ins = 0; char *buffer; short type; int modlen; type = modfile->type; modlen = modfile->buflen; switch (type) { case TYPE_SCREAM_3: case TYPE_IMPULSE: if (modlen > 36) { buffer = modfile->buf + 34; ins = (unsigned char) (*buffer); } break; case TYPE_AMIGA_MOD: ins = 31; break; case TYPE_FT2: if (modlen > 74) { buffer = modfile->buf + 72; ins = (unsigned char) (*buffer); } break; } return ((int) ins); } /* Number of orders of a MODULE */ EXPORT int number_orders(MODULE * modfile) { uint16_t ord = 0; char *buffer; short type; int modlen; type = modfile->type; modlen = modfile->buflen; switch (type) { case TYPE_SCREAM_3: case TYPE_IMPULSE: if (modlen > 34) { buffer = modfile->buf + 32; ord = (uint16_t) (*(buffer++)); ord <<= 8; ord |= (uint16_t) (*buffer); ord = bsLE16(ord); } break; case TYPE_AMIGA_MOD: if (modlen > 950) { buffer = modfile->buf + 950; ord = (uint16_t) (*buffer); } break; case TYPE_FT2: if (modlen > 72) { buffer = modfile->buf + 70; ord = (uint16_t) (*(buffer++)); ord <<= 8; ord |= (uint16_t) (*buffer); ord = bsLE16(ord); } break; } return ((int) ord); } /* Loads & typedetects a module to a MODULE struct */ EXPORT int load_module(MODULE * modfile, char *buffer, int buflen) { char *buf; short type; uint32_t *magic; uint32_t z; type = TYPE_UNKNOWN; /* XM`s identifier is 'Extended Module: ', starting at offset 0 */ if (buflen > 17) { if (memcmp(buffer, "Extended Module: ", 17) == 0) { type = TYPE_FT2; } } /* IT`s identifier is 'IMPM', starting at offset 0 */ if (buflen > 4) { magic = (uint32_t *) buffer; z = 0x494D504D; z = bsBE32(z); if (z == (*magic)) { type = TYPE_IMPULSE; } } /* S3M`s identifier is 'SCRM', starting at offset 44 (28+4+2*6) */ if (buflen > 48) { buf = buffer + 44; magic = (uint32_t *) buf; z = 0x5343524D; z = bsBE32(z); if (z == (*magic)) { type = TYPE_SCREAM_3; } } /* MOD has a lot of identifiers, starting at offset 1080 */ if (buflen > 1084) { buf = buffer + 1080; memcpy(&z, buf, 4); z = bsBE32(z); switch (z) { /* Thanks to the Modfil11.txt for this identifiers */ case 0x4d2e4b2e: case 0x46544c34: case 0x4d214b21: case 0x3443484e: case 0x3643484e: case 0x3843484e: case 0x4f435441: case 0x464c5434: case 0x43443831: case 0x464c5438: type = TYPE_AMIGA_MOD; break; } } modfile->type = type; modfile->buflen = buflen; modfile->buf = buffer; if (type == TYPE_UNKNOWN) return -1; return 0; } /* Returns the name of the "numinst" instument as a null-terminated string */ /* Returned value must be free()`d */ EXPORT char * return_instrument_name(MODULE * mod, int numinst) { register int i, j; char *buffer; char *insname; char *limit; int orders; int instruments; uint16_t z; uint32_t Z; int offset; int numsamples; unsigned int hlen; int G; orders = number_orders(mod); instruments = number_instruments(mod); if (orders < 1) return NULL; if (instruments < (numinst + 1)) return NULL; insname = NULL; switch (mod->type) { case TYPE_SCREAM_3: if (mod->buflen > (96 + orders + (instruments << 1))) { buffer = mod->buf + 96 + orders; buffer += (numinst << 1); z = (uint16_t) (*(buffer++)); z <<= 8; z |= (uint16_t) (*buffer); z = bsLE16(z); offset = ((int) z) << 4; offset += 48; if (mod->buflen <= offset) break; buffer = mod->buf + offset; insname = (char *) malloc(strlen(buffer) + 1); if (insname == NULL) break; strcpy(insname, buffer); } break; case TYPE_IMPULSE: if (mod->buflen > (192 + orders + (instruments << 2))) { buffer = mod->buf + 192 + orders; buffer += (numinst << 2); memcpy(&Z, buffer, 4); Z = bsLE32(Z); if (mod->buflen <= ((int) Z) + 32) break; buffer = mod->buf + Z + 32; insname = (char *) malloc(strlen(buffer) + 1); if (insname == NULL) break; strcpy(insname, buffer); } break; case TYPE_AMIGA_MOD: if (mod->buflen > (50 + 30 * numinst)) { buffer = mod->buf + 20; buffer += numinst * 30; insname = (char *) malloc(23); if (insname == NULL) break; i = 22; while (i--) insname[i] = buffer[i]; insname[22] = 0; } break; case TYPE_FT2: if (mod->buflen > 80 + 73 * orders) { buffer = mod->buf + 336; limit = mod->buf + mod->buflen; /* Processing patterns... */ for (i = 0; i < orders; ++i) { buffer += 7; if (buffer + 1 >= limit) break; z = (uint16_t) (*(buffer++)); z <<= 8; z |= (uint16_t) (*(buffer++)); z = bsLE16(z); buffer += z; } if (buffer + 1 >= limit) break; /* Processing instruments... */ for (i = 0; i < numinst; ++i) { if (buffer + 29 >= limit) break; z = (uint16_t) (*(buffer + 27)); z <<= 8; z |= (uint16_t) (*(buffer + 28)); z = bsLE16(z); numsamples = (int) z; /* Processing samples... */ if (numsamples > 0) { if ((buffer + 33) >= limit) break; memcpy(&Z, buffer + 29, 4); Z = bsLE32(Z); hlen = (unsigned int) Z; buffer += 0x107; G = 0; for (j = 0; j < numsamples; ++j) { if (buffer + 4 >= limit) break; memcpy(&Z, buffer, 4); Z = bsLE32(Z); buffer += 0x28; G += Z; } buffer += G; if (buffer >= limit) break; } else { memcpy(&Z, buffer, 4); Z = bsLE32(Z); buffer += Z; } } insname = NULL; buffer += 4; if (buffer + 23 >= limit) break; insname = (char *) malloc(23); i = 22; while (i--) insname[i] = buffer[i]; insname[22] = 0; } break; } return insname; } /* Fetch the module name into `buffer' */ EXPORT void module_name(MODULE * modfile, char *buffer) { int O; int i; O = 0; switch (modfile->type) { case TYPE_IMPULSE: O = 4; case TYPE_SCREAM_3: strcpy(buffer, modfile->buf + O); break; case TYPE_FT2: O = 17; case TYPE_AMIGA_MOD: i = 0; memcpy(buffer, modfile->buf + O, 20); buffer[20] = 0; break; } return; } EXPORT short module_type(MODULE * modfile) { return modfile->type; } EXPORT char * module_typestr(short type) { switch (type) { case TYPE_IMPULSE: return "IT"; break; case TYPE_SCREAM_3: return "S3M"; break; case TYPE_FT2: return "XM"; break; case TYPE_AMIGA_MOD: return "MOD"; break; default: return "???"; } return NULL; } #ifdef MODINFO_DEBUG #include #include #include #include char * xm_retr_file(int fd, int *len) { char *buffer; int buflen = 0; int bytes_out = 0; buffer = (char *) malloc(1024); while ((bytes_out = read(fd, buffer + buflen, 1024)) != 0) { if (bytes_out == -1) break; buflen += bytes_out; buffer = (char *) realloc(buffer, 1024 + buflen); if (buffer == NULL) return NULL; } buffer = (char *) realloc(buffer, buflen); if (buffer == NULL) return NULL; *len = buflen; return buffer; } main(argc, argv) char **argv; { int i; char *buffer; static char modname[128]; MODULE mod; int buflen; int fd; char *typ = NULL; int ins; if (argc < 2) return 1; fd = open(argv[1], O_RDONLY); if (fd < 0) return 1; buffer = xm_retr_file(fd, &buflen); if (buflen < 1) return 1; load_module(&mod, buffer, buflen); switch (module_type(&mod)) { case TYPE_IMPULSE: typ = "Impulse Tracker"; break; case TYPE_SCREAM_3: typ = "Scream Tracker 3"; break; case TYPE_FT2: typ = "FastTracker II"; break; case TYPE_AMIGA_MOD: typ = "ProTracker/NoiseTracker"; break; } if (typ == NULL) return 1; module_name(&mod, modname); printf("Kind : [%s module]\n", typ); printf("Name : [%s]\n", modname); printf("Has:\n\t%d orders\n\t%d instruments\nInstrument names:\n", number_orders(&mod), (ins = number_instruments(&mod)) ); for (i = 0; i < ins; ++i) { typ = return_instrument_name(&mod, i); printf("\t(%d) => [%s]\n", i, typ); if (typ) free(typ); } puts(""); return 0; } #endif /* * @EOF@ -- revised May 6 2006 */