Module Name: src Committed By: mrg Date: Tue Mar 12 00:34:38 UTC 2024
Modified Files: src/usr.bin/audio/common: wav.c Log Message: audioplay(1): handle mis-aligned RIFF chunks. put the code to find RIFF chunks into a new find_riff_chunk() function, and handle mis-aligned chunk lengths. can now play files with chunks that say they are 7 bytes long, and have 1 byte padding. add some -V -V extra-verbose for the wav parser. To generate a diff of this commit: cvs rdiff -u -r1.21 -r1.22 src/usr.bin/audio/common/wav.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/usr.bin/audio/common/wav.c diff -u src/usr.bin/audio/common/wav.c:1.21 src/usr.bin/audio/common/wav.c:1.22 --- src/usr.bin/audio/common/wav.c:1.21 Mon Mar 11 23:12:29 2024 +++ src/usr.bin/audio/common/wav.c Tue Mar 12 00:34:38 2024 @@ -1,4 +1,4 @@ -/* $NetBSD: wav.c,v 1.21 2024/03/11 23:12:29 mrg Exp $ */ +/* $NetBSD: wav.c,v 1.22 2024/03/12 00:34:38 mrg Exp $ */ /* * Copyright (c) 2002, 2009, 2013, 2015, 2019, 2024 Matthew R. Green @@ -33,7 +33,7 @@ #include <sys/cdefs.h> #ifndef lint -__RCSID("$NetBSD: wav.c,v 1.21 2024/03/11 23:12:29 mrg Exp $"); +__RCSID("$NetBSD: wav.c,v 1.22 2024/03/12 00:34:38 mrg Exp $"); #endif @@ -90,6 +90,49 @@ wav_enc_from_val(int encoding) /* * WAV format helpers */ + +static bool +find_riff_chunk(const char search[4], size_t *remainp, char **wherep, uint32_t *partlen) +{ + wav_audioheaderpart part; + + *partlen = 0; + +#define ADJUST(l) do { \ + if (l >= *(remainp)) \ + return false; \ + *(wherep) += (l); \ + *(remainp) -= (l); \ +} while (0) + + while (*remainp >= sizeof part) { + const char *emsg = ""; + uint32_t len; + + memcpy(&part, *wherep, sizeof part); + ADJUST(sizeof part); + len = getle32(part.len); + if (len % 2) { + emsg = " (odd length, adjusted)"; + len += 1; + } + if (strncmp(part.name, search, sizeof *search) == 0) { + *partlen = len; + if (verbose > 1) + fprintf(stderr, "Found part %.04s length %d%s\n", + part.name, len, emsg); + return true; + } + ADJUST(len); + if (verbose > 1) + fprintf(stderr, "Skipping part %.04s length %d%s\n", + part.name, len, emsg); + } +#undef ADJUST + + return false; +} + /* * find a .wav header, etc. returns header length on success */ @@ -98,7 +141,6 @@ audio_wav_parse_hdr(void *hdr, size_t sz u_int *sample, u_int *channels, off_t *datasize) { char *where = hdr; - wav_audioheaderpart part; wav_audioheaderfmt fmt; wav_audiohdrextensible ext; size_t remain = sz; @@ -131,17 +173,7 @@ audio_wav_parse_hdr(void *hdr, size_t sz return (AUDIO_ENOENT); ADJUST(sizeof strWAVE); - found = false; - while (remain >= sizeof part) { - memcpy(&part, where, sizeof part); - ADJUST(sizeof part); - len = getle32(part.len); - if (strncmp(part.name, strfmt, sizeof strfmt) == 0) { - found = true; - break; - } - ADJUST(len); - } + found = find_riff_chunk(strfmt, &remain, &where, &len); /* too short ? */ if (!found || remain <= sizeof fmt) @@ -243,20 +275,9 @@ audio_wav_parse_hdr(void *hdr, size_t sz break; } - found = false; - while (remain >= sizeof part) { - memcpy(&part, where, sizeof part); - ADJUST(sizeof part); - len = getle32(part.len); - if (strncmp(part.name, strdata, sizeof strdata) == 0) { - found = true; - break; - } - /* Adjust len here only for non-data parts. */ - ADJUST(len); - } + found = find_riff_chunk(strdata, &remain, &where, &len); if (!found) - return (AUDIO_ENOENT); + return (AUDIO_EWAVNODATA); if (len) { if (channels)