From 8013b4b934b9d18c853daf2d605a68eb874df24b Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Mon, 4 Sep 2000 09:18:13 +0000 Subject: [PATCH] Recoded WAV file parser --- aplay/aplay.c | 135 +++++++++++++++++++++++++++++++++--------------- aplay/formats.h | 4 +- 2 files changed, 93 insertions(+), 46 deletions(-) diff --git a/aplay/aplay.c b/aplay/aplay.c index 0dd5b73..a98458e 100644 --- a/aplay/aplay.c +++ b/aplay/aplay.c @@ -618,28 +618,63 @@ static int test_vocfile(void *buffer) return -1; /* magic string fail */ } +/* + * helper for test_wavefile + */ + +size_t test_wavefile_read(int fd, char *buffer, size_t *size, size_t reqsize, int line) +{ + if (*size >= reqsize) + return *size; + if (safe_read(fd, buffer + *size, reqsize - *size) != reqsize - *size) { + error("read error (called from line %i)", line); + exit(EXIT_FAILURE); + } + return *size = reqsize; +} + + /* * test, if it's a .WAV file, > 0 if ok (and set the speed, stereo etc.) * == 0 if not * Value returned is bytes to be discarded. */ -static int test_wavefile(void *buffer, size_t size) +static ssize_t test_wavefile(int fd, char *buffer, size_t size) { - WaveHeader *h = buffer; - WaveFmtHeader *f; + WaveHeader *h = (WaveHeader *)buffer; + WaveFmtBody *f; WaveChunkHeader *c; + u_int type, len; + if (size < sizeof(WaveHeader)) + return -1; if (h->magic != WAV_RIFF || h->type != WAV_WAVE) - return 0; - c = (WaveChunkHeader*)((char *)buffer + sizeof(WaveHeader)); - while (c->type != WAV_FMT) { - c = (WaveChunkHeader*)((char*)c + sizeof(*c) + LE_INT(c->length)); - if ((char *)c + sizeof(*c) > (char*) buffer + size) { - error("cannot found WAVE fmt chunk"); - exit(EXIT_FAILURE); - } + return -1; + if (size > sizeof(WaveHeader)) + memmove(buffer, buffer + sizeof(WaveHeader), size - sizeof(WaveHeader)); + size -= sizeof(WaveHeader); + while (1) { + test_wavefile_read(fd, buffer, &size, sizeof(WaveChunkHeader), __LINE__); + c = (WaveChunkHeader*)buffer; + type = c->type; + len = LE_INT(c->length); + if (size > sizeof(WaveChunkHeader)) + memmove(buffer, buffer + sizeof(WaveChunkHeader), size - sizeof(WaveChunkHeader)); + size -= sizeof(WaveChunkHeader); + if (type == WAV_FMT) + break; + test_wavefile_read(fd, buffer, &size, len, __LINE__); + if (size > len) + memmove(buffer, buffer + len, size - len); + size -= len; + } + + if (len < sizeof(WaveFmtBody)) { + error("unknown length of 'fmt ' chunk (read %u, should be %u at least)", len, (u_int)sizeof(WaveFmtBody)); + exit(EXIT_FAILURE); } - f = (WaveFmtHeader*) c; + test_wavefile_read(fd, buffer, &size, len, __LINE__); + f = (WaveFmtBody*) buffer; if (LE_SHORT(f->format) != WAV_PCM_CODE) { error("can't play not PCM-coded WAVE-files"); exit(EXIT_FAILURE); @@ -661,18 +696,35 @@ static int test_wavefile(void *buffer, size_t size) exit(EXIT_FAILURE); } format.rate = LE_INT(f->sample_fq); - while (c->type != WAV_DATA) { - c = (WaveChunkHeader*)((char*)c + sizeof(*c) + LE_INT(c->length)); - if ((char *)c + sizeof(*c) > (char*) buffer + size) { - error("cannot found WAVE data chunk"); - exit(EXIT_FAILURE); + + if (size > len) + memmove(buffer, buffer + len, size - len); + size -= len; + + while (1) { + u_int type, len; + + test_wavefile_read(fd, buffer, &size, sizeof(WaveChunkHeader), __LINE__); + c = (WaveChunkHeader*)buffer; + type = c->type; + len = LE_INT(c->length); + if (size > sizeof(WaveChunkHeader)) + memmove(buffer, buffer + sizeof(WaveChunkHeader), size - sizeof(WaveChunkHeader)); + size -= sizeof(WaveChunkHeader); + if (type == WAV_DATA) { + if (len < count) + count = len; + check_new_format(&format); + return size; } + test_wavefile_read(fd, buffer, &size, len, __LINE__); + if (size > len) + memmove(buffer, buffer + len, size - len); + size -= len; } - if (LE_INT(c->length) < count) - count = LE_INT(c->length); - check_new_format(&format); - return (char *)c + sizeof(*c) - (char *) buffer; + /* shouldn't be reached */ + return -1; } /* @@ -1348,8 +1400,8 @@ static void begin_voc(int fd, size_t cnt) static void begin_wave(int fd, size_t cnt) { WaveHeader h; - WaveFmtHeader f; - WaveChunkHeader c; + WaveFmtBody f; + WaveChunkHeader cf, cd; int bits; u_int tmp; u_short tmp2; @@ -1367,12 +1419,13 @@ static void begin_wave(int fd, size_t cnt) exit(EXIT_FAILURE); } h.magic = WAV_RIFF; - tmp = cnt + sizeof(WaveHeader) + sizeof(WaveFmtHeader) + sizeof(WaveChunkHeader) - 8; + tmp = cnt + sizeof(WaveHeader) + sizeof(WaveChunkHeader) + sizeof(WaveFmtBody) + sizeof(WaveChunkHeader) - 8; h.length = LE_INT(tmp); h.type = WAV_WAVE; - f.type = WAV_FMT; - f.length = LE_INT(16); + cf.type = WAV_FMT; + cf.length = LE_INT(16); + f.format = LE_INT(WAV_PCM_CODE); f.modus = LE_SHORT(format.channels); f.sample_fq = LE_INT(format.rate); @@ -1389,12 +1442,13 @@ static void begin_wave(int fd, size_t cnt) #endif f.bit_p_spl = LE_SHORT(bits); - c.type = WAV_DATA; - c.length = LE_INT(cnt); + cd.type = WAV_DATA; + cd.length = LE_INT(cnt); if (write(fd, &h, sizeof(WaveHeader)) != sizeof(WaveHeader) || - write(fd, &f, sizeof(WaveFmtHeader)) != sizeof(WaveFmtHeader) || - write(fd, &c, sizeof(WaveChunkHeader)) != sizeof(WaveChunkHeader)) { + write(fd, &cf, sizeof(WaveChunkHeader)) != sizeof(WaveChunkHeader) || + write(fd, &f, sizeof(WaveFmtBody)) != sizeof(WaveFmtBody) || + write(fd, &cd, sizeof(WaveChunkHeader)) != sizeof(WaveChunkHeader)) { error("write error"); exit(EXIT_FAILURE); } @@ -1550,6 +1604,7 @@ void capture_go(int fd, size_t count, int rtype, char *name) static void playback(char *name) { int fd, ofs; + size_t dta, dtawave; count = calc_count(); snd_pcm_flush(handle); @@ -1563,7 +1618,8 @@ static void playback(char *name) } } /* read the file header */ - if (safe_read(fd, audiobuf, sizeof(AuHeader)) != sizeof(AuHeader)) { + dta = sizeof(AuHeader); + if (safe_read(fd, audiobuf, dta) != dta) { error("read error"); exit(EXIT_FAILURE); } @@ -1572,9 +1628,9 @@ static void playback(char *name) playback_go(fd, 0, count, FORMAT_AU, name); goto __end; } + dta = sizeof(VocHeader); if (safe_read(fd, audiobuf + sizeof(AuHeader), - sizeof(VocHeader) - sizeof(AuHeader)) != - sizeof(VocHeader) - sizeof(AuHeader)) { + dta - sizeof(AuHeader)) != dta - sizeof(AuHeader)) { error("read error"); exit(EXIT_FAILURE); } @@ -1583,20 +1639,13 @@ static void playback(char *name) goto __end; } /* read bytes for WAVE-header */ - if (safe_read(fd, audiobuf + sizeof(VocHeader), - 64 - sizeof(VocHeader)) != - 64 - sizeof(VocHeader)) { - error("read error"); - exit(EXIT_FAILURE); - } - if ((ofs = test_wavefile(audiobuf, 64)) > 0) { - memmove(audiobuf, audiobuf + ofs, 64 - ofs); - playback_go(fd, 64 - ofs, count, FORMAT_WAVE, name); + if ((dtawave = test_wavefile(fd, audiobuf, dta)) >= 0) { + playback_go(fd, dtawave, count, FORMAT_WAVE, name); } else { /* should be raw data */ check_new_format(&rformat); init_raw_data(); - playback_go(fd, 64, count, FORMAT_RAW, name); + playback_go(fd, dta, count, FORMAT_RAW, name); } __end: if (fd != 0) diff --git a/aplay/formats.h b/aplay/formats.h index c9bd144..d84652b 100644 --- a/aplay/formats.h +++ b/aplay/formats.h @@ -75,15 +75,13 @@ typedef struct { } WaveHeader; typedef struct { - u_int type; /* 'fmt ' */ - u_int length; /* length of chunk */ u_short format; /* should be 1 for PCM-code */ u_short modus; /* 1 Mono, 2 Stereo */ u_int sample_fq; /* frequence of sample */ u_int byte_p_sec; u_short byte_p_spl; /* samplesize; 1 or 2 bytes */ u_short bit_p_spl; /* 8, 12 or 16 bit */ -} WaveFmtHeader; +} WaveFmtBody; typedef struct { u_int type; /* 'data' */ -- 2.47.1