diff --git a/tools/str/unstr.c b/tools/str/unstr.c index d94701915..e694f3844 100644 --- a/tools/str/unstr.c +++ b/tools/str/unstr.c @@ -28,6 +28,7 @@ struct options { char list; char print; char verbose; + char sound; }; @@ -38,7 +39,15 @@ void writeFiles(const index_header *h, const uint8 *data, const char *path, void parse_arguments(int argc, char *argv[], struct options *opts); void listEntries(const index_header *h, const uint8 *buf, FILE *out); void writeEntries(const index_header *h, const uint8 *buf, FILE *out); +void writeSoundEntries(const index_header *h, const uint8 *buf, const char* outmask); +const char *riffHdr = "RIFF"; +const char *waveType = "WAVE"; +const char *fmtHdr = "fmt "; +const char *dataHdr = "data"; +#define FMTHDR_SIZE 0x10 +#define DATAHDR_SIZE 0x08 +#define WAVEHDR_SIZE (4 + 4 + 4 + FMTHDR_SIZE + DATAHDR_SIZE) int main(int argc, char *argv[]) { @@ -47,6 +56,7 @@ main(int argc, char *argv[]) { uint8 *buf; index_header *h; struct options opts; + char outnbuf[512]; parse_arguments(argc, argv, &opts); @@ -69,6 +79,15 @@ main(int argc, char *argv[]) { } close(in); + if (opts.sound && !opts.outfile) { + char *pdot = strrchr(opts.infile, '.'); + opts.outfile = outnbuf; + strcpy(outnbuf, opts.infile); + if (pdot) + outnbuf[pdot - opts.infile] = 0; + + } + h = readIndex(buf); if (opts.print) printIndex(h, buf, stdout); @@ -76,8 +95,11 @@ main(int argc, char *argv[]) { if (opts.list) { listEntries(h, buf, stdout); } - - if (opts.outfile) { + + if (opts.sound && opts.outfile) { + writeSoundEntries(h, buf, opts.outfile); + + } else if (opts.outfile) { FILE *out; out = fopen(opts.outfile, "wb+"); if (out == NULL) { @@ -99,7 +121,8 @@ usage() { fprintf(stderr, "unstr -a \n" "unstr -p \n" - "unstr [-o ] \n"); + "unstr [-o ] \n" + "unstr -s [-o ] \n"); } void @@ -108,7 +131,7 @@ parse_arguments(int argc, char *argv[], struct options *opts) { memset(opts, '\0', sizeof (struct options)); while (1) { - ch = getopt(argc, argv, "ahlo:pv"); + ch = getopt(argc, argv, "ahlo:psv"); if (ch == -1) break; switch(ch) { @@ -124,6 +147,9 @@ parse_arguments(int argc, char *argv[], struct options *opts) { case 'v': opts->verbose = 1; break; + case 's': + opts->sound = 1; + break; case '?': case 'h': default: @@ -209,4 +235,77 @@ writeEntries(const index_header *h, const uint8 *buf, FILE *out) { } } +void +signSoundBuf(uint8 *buf, uint32 len) +{ + for (; len; ++buf, --len) + *buf ^= 0x80; +} +void +writeFile_Int16_LE(FILE *f, uint16 val) +{ + fputc(val & 0xff, f); + fputc((val >> 8) & 0xff, f); +} + +void +writeFile_Int32_LE(FILE *f, uint32 val) +{ + writeFile_Int16_LE(f, val & 0xffff); + writeFile_Int16_LE(f, (val >> 16) & 0xffff); +} + +void +writeSoundEntries(const index_header *h, const uint8 *buf, const char* outmask) { + FILE *out; + uint32 i; + char namebuf[512]; + const uint8 *start; + uint8 *data; + const uint8 *orgdata; + uint32 datalen; + uint32 wavelen; + uint32 freq; + + start = buf + 8 + (h->num_entries + 1) * 4; + data = NULL; + for (i = 0; i < h->num_entries; i++) { + sprintf(namebuf, "%s.%u.wav", outmask, i); + + out = fopen(namebuf, "wb"); + if (out == NULL) { + fprintf(stderr, "Could not open output file '%s': %s\n", + namebuf, strerror(errno)); + exit(EXIT_FAILURE); + } + + datalen = h->entries[i].size - 2; + data = realloc(data, datalen); + orgdata = start + h->entries[i].offset; + memcpy(data, orgdata, datalen); + signSoundBuf(data, datalen); + freq = MAKE_WORD(orgdata[datalen], orgdata[datalen + 1]); + + wavelen = datalen + WAVEHDR_SIZE; + fputs(riffHdr, out); + writeFile_Int32_LE(out, wavelen); + fputs(waveType, out); + + fputs(fmtHdr, out); + writeFile_Int32_LE(out, FMTHDR_SIZE); + writeFile_Int16_LE(out, 1); // format + writeFile_Int16_LE(out, 1); // channels + writeFile_Int32_LE(out, freq); // samples/sec + writeFile_Int32_LE(out, freq); // bytes/sec + writeFile_Int16_LE(out, 1); // block align + writeFile_Int16_LE(out, 8); // bits/sample + + fputs(dataHdr, out); + writeFile_Int32_LE(out, datalen); + + fwrite(data, 1, datalen, out); + fclose(out); + } + free(data); +}