int check_md5(char *path, char *digest) { unsigned char buf[BUFLEN]; MD5_CTX ctx; FILE *f; int bytes_read; f = fopen(path, "rb"); if (f == NULL) return -1; MD5Init(&ctx); while ((bytes_read = fread(buf, 1, BUFLEN, f)) > 0) { MD5Update(&ctx, buf, bytes_read); } MD5Final(&ctx); fclose(f); return compare_md5(ctx.digest, digest); }
int compare_module(struct xmp_module *mod, FILE *f) { char line[1024]; char *s; int i, j, x; /* Check title and format */ read_line(line, 1024, f); fail_unless(!strcmp(line, mod->name), "module name"); read_line(line, 1024, f); fail_unless(!strcmp(line, mod->type), "module type"); /* Check module attributes */ read_line(line, 1024, f); x = strtoul(line, &s, 0); fail_unless(x == mod->pat, "number of patterns"); x = strtoul(s, &s, 0); fail_unless(x == mod->trk, "number of tracks"); x = strtoul(s, &s, 0); fail_unless(x == mod->chn, "number of channels"); x = strtoul(s, &s, 0); fail_unless(x == mod->ins, "number of instruments"); x = strtoul(s, &s, 0); fail_unless(x == mod->smp, "number of samples"); x = strtoul(s, &s, 0); fail_unless(x == mod->spd, "initial speed"); x = strtoul(s, &s, 0); fail_unless(x == mod->bpm, "initial tempo"); x = strtoul(s, &s, 0); fail_unless(x == mod->len, "module length"); x = strtoul(s, &s, 0); fail_unless(x == mod->rst, "restart position"); x = strtoul(s, &s, 0); fail_unless(x == mod->gvl, "global volume"); /* Check orders */ if (mod->len > 0) { read_line(line, 1024, f); s = line; for (i = 0; i < mod->len; i++) { x = strtoul(s, &s, 0); fail_unless(x == mod->xxo[i], "orders"); } } /* Check instruments */ for (i = 0; i < mod->ins; i++) { struct xmp_instrument *xxi = &mod->xxi[i]; read_line(line, 1024, f); x = strtoul(line, &s, 0); fail_unless(x == xxi->vol, "instrument volume"); x = strtoul(s, &s, 0); fail_unless(x == xxi->nsm, "number of subinstruments"); x = strtoul(s, &s, 0); fail_unless(x == xxi->rls, "instrument release"); x = strncmp(++s, xxi->name, 32); fail_unless(x == 0, "instrument name"); /* check envelopes */ check_envelope(&xxi->aei, line, f); check_envelope(&xxi->fei, line, f); check_envelope(&xxi->pei, line, f); /* check mapping */ read_line(line, 1024, f); s = line; for (j = 0; j < XMP_MAX_KEYS; j++) { x = strtoul(s, &s, 0); fail_unless(x == xxi->map[j].ins, "instrument map"); } read_line(line, 1024, f); s = line; for (j = 0; j < XMP_MAX_KEYS; j++) { x = strtoul(s, &s, 0); fail_unless(x == xxi->map[j].xpo, "transpose map"); } /* check subinstruments */ for (j = 0; j < xxi->nsm; j++) { struct xmp_subinstrument *sub = &xxi->sub[j]; read_line(line, 1024, f); x = strtoul(line, &s, 0); fail_unless(x == sub->vol, "subinst volume"); x = strtoul(s, &s, 0); fail_unless(x == sub->gvl, "subinst gl volume"); x = strtoul(s, &s, 0); fail_unless(x == sub->pan, "subinst pan"); x = strtoul(s, &s, 0); fail_unless(x == sub->xpo, "subinst transpose"); x = strtoul(s, &s, 0); fail_unless(x == sub->fin, "subinst finetune"); x = strtoul(s, &s, 0); fail_unless(x == sub->vwf, "subinst vibr wf"); x = strtoul(s, &s, 0); fail_unless(x == sub->vde, "subinst vibr depth"); x = strtoul(s, &s, 0); fail_unless(x == sub->vra, "subinst vibr rate"); x = strtoul(s, &s, 0); fail_unless(x == sub->vsw, "subinst vibr sweep"); x = strtoul(s, &s, 0); fail_unless(x == sub->rvv, "subinst vol var"); x = strtoul(s, &s, 0); fail_unless(x == sub->sid, "subinst sample nr"); x = strtoul(s, &s, 0); fail_unless(x == sub->nna, "subinst NNA"); x = strtoul(s, &s, 0); fail_unless(x == sub->dct, "subinst DCT"); x = strtoul(s, &s, 0); fail_unless(x == sub->dca, "subinst DCA"); x = strtoul(s, &s, 0); fail_unless(x == sub->ifc, "subinst cutoff"); x = strtoul(s, &s, 0); fail_unless(x == sub->ifr, "subinst resonance"); } } /* Check patterns */ for (i = 0; i < mod->pat; i++) { struct xmp_pattern *xxp = mod->xxp[i]; read_line(line, 1024, f); x = strtoul(line, &s, 0); fail_unless(x == xxp->rows, "pattern rows"); for (j = 0; j < mod->chn; j++) { x = strtoul(s, &s, 0); fail_unless(x == xxp->index[j], "pattern index"); } } /* Check tracks */ for (i = 0; i < mod->trk; i++) { struct xmp_track *xxt = mod->xxt[i]; unsigned char d[16]; MD5_CTX ctx; read_line(line, 1024, f); x = strtoul(line, &s, 0); fail_unless(x == xxt->rows, "track rows"); MD5Init(&ctx); MD5Update(&ctx, (const unsigned char *)xxt->event, xxt->rows * sizeof (struct xmp_event)); MD5Final(d, &ctx); fail_unless(compare_md5(d, ++s) == 0, "track data"); } /* Check samples */ for (i = 0; i < mod->smp; i++) { struct xmp_sample *xxs = &mod->xxs[i]; unsigned char d[16]; MD5_CTX ctx; int len = xxs->len; if (xxs->flg & XMP_SAMPLE_16BIT) len *= 2; read_line(line, 1024, f); x = strtoul(line, &s, 0); fail_unless(x == xxs->len, "sample length"); x = strtoul(s, &s, 0); fail_unless(x == xxs->lps, "sample loop start"); x = strtoul(s, &s, 0); fail_unless(x == xxs->lpe, "sample loop end"); x = strtoul(s, &s, 0); fail_unless(x == xxs->flg, "sample flags"); s++; if (len > 0 && xxs->data != NULL) { MD5Init(&ctx); MD5Update(&ctx, xxs->data, len); MD5Final(d, &ctx); fail_unless(compare_md5(d, s) == 0, "sample data"); } s += 32; fail_unless(strcmp(xxs->name, ++s) == 0, "sample name"); } /* Check channels */ for (i = 0; i < mod->chn; i++) { struct xmp_channel *xxc = &mod->xxc[i]; read_line(line, 1024, f); x = strtoul(line, &s, 0); fail_unless(x == xxc->pan, "channel pan"); x = strtoul(s, &s, 0); fail_unless(x == xxc->vol, "channel volume"); x = strtoul(s, &s, 0); fail_unless(x == xxc->flg, "channel flags"); } return 0; }