static int test_pha(const uint8 *data, char *t, int s) { int i; int ptr, ssize; PW_REQUEST_DATA(s, 451 + 128 * 4); if (data[10] != 0x03 || data[11] != 0xc0) return -1; /* test #2 (volumes,sample addresses and whole sample size) */ ssize = 0; for (i = 0; i < 31; i++) { const uint8 *d = data + i * 14; /* sample size */ ssize += readmem16b(d) << 1; if (d[3] > 0x40) return -1; /* loop start */ if ((readmem16b(d + 4) << 1) > ssize) return -1; /* address of sample data */ if (readmem32b(d + 8) < 0x3c0) return -1; } if (ssize <= 2 || ssize > 31 * 65535) return -1; /* test #3 (addresses of pattern in file ... ptk_tableible ?) */ /* l is the whole sample size */ /* ssize is used here as a variable ... set to 0 afterward */ for (i = 0; i < 128; i++) { ptr = readmem32b(data + 448 + i * 4); if (ptr + 2 - 960 < ssize) return -1; } pw_read_title(NULL, t, 0); return 0; }
static int test_hrt(const uint8 *data, char *t, int s) { int i; PW_REQUEST_DATA(s, 1084); if (readmem32b(data + 1080) != MAGIC4('H','R','T','!')) return -1; for (i = 0; i < 31; i++) { const uint8 *d = data + 20 + i * 30; /* test finetune */ if (d[24] > 0x0f) return -1; /* test volume */ if (d[25] > 0x40) return -1; } pw_read_title(data, t, 20); return 0; }
static int test_pru2(uint8 *data, char *t, int s) { int k; PW_REQUEST_DATA(s, 12 + 31 * 8); if (readmem32b(data) != 0x534e5421) return -1; #if 0 /* check sample address */ j = (data[i + 4] << 24) + (data[i + 5] << 16) + (data[i + 6] << 8) + data[i + 7]; PW_REQUEST_DATA (s, j); #endif /* test volumes */ for (k = 0; k < 31; k++) { if (data[11 + k * 8] > 0x40) return -1; } /* test finetunes */ for (k = 0; k < 31; k++) { if (data[10 + k * 8] > 0x0F) return -1; } pw_read_title(NULL, t, 0); return 0; }
static int test_fuzz (uint8 *data, int s) { int j, k; int start = 0, ssize = 0; if (readmem32b(data) != MAGIC4('M','1','.','0')) return -1; /* test finetune */ for (k = 0; k < 31; k++) { if (data[start + 72 + k * 68] > 0x0f) return -1; } /* test volumes */ for (k = 0; k < 31; k++) { if (data[start + 73 + k * 68] > 0x40) return -1; } /* test sample sizes */ for (k = 0; k < 31; k++) { j = readmem16b(data + start + k * 68 + 66); if (j > 0x8000) return -1; ssize += j * 2; } /* test size of pattern list */ if (data[start + 2114] == 0x00) return -1; return 0; }
/* Returns bytes still to read.. or < 0 if error. */ static int checkS404File(uint32 *buf, /*size_t len,*/ int32 *oLen, int32 *pLen, int32 *sLen ) { /*if (len < 16) return -1;*/ if (memcmp(buf, "S404", 4) != 0) return -1; *sLen = readmem32b((uint8 *)&buf[1]); /* Security length */ if (*sLen < 0) return -1; *oLen = readmem32b((uint8 *)&buf[2]); /* Depacked length */ if (*oLen < 0) return -1; *pLen = readmem32b((uint8 *)&buf[3]); /* Packed length */ if (*pLen < 0) return -1; return 0; }
static int test_muse(unsigned char *b) { if (memcmp(b, "MUSE", 4) == 0) { uint32 r = readmem32b(b + 4); /* MOD2J2B uses 0xdeadbabe */ if (r == 0xdeadbeaf || r == 0xdeadbabe) { return 1; } } return 0; }
static int test_ntp(uint8 *data, int s) { int j, k; int start = 0; PW_REQUEST_DATA(s, 64); if (readmem32b(data + start) != MAGIC4('M','O','D','U')) return -1; j = readmem16b(data + start + 20) + 4; /* "BODY" tag */ k = readmem16b(data + start + 28) + j + 4; /* "SAMP" tag */ PW_REQUEST_DATA(s, j + 4); if (readmem32b(data + start + j) != MAGIC4('B','O','D','Y')) return -1; PW_REQUEST_DATA(s, k + 4); if (readmem32b(data + start + k) != MAGIC4('S','A','M','P')) return -1; return 0; }
uint32 hio_read32b(HIO_HANDLE *h) { if (HIO_HANDLE_TYPE(h) == HIO_HANDLE_TYPE_FILE) { return read32b(h->f); } else { ptrdiff_t can_read = CAN_READ(h); if (can_read >= 4) { uint32 n = readmem32b(h->start + h->pos); h->pos += 4; return n; } else { h->pos += can_read; return EOF; } } }
static int test_skyt(const uint8 *data, char *t, int s) { int i; PW_REQUEST_DATA(s, 8 * 31 + 12); /* test 2 */ for (i = 0; i < 31; i++) { if (data[8 * i + 4] > 0x40) return -1; } if (readmem32b(data + 256) != MAGIC4('S','K','Y','T')) return -1; pw_read_title(NULL, t, 0); return 0; }
static int test_pru1(uint8 *data, char *t, int s) { PW_REQUEST_DATA(s, 1084); if (readmem32b(data + 1080) != 0x534e542e) /* "SNT." */ return -1; /* test 2 */ if (data[951] != 0x7f) return -1; /* test 3 */ if (data[950] > 0x7f) return -1; pw_read_title(data, t, 20); return 0; }
static int test_mp_id(uint8 *data, char *t, int s) { int j, l, k; int start = 0; /* "TRK1" Module Protector */ if (readmem32b(data) != MAGIC_TRK1) return -1; /* test #1 */ for (j = 0; j < 31; j++) { if (data[start + 6 + 8 * j] > 0x0f) return -1; } /* test #2 */ l = data[start + 252]; if (l > 0x7f || l == 0x00) return -1; /* test #4 */ k = 0; for (j = 0; j < 128; j++) { if (data[start + 254 + j] > k) k = data[start + 254 + j]; if (data[start + 254 + j] > 0x7f) return -1; } k++; /* test #5 ptk notes .. gosh ! (testing all patterns !) */ /* k contains the number of pattern saved */ for (j = 0; j < (256 * k); j++) { l = data[start + 382 + j * 4]; if (l > 19) return -1; } pw_read_title(NULL, t, 0); return 0; }
static int test_pp21(uint8 *data, char *t, int s) { int i; int ssize, tsize, npat, max_ref; ssize = 0; for (i = 0; i < 31; i++) { uint8 *d = data + i * 8; int len = readmem16b(d) << 1; int start = readmem16b(d + 4) << 1; ssize += len; /* finetune > 0x0f ? */ if (d[2] > 0x0f) return -1; /* loop start > size ? */ if (start > len) return -1; } if (ssize <= 2) return -1; /* test #3 about size of pattern list */ npat = data[248]; if (npat == 0 || npat > 127) return -1; /* get the highest track value */ tsize = 0; for (i = 0; i < 512; i++) { int trk = data[250 + i]; if (trk > tsize) tsize = trk; } tsize++; tsize <<= 6; /* test #4 track data value > $4000 ? */ max_ref = 0; for (i = 0; i < tsize; i++) { int ref = readmem16b(data + i * 2 + 762); if (ref > 0x4000) return -1; if (ref > max_ref) max_ref = ref; } /* test #5 reference table size *4 ? */ if (readmem32b(data + (tsize << 1) + 762) != (max_ref + 1) * 4) return -1; pw_read_title(NULL, t, 0); return 0; }
static int decrunch(struct list_head *head, FILE **f, char **s, int ttl) { unsigned char b[1024]; char *cmd; FILE *t; int fd, builtin, res; char *temp2, tmp[PATH_MAX]; struct tmpfilename *temp; int headersize; cmd = NULL; builtin = res = 0; if (get_temp_dir(tmp, PATH_MAX) < 0) return 0; strncat(tmp, "xmp_XXXXXX", PATH_MAX); fseek(*f, 0, SEEK_SET); if ((headersize = fread(b, 1, 1024, *f)) < 100) /* minimum valid file size */ return 0; #if defined __AMIGA__ && !defined __AROS__ if (test_xfd(b, 1024)) { builtin = BUILTIN_XFD; } else #endif if (b[0] == 'P' && b[1] == 'K' && ((b[2] == 3 && b[3] == 4) || (b[2] == '0' && b[3] == '0' && b[4] == 'P' && b[5] == 'K' && b[6] == 3 && b[7] == 4))) { /* Zip */ builtin = BUILTIN_ZIP; } else if (b[2] == '-' && b[3] == 'l' && b[4] == 'h') { /* LHa */ builtin = BUILTIN_LHA; } else if (b[0] == 31 && b[1] == 139) { /* gzip */ builtin = BUILTIN_GZIP; } else if (b[0] == 'B' && b[1] == 'Z' && b[2] == 'h') { /* bzip2 */ builtin = BUILTIN_BZIP2; } else if (b[0] == 0xfd && b[3] == 'X' && b[4] == 'Z' && b[5] == 0x00) { /* xz */ builtin = BUILTIN_XZ; #if 0 } else if (b[0] == 'Z' && b[1] == 'O' && b[2] == 'O' && b[3] == ' ') { /* zoo */ builtin = BUILTIN_ZOO; #endif } else if (b[0] == 'M' && b[1] == 'O' && b[2] == '3') { /* MO3 */ cmd = "unmo3 -s \"%s\" STDOUT"; } else if (b[0] == 31 && b[1] == 157) { /* compress */ builtin = BUILTIN_COMPRESS; } else if (memcmp(b, "PP20", 4) == 0) { /* PowerPack */ builtin = BUILTIN_PP; } else if (memcmp(b, "XPKF", 4) == 0 && memcmp(b + 8, "SQSH", 4) == 0) { /* SQSH */ builtin = BUILTIN_SQSH; } else if (!memcmp(b, "Archive\0", 8)) { /* ArcFS */ builtin = BUILTIN_ARCFS; } else if (memcmp(b, "ziRCONia", 8) == 0) { /* MMCMP */ builtin = BUILTIN_MMCMP; } else if (memcmp(b, "MUSE", 4) == 0 && readmem32b(b + 4) == 0xdeadbeaf) { /* J2B MUSE */ builtin = BUILTIN_MUSE; } else if (memcmp(b, "MUSE", 4) == 0 && readmem32b(b + 4) == 0xdeadbabe) { /* MOD2J2B MUSE */ builtin = BUILTIN_MUSE; } else if (memcmp(b, "LZX", 3) == 0) { /* LZX */ builtin = BUILTIN_LZX; } else if (memcmp(b, "Rar", 3) == 0) { /* rar */ cmd = "unrar p -inul -xreadme -x*.diz -x*.nfo -x*.txt " "-x*.exe -x*.com \"%s\""; } else if (memcmp(b, "S404", 4) == 0) { /* Stonecracker */ builtin = BUILTIN_S404; } else if (test_oxm(*f) == 0) { /* oggmod */ builtin = BUILTIN_OXM; } if (builtin == 0 && cmd == NULL && b[0] == 0x1a) { int x = b[1] & 0x7f; int i, flag = 0; long size; /* check file name */ for (i = 0; i < 13; i++) { if (b[2 + i] == 0) { if (i == 0) /* name can't be empty */ flag = 1; break; } if (!isprint(b[2 + i])) { /* name must be printable */ flag = 1; break; } } size = readmem32l(b + 15); /* max file size is 512KB */ if (size < 0 || size > 512 * 1024) flag = 1; if (flag == 0) { if (x >= 1 && x <= 9 && x != 7) { /* Arc */ builtin = BUILTIN_ARC; } else if (x == 0x7f) { /* !Spark */ builtin = BUILTIN_ARC; } } } fseek(*f, 0, SEEK_SET); if (builtin == 0 && cmd == NULL) return 0; #if defined ANDROID || defined __native_client__ /* Don't use external helpers in android */ if (cmd) return 0; #endif D_(D_WARN "Depacking file... "); temp = calloc(sizeof (struct tmpfilename), 1); if (!temp) { D_(D_CRIT "calloc failed"); return -1; } temp->name = strdup(tmp); if (temp->name == NULL || (fd = mkstemp(temp->name)) < 0) { D_(D_CRIT "failed"); return -1; } list_add_tail(&temp->list, head); if ((t = fdopen(fd, "w+b")) == NULL) { D_(D_CRIT "failed"); return -1; } if (cmd) { #define BSIZE 0x4000 int n; char line[1024], buf[BSIZE]; FILE *p; snprintf(line, 1024, cmd, *s); #ifdef WIN32 /* Note: The _popen function returns an invalid file opaque, if * used in a Windows program, that will cause the program to hang * indefinitely. _popen works properly in a Console application. * To create a Windows application that redirects input and output, * read the section "Creating a Child Process with Redirected Input * and Output" in the Win32 SDK. -- Mirko */ if ((p = popen(line, "rb")) == NULL) { #else /* Linux popen fails with "rb" */ if ((p = popen(line, "r")) == NULL) { #endif D_(D_CRIT "failed"); fclose(t); return -1; } while ((n = fread(buf, 1, BSIZE, p)) > 0) fwrite(buf, 1, n, t); pclose (p); } else { switch (builtin) { case BUILTIN_PP: res = decrunch_pp(*f, t); break; case BUILTIN_ARC: res = decrunch_arc(*f, t); break; case BUILTIN_ARCFS: res = decrunch_arcfs(*f, t); break; case BUILTIN_SQSH: res = decrunch_sqsh(*f, t); break; case BUILTIN_MMCMP: res = decrunch_mmcmp(*f, t); break; case BUILTIN_MUSE: res = decrunch_muse(*f, t); break; case BUILTIN_LZX: res = decrunch_lzx(*f, t); break; case BUILTIN_S404: res = decrunch_s404(*f, t); break; case BUILTIN_ZIP: res = decrunch_zip(*f, t); break; case BUILTIN_GZIP: res = decrunch_gzip(*f, t); break; case BUILTIN_COMPRESS: res = decrunch_compress(*f, t); break; case BUILTIN_BZIP2: res = decrunch_bzip2(*f, t); break; case BUILTIN_XZ: res = decrunch_xz(*f, t); break; case BUILTIN_LHA: res = decrunch_lha(*f, t); break; #if 0 case BUILTIN_ZOO: res = decrunch_zoo(*f, t); break; #endif case BUILTIN_OXM: res = decrunch_oxm(*f, t); break; #ifdef AMIGA case BUILTIN_XFD: res = decrunch_xfd(*f, t); break; #endif } } if (res < 0) { D_(D_CRIT "failed"); fclose(t); return -1; } D_(D_INFO "done"); fclose(*f); *f = t; if (!--ttl) { return -1; } temp2 = strdup(temp->name); res = decrunch(head, f, &temp->name, ttl); free(temp2); /* Mirko: temp is now deallocated in unlink_tempfiles() * not a problem, since unlink_tempfiles() is called after decrunch * in loader routines * * free(temp); */ return res; } /* * Windows doesn't allow you to unlink an open file, so we changed the * temp file cleanup system to remove temporary files after we close it */ static void unlink_tempfiles(struct list_head *head) { struct tmpfilename *li; struct list_head *tmp; /* can't use list_for_each when freeing the node! */ for (tmp = head->next; tmp != head; ) { li = list_entry(tmp, struct tmpfilename, list); D_(D_INFO "unlink tmpfile %s", li->name); unlink(li->name); free(li->name); list_del(&li->list); tmp = tmp->next; free(li); } } int xmp_test_module(char *path, struct xmp_test_info *info) { HIO_HANDLE *h; struct stat st; char buf[XMP_NAME_SIZE]; int i; struct list_head tmpfiles_list; int ret = -XMP_ERROR_FORMAT;; if (stat(path, &st) < 0) return -XMP_ERROR_SYSTEM; #ifndef _MSC_VER if (S_ISDIR(st.st_mode)) { errno = EISDIR; return -XMP_ERROR_SYSTEM; } #endif if ((h = hio_open_file(path, "rb")) == NULL) return -XMP_ERROR_SYSTEM; INIT_LIST_HEAD(&tmpfiles_list); if (decrunch(&tmpfiles_list, &h->f, &path, DECRUNCH_MAX) < 0) { ret = -XMP_ERROR_DEPACK; goto err; } if (hio_stat(h, &st) < 0) {/* get size after decrunch */ ret = -XMP_ERROR_DEPACK; goto err; } if (st.st_size < 256) { /* set minimum valid module size */ ret = -XMP_ERROR_FORMAT; goto err; } if (info != NULL) { *info->name = 0; /* reset name prior to testing */ *info->type = 0; /* reset type prior to testing */ } for (i = 0; format_loader[i] != NULL; i++) { fseek(h->f, 0, SEEK_SET); if (format_loader[i]->test(h, buf, 0) == 0) { int is_prowizard = 0; if (strcmp(format_loader[i]->name, "prowizard") == 0) { fseek(h->f, 0, SEEK_SET); pw_test_format(h->f, buf, 0, info); is_prowizard = 1; } fclose(h->f); unlink_tempfiles(&tmpfiles_list); if (info != NULL && !is_prowizard) { strncpy(info->name, buf, XMP_NAME_SIZE); strncpy(info->type, format_loader[i]->name, XMP_NAME_SIZE); } return 0; } } err: hio_close(h); unlink_tempfiles(&tmpfiles_list); return ret; }
static int test_tdd(uint8 *data, char *t, int s) { int i; int ssize, psize, pdata_ofs; PW_REQUEST_DATA(s, 564); /* test #2 (volumes,sample addresses and whole sample size) */ ssize = 0; for (i = 0; i < 31; i++) { uint8 *d = data + i * 14; int addr = readmem32b(d + 130); /* sample address */ int size = readmem16b(d + 134); /* sample size */ int sadr = readmem32b(d + 138); /* loop start address */ int lsiz = readmem16b(d + 142); /* loop size (replen) */ /* volume > 40h ? */ if (d[137] > 0x40) return -1; /* loop start addy < sampl addy ? */ if (sadr < addr) return -1; /* addy < 564 ? */ if (addr < 564 || sadr < 564) return -1; /* loop start > size ? */ if (sadr - addr > size) return -1; /* loop start+replen > size ? */ if (sadr - addr + lsiz > size + 2) return -1; ssize += size; } if (ssize <= 2 || ssize > 31 * 65535) return -1; #if 0 /* test #3 (addresses of pattern in file ... ptk_tableible ?) */ /* ssize is the whole sample size :) */ if ((ssize + 564) > in_size) { Test = BAD; return; } #endif /* test size of pattern list */ if (data[0] == 0 || data[0] > 0x7f) return -1; /* test pattern list */ psize = 0; for (i = 0; i < 128; i++) { int pat = data[i + 2]; if (pat > 0x7f) return -1; if (pat > psize) psize = pat; } psize++; psize <<= 10; /* test end of pattern list */ for (i = data[0] + 2; i < 128; i++) { if (data[i + 2] != 0) return -1; } #if 0 /* test if not out of file range */ if ((ssize + 564 + k) > in_size) return -1; #endif /* ssize is the whole sample data size */ /* test pattern data now ... */ pdata_ofs = 564 + ssize; PW_REQUEST_DATA(s, 564 + ssize + psize); for (i = 0; i < psize; i += 4) { uint8 *d = data + pdata_ofs + i; /* sample number > 31 ? */ if (d[0] > 0x1f) return -1; /* note > 0x48 (36*2) */ if (d[1] > 0x48 || (d[1] & 0x01) == 0x01) return -1; /* fx=C and fxtArg > 64 ? */ if ((d[2] & 0x0f) == 0x0c && d[3] > 0x40) return -1; /* fx=D and fxtArg > 64 ? */ if ((d[2] & 0x0f) == 0x0d && d[3] > 0x40) return -1; /* fx=B and fxtArg > 127 ? */ if ((d[2] & 0x0f) == 0x0b) return -1; } pw_read_title(NULL, t, 0); return -1; }
static int test_fuchs (uint8 *data, int s) { int start = 0; int j, k, m, n, o; #if 0 /* test #1 */ if (i < 192) { Test = BAD; return; } start = i - 192; #endif if (readmem32b(data + 192) != 0x534f4e47) /* SONG */ return -1; /* all sample size */ j = ((data[start + 10] << 24) + (data[start + 11] << 16) + (data[start + 12] << 8) + data[start + 13]); if (j <= 2 || j >= (65535 * 16)) return -1; /* samples descriptions */ m = 0; for (k = 0; k < 16; k++) { /* size */ o = (data[start + k * 2 + 14] << 8) + data[start + k * 2 + 15]; /* loop start */ n = (data[start + k * 2 + 78] << 8) + data[start + k * 2 + 79]; /* volumes */ if (data[start + 46 + k * 2] > 0x40) return -1; /* size < loop start ? */ if (o < n) return -1; m += o; } /* m is the size of all samples (in descriptions) */ /* j is the sample data sizes (header) */ /* size<2 or size > header sample size ? */ if (m <= 2 || m > j) return -1; /* get highest pattern number in pattern list */ k = 0; for (j = 0; j < 40; j++) { n = data[start + j * 2 + 113]; if (n > 40) return -1; if (n > k) k = n; } /* m is the size of all samples (in descriptions) */ /* k is the highest pattern data -1 */ #if 0 /* input file not long enough ? */ k += 1; k *= 1024; PW_REQUEST_DATA (s, k + 200); #endif /* m is the size of all samples (in descriptions) */ /* k is the pattern data size */ return 0; }
static int test_tdd (uint8 *data, int s) { int j, k, l, m, n; int start = 0, ssize; PW_REQUEST_DATA (s, 564); /* test #2 (volumes,sample addresses and whole sample size) */ ssize = 0; for (j = 0; j < 31; j++) { uint8 *d = data + start + j * 14; k = readmem32b(d + 130); /* sample address */ l = readmem16b(d + 134); /* sample size */ m = readmem32b(d + 138); /* loop start address */ n = readmem16b(d + 142); /* loop size (replen) */ /* volume > 40h ? */ if (data[start + j * 14 + 137] > 0x40) return -1; /* loop start addy < sampl addy ? */ if (m < k) return -1; /* addy < 564 ? */ if (k < 564 || m < 564) return -1; /* loop start > size ? */ if (m - k > l) return -1; /* loop start+replen > size ? */ if (m - k + n > l + 2) return -1; ssize += l; } if (ssize <= 2 || ssize > (31 * 65535)) return -1; #if 0 /* test #3 (addresses of pattern in file ... ptk_tableible ?) */ /* ssize is the whole sample size :) */ if ((ssize + 564) > in_size) { /*printf ( "#3 (start:%ld)\n" , start );*/ Test = BAD; return; } #endif /* test size of pattern list */ if (data[start] > 0x7f || data[start] == 0x00) return -1; /* test pattern list */ k = 0; for (j = 0; j < 128; j++) { if (data[start + j + 2] > 0x7f) return -1; if (data[start + j + 2] > k) k = data[start + j + 2]; } k += 1; k *= 1024; /* test end of pattern list */ for (j = data[start] + 2; j < 128; j++) { if (data[start + j + 2] != 0) return -1; } #if 0 /* test if not out of file range */ if ((start + ssize + 564 + k) > in_size) return -1; #endif /* ssize is the whole sample data size */ /* k is the whole pattern data size */ /* test pattern data now ... */ l = start + 564 + ssize; /* l points on pattern data */ for (j = 0; j < k; j += 4) { /* sample number > 31 ? */ if (data[l + j] > 0x1f) return -1; /* note > 0x48 (36*2) */ if (data[l + j + 1] > 0x48 || (data[l + j + 1] & 0x01) == 0x01) return -1; /* fx=C and fxtArg > 64 ? */ if ((data[l + j + 2] & 0x0f) == 0x0c && data[l + j + 3] > 0x40) return -1; /* fx=D and fxtArg > 64 ? */ if ((data[l + j + 2] & 0x0f) == 0x0d && data[l + j + 3] > 0x40) return -1; /* fx=B and fxtArg > 127 ? */ if ((data[l + j + 2] & 0x0f) == 0x0b) return -1; } return -1; }