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)